Derek Schuff | 885dc59 | 2017-10-05 21:18:42 +0000 | [diff] [blame] | 1 | ; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt |
Dan Gohman | 5d2b935 | 2018-01-19 17:16:24 +0000 | [diff] [blame] | 2 | ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=+atomics,+sign-ext | FileCheck %s |
Derek Schuff | 885dc59 | 2017-10-05 21:18:42 +0000 | [diff] [blame] | 3 | |
| 4 | ; Test that atomic loads are assembled properly. |
| 5 | |
| 6 | target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" |
Sam Clegg | a590800 | 2018-05-10 17:49:11 +0000 | [diff] [blame^] | 7 | target triple = "wasm32-unknown-unknown" |
Derek Schuff | 885dc59 | 2017-10-05 21:18:42 +0000 | [diff] [blame] | 8 | |
| 9 | ; CHECK-LABEL: load_i32_no_offset: |
| 10 | ; CHECK: i32.atomic.load $push[[NUM:[0-9]+]]=, 0($0){{$}} |
| 11 | ; CHECK-NEXT: return $pop[[NUM]]{{$}} |
| 12 | define i32 @load_i32_no_offset(i32 *%p) { |
| 13 | %v = load atomic i32, i32* %p seq_cst, align 4 |
| 14 | ret i32 %v |
| 15 | } |
| 16 | |
| 17 | ; With an nuw add, we can fold an offset. |
| 18 | |
| 19 | ; CHECK-LABEL: load_i32_with_folded_offset: |
| 20 | ; CHECK: i32.atomic.load $push0=, 24($0){{$}} |
| 21 | define i32 @load_i32_with_folded_offset(i32* %p) { |
| 22 | %q = ptrtoint i32* %p to i32 |
| 23 | %r = add nuw i32 %q, 24 |
| 24 | %s = inttoptr i32 %r to i32* |
| 25 | %t = load atomic i32, i32* %s seq_cst, align 4 |
| 26 | ret i32 %t |
| 27 | } |
| 28 | |
| 29 | ; With an inbounds gep, we can fold an offset. |
| 30 | |
| 31 | ; CHECK-LABEL: load_i32_with_folded_gep_offset: |
| 32 | ; CHECK: i32.atomic.load $push0=, 24($0){{$}} |
| 33 | define i32 @load_i32_with_folded_gep_offset(i32* %p) { |
| 34 | %s = getelementptr inbounds i32, i32* %p, i32 6 |
| 35 | %t = load atomic i32, i32* %s seq_cst, align 4 |
| 36 | ret i32 %t |
| 37 | } |
| 38 | |
| 39 | ; We can't fold a negative offset though, even with an inbounds gep. |
| 40 | |
| 41 | ; CHECK-LABEL: load_i32_with_unfolded_gep_negative_offset: |
| 42 | ; CHECK: i32.const $push0=, -24{{$}} |
| 43 | ; CHECK: i32.add $push1=, $0, $pop0{{$}} |
| 44 | ; CHECK: i32.atomic.load $push2=, 0($pop1){{$}} |
| 45 | define i32 @load_i32_with_unfolded_gep_negative_offset(i32* %p) { |
| 46 | %s = getelementptr inbounds i32, i32* %p, i32 -6 |
| 47 | %t = load atomic i32, i32* %s seq_cst, align 4 |
| 48 | ret i32 %t |
| 49 | } |
| 50 | |
| 51 | ; Without nuw, and even with nsw, we can't fold an offset. |
| 52 | |
| 53 | ; CHECK-LABEL: load_i32_with_unfolded_offset: |
| 54 | ; CHECK: i32.const $push0=, 24{{$}} |
| 55 | ; CHECK: i32.add $push1=, $0, $pop0{{$}} |
| 56 | ; CHECK: i32.atomic.load $push2=, 0($pop1){{$}} |
| 57 | define i32 @load_i32_with_unfolded_offset(i32* %p) { |
| 58 | %q = ptrtoint i32* %p to i32 |
| 59 | %r = add nsw i32 %q, 24 |
| 60 | %s = inttoptr i32 %r to i32* |
| 61 | %t = load atomic i32, i32* %s seq_cst, align 4 |
| 62 | ret i32 %t |
| 63 | } |
| 64 | |
| 65 | ; Without inbounds, we can't fold a gep offset. |
| 66 | |
| 67 | ; CHECK-LABEL: load_i32_with_unfolded_gep_offset: |
| 68 | ; CHECK: i32.const $push0=, 24{{$}} |
| 69 | ; CHECK: i32.add $push1=, $0, $pop0{{$}} |
| 70 | ; CHECK: i32.atomic.load $push2=, 0($pop1){{$}} |
| 71 | define i32 @load_i32_with_unfolded_gep_offset(i32* %p) { |
| 72 | %s = getelementptr i32, i32* %p, i32 6 |
| 73 | %t = load atomic i32, i32* %s seq_cst, align 4 |
| 74 | ret i32 %t |
| 75 | } |
| 76 | |
| 77 | ; CHECK-LABEL: load_i64_no_offset: |
| 78 | ; CHECK: i64.atomic.load $push[[NUM:[0-9]+]]=, 0($0){{$}} |
| 79 | ; CHECK-NEXT: return $pop[[NUM]]{{$}} |
| 80 | define i64 @load_i64_no_offset(i64 *%p) { |
| 81 | %v = load atomic i64, i64* %p seq_cst, align 8 |
| 82 | ret i64 %v |
| 83 | } |
| 84 | |
| 85 | ; Same as above but with i64. |
| 86 | |
| 87 | ; CHECK-LABEL: load_i64_with_folded_offset: |
| 88 | ; CHECK: i64.atomic.load $push0=, 24($0){{$}} |
| 89 | define i64 @load_i64_with_folded_offset(i64* %p) { |
| 90 | %q = ptrtoint i64* %p to i32 |
| 91 | %r = add nuw i32 %q, 24 |
| 92 | %s = inttoptr i32 %r to i64* |
| 93 | %t = load atomic i64, i64* %s seq_cst, align 8 |
| 94 | ret i64 %t |
| 95 | } |
| 96 | |
| 97 | ; Same as above but with i64. |
| 98 | |
| 99 | ; CHECK-LABEL: load_i64_with_folded_gep_offset: |
| 100 | ; CHECK: i64.atomic.load $push0=, 24($0){{$}} |
| 101 | define i64 @load_i64_with_folded_gep_offset(i64* %p) { |
| 102 | %s = getelementptr inbounds i64, i64* %p, i32 3 |
| 103 | %t = load atomic i64, i64* %s seq_cst, align 8 |
| 104 | ret i64 %t |
| 105 | } |
| 106 | |
| 107 | ; Same as above but with i64. |
| 108 | |
| 109 | ; CHECK-LABEL: load_i64_with_unfolded_gep_negative_offset: |
| 110 | ; CHECK: i32.const $push0=, -24{{$}} |
| 111 | ; CHECK: i32.add $push1=, $0, $pop0{{$}} |
| 112 | ; CHECK: i64.atomic.load $push2=, 0($pop1){{$}} |
| 113 | define i64 @load_i64_with_unfolded_gep_negative_offset(i64* %p) { |
| 114 | %s = getelementptr inbounds i64, i64* %p, i32 -3 |
| 115 | %t = load atomic i64, i64* %s seq_cst, align 8 |
| 116 | ret i64 %t |
| 117 | } |
| 118 | |
| 119 | ; Same as above but with i64. |
| 120 | |
| 121 | ; CHECK-LABEL: load_i64_with_unfolded_offset: |
| 122 | ; CHECK: i32.const $push0=, 24{{$}} |
| 123 | ; CHECK: i32.add $push1=, $0, $pop0{{$}} |
| 124 | ; CHECK: i64.atomic.load $push2=, 0($pop1){{$}} |
| 125 | define i64 @load_i64_with_unfolded_offset(i64* %p) { |
| 126 | %q = ptrtoint i64* %p to i32 |
| 127 | %r = add nsw i32 %q, 24 |
| 128 | %s = inttoptr i32 %r to i64* |
| 129 | %t = load atomic i64, i64* %s seq_cst, align 8 |
| 130 | ret i64 %t |
| 131 | } |
| 132 | |
| 133 | ; Same as above but with i64. |
| 134 | |
| 135 | ; CHECK-LABEL: load_i64_with_unfolded_gep_offset: |
| 136 | ; CHECK: i32.const $push0=, 24{{$}} |
| 137 | ; CHECK: i32.add $push1=, $0, $pop0{{$}} |
| 138 | ; CHECK: i64.atomic.load $push2=, 0($pop1){{$}} |
| 139 | define i64 @load_i64_with_unfolded_gep_offset(i64* %p) { |
| 140 | %s = getelementptr i64, i64* %p, i32 3 |
| 141 | %t = load atomic i64, i64* %s seq_cst, align 8 |
| 142 | ret i64 %t |
| 143 | } |
| 144 | |
| 145 | ; CHECK-LABEL: load_i32_with_folded_or_offset: |
| 146 | ; CHECK: i32.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}} |
| 147 | ; CHECK-NEXT: i32.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}} |
| 148 | define i32 @load_i32_with_folded_or_offset(i32 %x) { |
| 149 | %and = and i32 %x, -4 |
| 150 | %t0 = inttoptr i32 %and to i8* |
| 151 | %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2 |
| 152 | %t1 = load atomic i8, i8* %arrayidx seq_cst, align 8 |
| 153 | %conv = sext i8 %t1 to i32 |
| 154 | ret i32 %conv |
| 155 | } |
| 156 | |
| 157 | ; When loading from a fixed address, materialize a zero. |
| 158 | |
| 159 | ; CHECK-LABEL: load_i32_from_numeric_address |
| 160 | ; CHECK: i32.const $push0=, 0{{$}} |
| 161 | ; CHECK: i32.atomic.load $push1=, 42($pop0){{$}} |
| 162 | define i32 @load_i32_from_numeric_address() { |
| 163 | %s = inttoptr i32 42 to i32* |
| 164 | %t = load atomic i32, i32* %s seq_cst, align 4 |
| 165 | ret i32 %t |
| 166 | } |
| 167 | |
| 168 | |
| 169 | ; CHECK-LABEL: load_i32_from_global_address |
| 170 | ; CHECK: i32.const $push0=, 0{{$}} |
| 171 | ; CHECK: i32.atomic.load $push1=, gv($pop0){{$}} |
| 172 | @gv = global i32 0 |
| 173 | define i32 @load_i32_from_global_address() { |
| 174 | %t = load atomic i32, i32* @gv seq_cst, align 4 |
| 175 | ret i32 %t |
| 176 | } |
| 177 | |
| 178 | ; Fold an offset into a sign-extending load. |
| 179 | |
| 180 | ; CHECK-LABEL: load_i8_s_with_folded_offset: |
| 181 | ; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}} |
| 182 | ; CHECK-NEXT: i32.extend8_s $push1=, $pop0 |
| 183 | define i32 @load_i8_s_with_folded_offset(i8* %p) { |
| 184 | %q = ptrtoint i8* %p to i32 |
| 185 | %r = add nuw i32 %q, 24 |
| 186 | %s = inttoptr i32 %r to i8* |
| 187 | %t = load atomic i8, i8* %s seq_cst, align 1 |
| 188 | %u = sext i8 %t to i32 |
| 189 | ret i32 %u |
| 190 | } |
| 191 | |
| 192 | ; Fold a gep offset into a sign-extending load. |
| 193 | |
| 194 | ; CHECK-LABEL: load_i8_s_with_folded_gep_offset: |
| 195 | ; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}} |
| 196 | ; CHECK-NEXT: i32.extend8_s $push1=, $pop0 |
| 197 | define i32 @load_i8_s_with_folded_gep_offset(i8* %p) { |
| 198 | %s = getelementptr inbounds i8, i8* %p, i32 24 |
| 199 | %t = load atomic i8, i8* %s seq_cst, align 1 |
| 200 | %u = sext i8 %t to i32 |
| 201 | ret i32 %u |
| 202 | } |
| 203 | |
| 204 | ; CHECK-LABEL: load_i16_s_i64_with_folded_gep_offset: |
| 205 | ; CHECK: i64.atomic.load16_u $push0=, 6($0){{$}} |
| 206 | define i64 @load_i16_s_i64_with_folded_gep_offset(i16* %p) { |
| 207 | %s = getelementptr inbounds i16, i16* %p, i32 3 |
| 208 | %t = load atomic i16, i16* %s seq_cst, align 2 |
| 209 | %u = zext i16 %t to i64 |
| 210 | ret i64 %u |
| 211 | } |
| 212 | |
| 213 | ; CHECK-LABEL: load_i64_with_folded_or_offset: |
| 214 | ; CHECK: i64.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}} |
| 215 | ; CHECK-NEXT: i64.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}} |
| 216 | define i64 @load_i64_with_folded_or_offset(i32 %x) { |
| 217 | %and = and i32 %x, -4 |
| 218 | %t0 = inttoptr i32 %and to i8* |
| 219 | %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2 |
| 220 | %t1 = load atomic i8, i8* %arrayidx seq_cst, align 8 |
| 221 | %conv = sext i8 %t1 to i64 |
| 222 | ret i64 %conv |
| 223 | } |
| 224 | |
| 225 | |
| 226 | ; Fold an offset into a zero-extending load. |
| 227 | |
| 228 | ; CHECK-LABEL: load_i16_u_with_folded_offset: |
| 229 | ; CHECK: i32.atomic.load16_u $push0=, 24($0){{$}} |
| 230 | define i32 @load_i16_u_with_folded_offset(i8* %p) { |
| 231 | %q = ptrtoint i8* %p to i32 |
| 232 | %r = add nuw i32 %q, 24 |
| 233 | %s = inttoptr i32 %r to i16* |
| 234 | %t = load atomic i16, i16* %s seq_cst, align 2 |
| 235 | %u = zext i16 %t to i32 |
| 236 | ret i32 %u |
| 237 | } |
| 238 | |
| 239 | ; Fold a gep offset into a zero-extending load. |
| 240 | |
| 241 | ; CHECK-LABEL: load_i8_u_with_folded_gep_offset: |
| 242 | ; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}} |
| 243 | define i32 @load_i8_u_with_folded_gep_offset(i8* %p) { |
| 244 | %s = getelementptr inbounds i8, i8* %p, i32 24 |
| 245 | %t = load atomic i8, i8* %s seq_cst, align 1 |
| 246 | %u = zext i8 %t to i32 |
| 247 | ret i32 %u |
| 248 | } |
| 249 | |
| 250 | |
| 251 | ; When loading from a fixed address, materialize a zero. |
| 252 | ; As above but with extending load. |
| 253 | |
| 254 | ; CHECK-LABEL: load_zext_i32_from_numeric_address |
| 255 | ; CHECK: i32.const $push0=, 0{{$}} |
| 256 | ; CHECK: i32.atomic.load16_u $push1=, 42($pop0){{$}} |
| 257 | define i32 @load_zext_i32_from_numeric_address() { |
| 258 | %s = inttoptr i32 42 to i16* |
| 259 | %t = load atomic i16, i16* %s seq_cst, align 2 |
| 260 | %u = zext i16 %t to i32 |
| 261 | ret i32 %u |
| 262 | } |
| 263 | |
| 264 | ; CHECK-LABEL: load_sext_i32_from_global_address |
| 265 | ; CHECK: i32.const $push0=, 0{{$}} |
| 266 | ; CHECK: i32.atomic.load8_u $push1=, gv8($pop0){{$}} |
| 267 | ; CHECK-NEXT: i32.extend8_s $push2=, $pop1{{$}} |
| 268 | @gv8 = global i8 0 |
| 269 | define i32 @load_sext_i32_from_global_address() { |
| 270 | %t = load atomic i8, i8* @gv8 seq_cst, align 1 |
| 271 | %u = sext i8 %t to i32 |
| 272 | ret i32 %u |
| 273 | } |
| 274 | |
| 275 | ; Fold an offset into a sign-extending load. |
| 276 | ; As above but 32 extended to 64 bit. |
| 277 | ; CHECK-LABEL: load_i32_i64_s_with_folded_offset: |
| 278 | ; CHECK: i32.atomic.load $push0=, 24($0){{$}} |
| 279 | ; CHECK-NEXT: i64.extend_s/i32 $push1=, $pop0{{$}} |
| 280 | define i64 @load_i32_i64_s_with_folded_offset(i32* %p) { |
| 281 | %q = ptrtoint i32* %p to i32 |
| 282 | %r = add nuw i32 %q, 24 |
| 283 | %s = inttoptr i32 %r to i32* |
| 284 | %t = load atomic i32, i32* %s seq_cst, align 4 |
| 285 | %u = sext i32 %t to i64 |
| 286 | ret i64 %u |
| 287 | } |
| 288 | |
| 289 | ; Fold a gep offset into a zero-extending load. |
| 290 | ; As above but 32 extended to 64 bit. |
| 291 | ; CHECK-LABEL: load_i32_i64_u_with_folded_gep_offset: |
| 292 | ; CHECK: i64.atomic.load32_u $push0=, 96($0){{$}} |
| 293 | define i64 @load_i32_i64_u_with_folded_gep_offset(i32* %p) { |
| 294 | %s = getelementptr inbounds i32, i32* %p, i32 24 |
| 295 | %t = load atomic i32, i32* %s seq_cst, align 4 |
| 296 | %u = zext i32 %t to i64 |
| 297 | ret i64 %u |
| 298 | } |
| 299 | |
| 300 | ; i8 return value should test anyext loads |
| 301 | ; CHECK-LABEL: ldi8_a1: |
| 302 | ; CHECK: i32.atomic.load8_u $push[[NUM:[0-9]+]]=, 0($0){{$}} |
| 303 | ; CHECK-NEXT: return $pop[[NUM]]{{$}} |
| 304 | define i8 @ldi8_a1(i8 *%p) { |
| 305 | %v = load atomic i8, i8* %p seq_cst, align 1 |
| 306 | ret i8 %v |
| 307 | } |