1; RUN: llc < %s -asm-verbose=false | FileCheck %s 2 3; Test constant load and store address offsets. 4 5target datalayout = "e-p:32:32-i64:64-n32:64-S128" 6target triple = "wasm32-unknown-unknown" 7 8; With an nuw add, we can fold an offset. 9 10; CHECK-LABEL: load_i32_with_folded_offset: 11; CHECK: i32.load $push0=, 24($0){{$}} 12define i32 @load_i32_with_folded_offset(i32* %p) { 13 %q = ptrtoint i32* %p to i32 14 %r = add nuw i32 %q, 24 15 %s = inttoptr i32 %r to i32* 16 %t = load i32, i32* %s 17 ret i32 %t 18} 19 20; Without nuw, and even with nsw, we can't fold an offset. 21 22; CHECK-LABEL: load_i32_with_unfolded_offset: 23; CHECK: i32.const $push0=, 24{{$}} 24; CHECK: i32.add $push1=, $0, $pop0{{$}} 25; CHECK: i32.load $push2=, 0($pop1){{$}} 26define i32 @load_i32_with_unfolded_offset(i32* %p) { 27 %q = ptrtoint i32* %p to i32 28 %r = add nsw i32 %q, 24 29 %s = inttoptr i32 %r to i32* 30 %t = load i32, i32* %s 31 ret i32 %t 32} 33 34; Same as above but with i64. 35 36; CHECK-LABEL: load_i64_with_folded_offset: 37; CHECK: i64.load $push0=, 24($0){{$}} 38define i64 @load_i64_with_folded_offset(i64* %p) { 39 %q = ptrtoint i64* %p to i32 40 %r = add nuw i32 %q, 24 41 %s = inttoptr i32 %r to i64* 42 %t = load i64, i64* %s 43 ret i64 %t 44} 45 46; Same as above but with i64. 47 48; CHECK-LABEL: load_i64_with_unfolded_offset: 49; CHECK: i32.const $push0=, 24{{$}} 50; CHECK: i32.add $push1=, $0, $pop0{{$}} 51; CHECK: i64.load $push2=, 0($pop1){{$}} 52define i64 @load_i64_with_unfolded_offset(i64* %p) { 53 %q = ptrtoint i64* %p to i32 54 %r = add nsw i32 %q, 24 55 %s = inttoptr i32 %r to i64* 56 %t = load i64, i64* %s 57 ret i64 %t 58} 59 60; Same as above but with store. 61 62; CHECK-LABEL: store_i32_with_folded_offset: 63; CHECK: i32.store $discard=, 24($0), $pop0{{$}} 64define void @store_i32_with_folded_offset(i32* %p) { 65 %q = ptrtoint i32* %p to i32 66 %r = add nuw i32 %q, 24 67 %s = inttoptr i32 %r to i32* 68 store i32 0, i32* %s 69 ret void 70} 71 72; Same as above but with store. 73 74; CHECK-LABEL: store_i32_with_unfolded_offset: 75; CHECK: i32.const $push0=, 24{{$}} 76; CHECK: i32.add $push1=, $0, $pop0{{$}} 77; CHECK: i32.store $discard=, 0($pop1), $pop2{{$}} 78define void @store_i32_with_unfolded_offset(i32* %p) { 79 %q = ptrtoint i32* %p to i32 80 %r = add nsw i32 %q, 24 81 %s = inttoptr i32 %r to i32* 82 store i32 0, i32* %s 83 ret void 84} 85 86; Same as above but with store with i64. 87 88; CHECK-LABEL: store_i64_with_folded_offset: 89; CHECK: i64.store $discard=, 24($0), $pop0{{$}} 90define void @store_i64_with_folded_offset(i64* %p) { 91 %q = ptrtoint i64* %p to i32 92 %r = add nuw i32 %q, 24 93 %s = inttoptr i32 %r to i64* 94 store i64 0, i64* %s 95 ret void 96} 97 98; Same as above but with store with i64. 99 100; CHECK-LABEL: store_i64_with_unfolded_offset: 101; CHECK: i32.const $push0=, 24{{$}} 102; CHECK: i32.add $push1=, $0, $pop0{{$}} 103; CHECK: i64.store $discard=, 0($pop1), $pop2{{$}} 104define void @store_i64_with_unfolded_offset(i64* %p) { 105 %q = ptrtoint i64* %p to i32 106 %r = add nsw i32 %q, 24 107 %s = inttoptr i32 %r to i64* 108 store i64 0, i64* %s 109 ret void 110} 111 112; When loading from a fixed address, materialize a zero. 113 114; CHECK-LABEL: load_i32_from_numeric_address 115; CHECK: i32.const $push0=, 0{{$}} 116; CHECK: i32.load $push1=, 42($pop0){{$}} 117define i32 @load_i32_from_numeric_address() { 118 %s = inttoptr i32 42 to i32* 119 %t = load i32, i32* %s 120 ret i32 %t 121} 122 123; CHECK-LABEL: load_i32_from_global_address 124; CHECK: i32.const $push0=, 0{{$}} 125; CHECK: i32.load $push1=, gv($pop0){{$}} 126@gv = global i32 0 127define i32 @load_i32_from_global_address() { 128 %t = load i32, i32* @gv 129 ret i32 %t 130} 131 132; CHECK-LABEL: store_i32_to_numeric_address: 133; CHECK: i32.const $0=, 0{{$}} 134; CHECK: i32.store $discard=, 42($0), $0{{$}} 135define void @store_i32_to_numeric_address() { 136 %s = inttoptr i32 42 to i32* 137 store i32 0, i32* %s 138 ret void 139} 140 141; CHECK-LABEL: store_i32_to_global_address: 142; CHECK: i32.const $0=, 0{{$}} 143; CHECK: i32.store $discard=, gv($0), $0{{$}} 144define void @store_i32_to_global_address() { 145 store i32 0, i32* @gv 146 ret void 147} 148 149; Fold an offset into a sign-extending load. 150 151; CHECK-LABEL: load_i8_s_with_folded_offset: 152; CHECK: i32.load8_s $push0=, 24($0){{$}} 153define i32 @load_i8_s_with_folded_offset(i8* %p) { 154 %q = ptrtoint i8* %p to i32 155 %r = add nuw i32 %q, 24 156 %s = inttoptr i32 %r to i8* 157 %t = load i8, i8* %s 158 %u = sext i8 %t to i32 159 ret i32 %u 160} 161 162; Fold an offset into a zero-extending load. 163 164; CHECK-LABEL: load_i8_u_with_folded_offset: 165; CHECK: i32.load8_u $push0=, 24($0){{$}} 166define i32 @load_i8_u_with_folded_offset(i8* %p) { 167 %q = ptrtoint i8* %p to i32 168 %r = add nuw i32 %q, 24 169 %s = inttoptr i32 %r to i8* 170 %t = load i8, i8* %s 171 %u = zext i8 %t to i32 172 ret i32 %u 173} 174 175; Fold an offset into a truncating store. 176 177; CHECK-LABEL: store_i8_with_folded_offset: 178; CHECK: i32.store8 $discard=, 24($0), $pop0{{$}} 179define void @store_i8_with_folded_offset(i8* %p) { 180 %q = ptrtoint i8* %p to i32 181 %r = add nuw i32 %q, 24 182 %s = inttoptr i32 %r to i8* 183 store i8 0, i8* %s 184 ret void 185} 186