1 ; RUN: llc < %s -asm-verbose=false | FileCheck %s 2 3 ; Test constant load and store address offsets. 4 5 target datalayout = "e-p:32:32-i64:64-n32:64-S128" 6 target 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){{$}} 12 define 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){{$}} 26 define 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){{$}} 38 define 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){{$}} 52 define 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{{$}} 64 define 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{{$}} 78 define 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{{$}} 90 define 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{{$}} 104 define 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){{$}} 117 define 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 127 define 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{{$}} 135 define 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{{$}} 144 define 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){{$}} 153 define 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){{$}} 166 define 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{{$}} 179 define 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