1 ; RUN: not llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt
2 ; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+atomics,+sign-ext | FileCheck %s
4 ; Test that atomic loads are assembled properly.
6 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
7 target triple = "wasm32-unknown-unknown"
9 ;===----------------------------------------------------------------------------
10 ; Atomic loads: 32-bit
11 ;===----------------------------------------------------------------------------
15 ; CHECK-LABEL: load_i32_no_offset:
16 ; CHECK: i32.atomic.load $push0=, 0($0){{$}}
17 ; CHECK-NEXT: return $pop0{{$}}
18 define i32 @load_i32_no_offset(i32 *%p) {
19 %v = load atomic i32, i32* %p seq_cst, align 4
23 ; With an nuw add, we can fold an offset.
25 ; CHECK-LABEL: load_i32_with_folded_offset:
26 ; CHECK: i32.atomic.load $push0=, 24($0){{$}}
27 define i32 @load_i32_with_folded_offset(i32* %p) {
28 %q = ptrtoint i32* %p to i32
29 %r = add nuw i32 %q, 24
30 %s = inttoptr i32 %r to i32*
31 %t = load atomic i32, i32* %s seq_cst, align 4
35 ; With an inbounds gep, we can fold an offset.
37 ; CHECK-LABEL: load_i32_with_folded_gep_offset:
38 ; CHECK: i32.atomic.load $push0=, 24($0){{$}}
39 define i32 @load_i32_with_folded_gep_offset(i32* %p) {
40 %s = getelementptr inbounds i32, i32* %p, i32 6
41 %t = load atomic i32, i32* %s seq_cst, align 4
45 ; We can't fold a negative offset though, even with an inbounds gep.
47 ; CHECK-LABEL: load_i32_with_unfolded_gep_negative_offset:
48 ; CHECK: i32.const $push0=, -24{{$}}
49 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
50 ; CHECK: i32.atomic.load $push2=, 0($pop1){{$}}
51 define i32 @load_i32_with_unfolded_gep_negative_offset(i32* %p) {
52 %s = getelementptr inbounds i32, i32* %p, i32 -6
53 %t = load atomic i32, i32* %s seq_cst, align 4
57 ; Without nuw, and even with nsw, we can't fold an offset.
59 ; CHECK-LABEL: load_i32_with_unfolded_offset:
60 ; CHECK: i32.const $push0=, 24{{$}}
61 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
62 ; CHECK: i32.atomic.load $push2=, 0($pop1){{$}}
63 define i32 @load_i32_with_unfolded_offset(i32* %p) {
64 %q = ptrtoint i32* %p to i32
65 %r = add nsw i32 %q, 24
66 %s = inttoptr i32 %r to i32*
67 %t = load atomic i32, i32* %s seq_cst, align 4
71 ; Without inbounds, we can't fold a gep offset.
73 ; CHECK-LABEL: load_i32_with_unfolded_gep_offset:
74 ; CHECK: i32.const $push0=, 24{{$}}
75 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
76 ; CHECK: i32.atomic.load $push2=, 0($pop1){{$}}
77 define i32 @load_i32_with_unfolded_gep_offset(i32* %p) {
78 %s = getelementptr i32, i32* %p, i32 6
79 %t = load atomic i32, i32* %s seq_cst, align 4
83 ; When loading from a fixed address, materialize a zero.
85 ; CHECK-LABEL: load_i32_from_numeric_address
86 ; CHECK: i32.const $push0=, 0{{$}}
87 ; CHECK: i32.atomic.load $push1=, 42($pop0){{$}}
88 define i32 @load_i32_from_numeric_address() {
89 %s = inttoptr i32 42 to i32*
90 %t = load atomic i32, i32* %s seq_cst, align 4
94 ; CHECK-LABEL: load_i32_from_global_address
95 ; CHECK: i32.const $push0=, 0{{$}}
96 ; CHECK: i32.atomic.load $push1=, gv($pop0){{$}}
98 define i32 @load_i32_from_global_address() {
99 %t = load atomic i32, i32* @gv seq_cst, align 4
103 ;===----------------------------------------------------------------------------
104 ; Atomic loads: 64-bit
105 ;===----------------------------------------------------------------------------
109 ; CHECK-LABEL: load_i64_no_offset:
110 ; CHECK: i64.atomic.load $push0=, 0($0){{$}}
111 ; CHECK-NEXT: return $pop0{{$}}
112 define i64 @load_i64_no_offset(i64 *%p) {
113 %v = load atomic i64, i64* %p seq_cst, align 8
117 ; With an nuw add, we can fold an offset.
119 ; CHECK-LABEL: load_i64_with_folded_offset:
120 ; CHECK: i64.atomic.load $push0=, 24($0){{$}}
121 define i64 @load_i64_with_folded_offset(i64* %p) {
122 %q = ptrtoint i64* %p to i32
123 %r = add nuw i32 %q, 24
124 %s = inttoptr i32 %r to i64*
125 %t = load atomic i64, i64* %s seq_cst, align 8
129 ; With an inbounds gep, we can fold an offset.
131 ; CHECK-LABEL: load_i64_with_folded_gep_offset:
132 ; CHECK: i64.atomic.load $push0=, 24($0){{$}}
133 define i64 @load_i64_with_folded_gep_offset(i64* %p) {
134 %s = getelementptr inbounds i64, i64* %p, i32 3
135 %t = load atomic i64, i64* %s seq_cst, align 8
139 ; We can't fold a negative offset though, even with an inbounds gep.
141 ; CHECK-LABEL: load_i64_with_unfolded_gep_negative_offset:
142 ; CHECK: i32.const $push0=, -24{{$}}
143 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
144 ; CHECK: i64.atomic.load $push2=, 0($pop1){{$}}
145 define i64 @load_i64_with_unfolded_gep_negative_offset(i64* %p) {
146 %s = getelementptr inbounds i64, i64* %p, i32 -3
147 %t = load atomic i64, i64* %s seq_cst, align 8
151 ; Without nuw, and even with nsw, we can't fold an offset.
153 ; CHECK-LABEL: load_i64_with_unfolded_offset:
154 ; CHECK: i32.const $push0=, 24{{$}}
155 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
156 ; CHECK: i64.atomic.load $push2=, 0($pop1){{$}}
157 define i64 @load_i64_with_unfolded_offset(i64* %p) {
158 %q = ptrtoint i64* %p to i32
159 %r = add nsw i32 %q, 24
160 %s = inttoptr i32 %r to i64*
161 %t = load atomic i64, i64* %s seq_cst, align 8
165 ; Without inbounds, we can't fold a gep offset.
167 ; CHECK-LABEL: load_i64_with_unfolded_gep_offset:
168 ; CHECK: i32.const $push0=, 24{{$}}
169 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
170 ; CHECK: i64.atomic.load $push2=, 0($pop1){{$}}
171 define i64 @load_i64_with_unfolded_gep_offset(i64* %p) {
172 %s = getelementptr i64, i64* %p, i32 3
173 %t = load atomic i64, i64* %s seq_cst, align 8
177 ;===----------------------------------------------------------------------------
178 ; Atomic stores: 32-bit
179 ;===----------------------------------------------------------------------------
183 ; CHECK-LABEL: store_i32_no_offset:
184 ; CHECK-NEXT: .functype store_i32_no_offset (i32, i32) -> (){{$}}
185 ; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
186 ; CHECK-NEXT: return{{$}}
187 define void @store_i32_no_offset(i32 *%p, i32 %v) {
188 store atomic i32 %v, i32* %p seq_cst, align 4
192 ; With an nuw add, we can fold an offset.
194 ; CHECK-LABEL: store_i32_with_folded_offset:
195 ; CHECK: i32.atomic.store 24($0), $pop0{{$}}
196 define void @store_i32_with_folded_offset(i32* %p) {
197 %q = ptrtoint i32* %p to i32
198 %r = add nuw i32 %q, 24
199 %s = inttoptr i32 %r to i32*
200 store atomic i32 0, i32* %s seq_cst, align 4
204 ; With an inbounds gep, we can fold an offset.
206 ; CHECK-LABEL: store_i32_with_folded_gep_offset:
207 ; CHECK: i32.atomic.store 24($0), $pop0{{$}}
208 define void @store_i32_with_folded_gep_offset(i32* %p) {
209 %s = getelementptr inbounds i32, i32* %p, i32 6
210 store atomic i32 0, i32* %s seq_cst, align 4
214 ; We can't fold a negative offset though, even with an inbounds gep.
216 ; CHECK-LABEL: store_i32_with_unfolded_gep_negative_offset:
217 ; CHECK: i32.const $push0=, -24{{$}}
218 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
219 ; CHECK: i32.atomic.store 0($pop1), $pop2{{$}}
220 define void @store_i32_with_unfolded_gep_negative_offset(i32* %p) {
221 %s = getelementptr inbounds i32, i32* %p, i32 -6
222 store atomic i32 0, i32* %s seq_cst, align 4
226 ; Without nuw, and even with nsw, we can't fold an offset.
228 ; CHECK-LABEL: store_i32_with_unfolded_offset:
229 ; CHECK: i32.const $push0=, 24{{$}}
230 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
231 ; CHECK: i32.atomic.store 0($pop1), $pop2{{$}}
232 define void @store_i32_with_unfolded_offset(i32* %p) {
233 %q = ptrtoint i32* %p to i32
234 %r = add nsw i32 %q, 24
235 %s = inttoptr i32 %r to i32*
236 store atomic i32 0, i32* %s seq_cst, align 4
240 ; Without inbounds, we can't fold a gep offset.
242 ; CHECK-LABEL: store_i32_with_unfolded_gep_offset:
243 ; CHECK: i32.const $push0=, 24{{$}}
244 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
245 ; CHECK: i32.atomic.store 0($pop1), $pop2{{$}}
246 define void @store_i32_with_unfolded_gep_offset(i32* %p) {
247 %s = getelementptr i32, i32* %p, i32 6
248 store atomic i32 0, i32* %s seq_cst, align 4
252 ; When storing from a fixed address, materialize a zero.
254 ; CHECK-LABEL: store_i32_to_numeric_address:
255 ; CHECK: i32.const $push0=, 0{{$}}
256 ; CHECK-NEXT: i32.const $push1=, 0{{$}}
257 ; CHECK-NEXT: i32.atomic.store 42($pop0), $pop1{{$}}
258 define void @store_i32_to_numeric_address() {
259 %s = inttoptr i32 42 to i32*
260 store atomic i32 0, i32* %s seq_cst, align 4
264 ; CHECK-LABEL: store_i32_to_global_address:
265 ; CHECK: i32.const $push0=, 0{{$}}
266 ; CHECK: i32.const $push1=, 0{{$}}
267 ; CHECK: i32.atomic.store gv($pop0), $pop1{{$}}
268 define void @store_i32_to_global_address() {
269 store atomic i32 0, i32* @gv seq_cst, align 4
273 ;===----------------------------------------------------------------------------
274 ; Atomic stores: 64-bit
275 ;===----------------------------------------------------------------------------
279 ; CHECK-LABEL: store_i64_no_offset:
280 ; CHECK-NEXT: .functype store_i64_no_offset (i32, i64) -> (){{$}}
281 ; CHECK-NEXT: i64.atomic.store 0($0), $1{{$}}
282 ; CHECK-NEXT: return{{$}}
283 define void @store_i64_no_offset(i64 *%p, i64 %v) {
284 store atomic i64 %v, i64* %p seq_cst, align 8
288 ; With an nuw add, we can fold an offset.
290 ; CHECK-LABEL: store_i64_with_folded_offset:
291 ; CHECK: i64.atomic.store 24($0), $pop0{{$}}
292 define void @store_i64_with_folded_offset(i64* %p) {
293 %q = ptrtoint i64* %p to i32
294 %r = add nuw i32 %q, 24
295 %s = inttoptr i32 %r to i64*
296 store atomic i64 0, i64* %s seq_cst, align 8
300 ; With an inbounds gep, we can fold an offset.
302 ; CHECK-LABEL: store_i64_with_folded_gep_offset:
303 ; CHECK: i64.atomic.store 24($0), $pop0{{$}}
304 define void @store_i64_with_folded_gep_offset(i64* %p) {
305 %s = getelementptr inbounds i64, i64* %p, i32 3
306 store atomic i64 0, i64* %s seq_cst, align 8
310 ; We can't fold a negative offset though, even with an inbounds gep.
312 ; CHECK-LABEL: store_i64_with_unfolded_gep_negative_offset:
313 ; CHECK: i32.const $push0=, -24{{$}}
314 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
315 ; CHECK: i64.atomic.store 0($pop1), $pop2{{$}}
316 define void @store_i64_with_unfolded_gep_negative_offset(i64* %p) {
317 %s = getelementptr inbounds i64, i64* %p, i32 -3
318 store atomic i64 0, i64* %s seq_cst, align 8
322 ; Without nuw, and even with nsw, we can't fold an offset.
324 ; CHECK-LABEL: store_i64_with_unfolded_offset:
325 ; CHECK: i32.const $push0=, 24{{$}}
326 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
327 ; CHECK: i64.atomic.store 0($pop1), $pop2{{$}}
328 define void @store_i64_with_unfolded_offset(i64* %p) {
329 %q = ptrtoint i64* %p to i32
330 %r = add nsw i32 %q, 24
331 %s = inttoptr i32 %r to i64*
332 store atomic i64 0, i64* %s seq_cst, align 8
336 ; Without inbounds, we can't fold a gep offset.
338 ; CHECK-LABEL: store_i64_with_unfolded_gep_offset:
339 ; CHECK: i32.const $push0=, 24{{$}}
340 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
341 ; CHECK: i64.atomic.store 0($pop1), $pop2{{$}}
342 define void @store_i64_with_unfolded_gep_offset(i64* %p) {
343 %s = getelementptr i64, i64* %p, i32 3
344 store atomic i64 0, i64* %s seq_cst, align 8
348 ;===----------------------------------------------------------------------------
349 ; Atomic sign-extending loads
350 ;===----------------------------------------------------------------------------
352 ; Fold an offset into a sign-extending load.
354 ; CHECK-LABEL: load_i8_i32_s_with_folded_offset:
355 ; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}
356 ; CHECK-NEXT: i32.extend8_s $push1=, $pop0
357 define i32 @load_i8_i32_s_with_folded_offset(i8* %p) {
358 %q = ptrtoint i8* %p to i32
359 %r = add nuw i32 %q, 24
360 %s = inttoptr i32 %r to i8*
361 %t = load atomic i8, i8* %s seq_cst, align 1
362 %u = sext i8 %t to i32
366 ; 32->64 sext load gets selected as i32.atomic.load, i64.extend_i32_s
367 ; CHECK-LABEL: load_i32_i64_s_with_folded_offset:
368 ; CHECK: i32.atomic.load $push0=, 24($0){{$}}
369 ; CHECK-NEXT: i64.extend_i32_s $push1=, $pop0{{$}}
370 define i64 @load_i32_i64_s_with_folded_offset(i32* %p) {
371 %q = ptrtoint i32* %p to i32
372 %r = add nuw i32 %q, 24
373 %s = inttoptr i32 %r to i32*
374 %t = load atomic i32, i32* %s seq_cst, align 4
375 %u = sext i32 %t to i64
379 ; Fold a gep offset into a sign-extending load.
381 ; CHECK-LABEL: load_i8_i32_s_with_folded_gep_offset:
382 ; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}
383 ; CHECK-NEXT: i32.extend8_s $push1=, $pop0
384 define i32 @load_i8_i32_s_with_folded_gep_offset(i8* %p) {
385 %s = getelementptr inbounds i8, i8* %p, i32 24
386 %t = load atomic i8, i8* %s seq_cst, align 1
387 %u = sext i8 %t to i32
391 ; CHECK-LABEL: load_i16_i32_s_with_folded_gep_offset:
392 ; CHECK: i32.atomic.load16_u $push0=, 48($0){{$}}
393 ; CHECK-NEXT: i32.extend16_s $push1=, $pop0
394 define i32 @load_i16_i32_s_with_folded_gep_offset(i16* %p) {
395 %s = getelementptr inbounds i16, i16* %p, i32 24
396 %t = load atomic i16, i16* %s seq_cst, align 2
397 %u = sext i16 %t to i32
401 ; CHECK-LABEL: load_i16_i64_s_with_folded_gep_offset:
402 ; CHECK: i64.atomic.load16_u $push0=, 48($0){{$}}
403 ; CHECK-NEXT: i64.extend16_s $push1=, $pop0
404 define i64 @load_i16_i64_s_with_folded_gep_offset(i16* %p) {
405 %s = getelementptr inbounds i16, i16* %p, i32 24
406 %t = load atomic i16, i16* %s seq_cst, align 2
407 %u = sext i16 %t to i64
411 ; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as
412 ; an 'add' if the or'ed bits are known to be zero.
414 ; CHECK-LABEL: load_i8_i32_s_with_folded_or_offset:
415 ; CHECK: i32.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}}
416 ; CHECK-NEXT: i32.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}
417 define i32 @load_i8_i32_s_with_folded_or_offset(i32 %x) {
418 %and = and i32 %x, -4
419 %t0 = inttoptr i32 %and to i8*
420 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
421 %t1 = load atomic i8, i8* %arrayidx seq_cst, align 1
422 %conv = sext i8 %t1 to i32
426 ; CHECK-LABEL: load_i8_i64_s_with_folded_or_offset:
427 ; CHECK: i64.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}}
428 ; CHECK-NEXT: i64.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}
429 define i64 @load_i8_i64_s_with_folded_or_offset(i32 %x) {
430 %and = and i32 %x, -4
431 %t0 = inttoptr i32 %and to i8*
432 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
433 %t1 = load atomic i8, i8* %arrayidx seq_cst, align 1
434 %conv = sext i8 %t1 to i64
438 ; When loading from a fixed address, materialize a zero.
440 ; CHECK-LABEL: load_i16_i32_s_from_numeric_address
441 ; CHECK: i32.const $push0=, 0{{$}}
442 ; CHECK: i32.atomic.load16_u $push1=, 42($pop0){{$}}
443 ; CHECK-NEXT: i32.extend16_s $push2=, $pop1
444 define i32 @load_i16_i32_s_from_numeric_address() {
445 %s = inttoptr i32 42 to i16*
446 %t = load atomic i16, i16* %s seq_cst, align 2
447 %u = sext i16 %t to i32
451 ; CHECK-LABEL: load_i8_i32_s_from_global_address
452 ; CHECK: i32.const $push0=, 0{{$}}
453 ; CHECK: i32.atomic.load8_u $push1=, gv8($pop0){{$}}
454 ; CHECK-NEXT: i32.extend8_s $push2=, $pop1{{$}}
456 define i32 @load_i8_i32_s_from_global_address() {
457 %t = load atomic i8, i8* @gv8 seq_cst, align 1
458 %u = sext i8 %t to i32
462 ;===----------------------------------------------------------------------------
463 ; Atomic zero-extending loads
464 ;===----------------------------------------------------------------------------
466 ; Fold an offset into a zero-extending load.
468 ; CHECK-LABEL: load_i8_i32_z_with_folded_offset:
469 ; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}
470 define i32 @load_i8_i32_z_with_folded_offset(i8* %p) {
471 %q = ptrtoint i8* %p to i32
472 %r = add nuw i32 %q, 24
473 %s = inttoptr i32 %r to i8*
474 %t = load atomic i8, i8* %s seq_cst, align 1
475 %u = zext i8 %t to i32
479 ; CHECK-LABEL: load_i32_i64_z_with_folded_offset:
480 ; CHECK: i64.atomic.load32_u $push0=, 24($0){{$}}
481 define i64 @load_i32_i64_z_with_folded_offset(i32* %p) {
482 %q = ptrtoint i32* %p to i32
483 %r = add nuw i32 %q, 24
484 %s = inttoptr i32 %r to i32*
485 %t = load atomic i32, i32* %s seq_cst, align 4
486 %u = zext i32 %t to i64
490 ; Fold a gep offset into a zero-extending load.
492 ; CHECK-LABEL: load_i8_i32_z_with_folded_gep_offset:
493 ; CHECK: i32.atomic.load8_u $push0=, 24($0){{$}}
494 define i32 @load_i8_i32_z_with_folded_gep_offset(i8* %p) {
495 %s = getelementptr inbounds i8, i8* %p, i32 24
496 %t = load atomic i8, i8* %s seq_cst, align 1
497 %u = zext i8 %t to i32
501 ; CHECK-LABEL: load_i16_i32_z_with_folded_gep_offset:
502 ; CHECK: i32.atomic.load16_u $push0=, 48($0){{$}}
503 define i32 @load_i16_i32_z_with_folded_gep_offset(i16* %p) {
504 %s = getelementptr inbounds i16, i16* %p, i32 24
505 %t = load atomic i16, i16* %s seq_cst, align 2
506 %u = zext i16 %t to i32
510 ; CHECK-LABEL: load_i16_i64_z_with_folded_gep_offset:
511 ; CHECK: i64.atomic.load16_u $push0=, 48($0){{$}}
512 define i64 @load_i16_i64_z_with_folded_gep_offset(i16* %p) {
513 %s = getelementptr inbounds i16, i16* %p, i64 24
514 %t = load atomic i16, i16* %s seq_cst, align 2
515 %u = zext i16 %t to i64
519 ; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as
520 ; an 'add' if the or'ed bits are known to be zero.
522 ; CHECK-LABEL: load_i8_i32_z_with_folded_or_offset:
523 ; CHECK: i32.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}}
524 define i32 @load_i8_i32_z_with_folded_or_offset(i32 %x) {
525 %and = and i32 %x, -4
526 %t0 = inttoptr i32 %and to i8*
527 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
528 %t1 = load atomic i8, i8* %arrayidx seq_cst, align 1
529 %conv = zext i8 %t1 to i32
533 ; CHECK-LABEL: load_i8_i64_z_with_folded_or_offset:
534 ; CHECK: i64.atomic.load8_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}){{$}}
535 define i64 @load_i8_i64_z_with_folded_or_offset(i32 %x) {
536 %and = and i32 %x, -4
537 %t0 = inttoptr i32 %and to i8*
538 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
539 %t1 = load atomic i8, i8* %arrayidx seq_cst, align 1
540 %conv = zext i8 %t1 to i64
544 ; When loading from a fixed address, materialize a zero.
546 ; CHECK-LABEL: load_i16_i32_z_from_numeric_address
547 ; CHECK: i32.const $push0=, 0{{$}}
548 ; CHECK: i32.atomic.load16_u $push1=, 42($pop0){{$}}
549 define i32 @load_i16_i32_z_from_numeric_address() {
550 %s = inttoptr i32 42 to i16*
551 %t = load atomic i16, i16* %s seq_cst, align 2
552 %u = zext i16 %t to i32
556 ; CHECK-LABEL: load_i8_i32_z_from_global_address
557 ; CHECK: i32.const $push0=, 0{{$}}
558 ; CHECK: i32.atomic.load8_u $push1=, gv8($pop0){{$}}
559 define i32 @load_i8_i32_z_from_global_address() {
560 %t = load atomic i8, i8* @gv8 seq_cst, align 1
561 %u = zext i8 %t to i32
565 ; i8 return value should test anyext loads
567 ; CHECK-LABEL: load_i8_i32_retvalue:
568 ; CHECK: i32.atomic.load8_u $push0=, 0($0){{$}}
569 ; CHECK-NEXT: return $pop0{{$}}
570 define i8 @load_i8_i32_retvalue(i8 *%p) {
571 %v = load atomic i8, i8* %p seq_cst, align 1
575 ;===----------------------------------------------------------------------------
576 ; Atomic truncating stores
577 ;===----------------------------------------------------------------------------
579 ; Fold an offset into a truncating store.
581 ; CHECK-LABEL: store_i8_i32_with_folded_offset:
582 ; CHECK: i32.atomic.store8 24($0), $1{{$}}
583 define void @store_i8_i32_with_folded_offset(i8* %p, i32 %v) {
584 %q = ptrtoint i8* %p to i32
585 %r = add nuw i32 %q, 24
586 %s = inttoptr i32 %r to i8*
587 %t = trunc i32 %v to i8
588 store atomic i8 %t, i8* %s seq_cst, align 1
592 ; CHECK-LABEL: store_i32_i64_with_folded_offset:
593 ; CHECK: i64.atomic.store32 24($0), $1{{$}}
594 define void @store_i32_i64_with_folded_offset(i32* %p, i64 %v) {
595 %q = ptrtoint i32* %p to i32
596 %r = add nuw i32 %q, 24
597 %s = inttoptr i32 %r to i32*
598 %t = trunc i64 %v to i32
599 store atomic i32 %t, i32* %s seq_cst, align 4
603 ; Fold a gep offset into a truncating store.
605 ; CHECK-LABEL: store_i8_i32_with_folded_gep_offset:
606 ; CHECK: i32.atomic.store8 24($0), $1{{$}}
607 define void @store_i8_i32_with_folded_gep_offset(i8* %p, i32 %v) {
608 %s = getelementptr inbounds i8, i8* %p, i32 24
609 %t = trunc i32 %v to i8
610 store atomic i8 %t, i8* %s seq_cst, align 1
614 ; CHECK-LABEL: store_i16_i32_with_folded_gep_offset:
615 ; CHECK: i32.atomic.store16 48($0), $1{{$}}
616 define void @store_i16_i32_with_folded_gep_offset(i16* %p, i32 %v) {
617 %s = getelementptr inbounds i16, i16* %p, i32 24
618 %t = trunc i32 %v to i16
619 store atomic i16 %t, i16* %s seq_cst, align 2
623 ; CHECK-LABEL: store_i16_i64_with_folded_gep_offset:
624 ; CHECK: i64.atomic.store16 48($0), $1{{$}}
625 define void @store_i16_i64_with_folded_gep_offset(i16* %p, i64 %v) {
626 %s = getelementptr inbounds i16, i16* %p, i32 24
627 %t = trunc i64 %v to i16
628 store atomic i16 %t, i16* %s seq_cst, align 2
632 ; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as
633 ; an 'add' if the or'ed bits are known to be zero.
635 ; CHECK-LABEL: store_i8_i32_with_folded_or_offset:
636 ; CHECK: i32.atomic.store8 2($pop{{[0-9]+}}), $1{{$}}
637 define void @store_i8_i32_with_folded_or_offset(i32 %x, i32 %v) {
638 %and = and i32 %x, -4
639 %p = inttoptr i32 %and to i8*
640 %arrayidx = getelementptr inbounds i8, i8* %p, i32 2
641 %t = trunc i32 %v to i8
642 store atomic i8 %t, i8* %arrayidx seq_cst, align 1
646 ; CHECK-LABEL: store_i8_i64_with_folded_or_offset:
647 ; CHECK: i64.atomic.store8 2($pop{{[0-9]+}}), $1{{$}}
648 define void @store_i8_i64_with_folded_or_offset(i32 %x, i64 %v) {
649 %and = and i32 %x, -4
650 %p = inttoptr i32 %and to i8*
651 %arrayidx = getelementptr inbounds i8, i8* %p, i32 2
652 %t = trunc i64 %v to i8
653 store atomic i8 %t, i8* %arrayidx seq_cst, align 1
657 ;===----------------------------------------------------------------------------
658 ; Atomic binary read-modify-writes: 32-bit
659 ;===----------------------------------------------------------------------------
661 ; There are several RMW instructions, but here we only test 'add' as an example.
665 ; CHECK-LABEL: rmw_add_i32_no_offset:
666 ; CHECK-NEXT: .functype rmw_add_i32_no_offset (i32, i32) -> (i32){{$}}
667 ; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
668 ; CHECK-NEXT: return $pop0{{$}}
669 define i32 @rmw_add_i32_no_offset(i32* %p, i32 %v) {
670 %old = atomicrmw add i32* %p, i32 %v seq_cst
674 ; With an nuw add, we can fold an offset.
676 ; CHECK-LABEL: rmw_add_i32_with_folded_offset:
677 ; CHECK: i32.atomic.rmw.add $push0=, 24($0), $1{{$}}
678 define i32 @rmw_add_i32_with_folded_offset(i32* %p, i32 %v) {
679 %q = ptrtoint i32* %p to i32
680 %r = add nuw i32 %q, 24
681 %s = inttoptr i32 %r to i32*
682 %old = atomicrmw add i32* %s, i32 %v seq_cst
686 ; With an inbounds gep, we can fold an offset.
688 ; CHECK-LABEL: rmw_add_i32_with_folded_gep_offset:
689 ; CHECK: i32.atomic.rmw.add $push0=, 24($0), $1{{$}}
690 define i32 @rmw_add_i32_with_folded_gep_offset(i32* %p, i32 %v) {
691 %s = getelementptr inbounds i32, i32* %p, i32 6
692 %old = atomicrmw add i32* %s, i32 %v seq_cst
696 ; We can't fold a negative offset though, even with an inbounds gep.
698 ; CHECK-LABEL: rmw_add_i32_with_unfolded_gep_negative_offset:
699 ; CHECK: i32.const $push0=, -24{{$}}
700 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
701 ; CHECK: i32.atomic.rmw.add $push2=, 0($pop1), $1{{$}}
702 define i32 @rmw_add_i32_with_unfolded_gep_negative_offset(i32* %p, i32 %v) {
703 %s = getelementptr inbounds i32, i32* %p, i32 -6
704 %old = atomicrmw add i32* %s, i32 %v seq_cst
708 ; Without nuw, and even with nsw, we can't fold an offset.
710 ; CHECK-LABEL: rmw_add_i32_with_unfolded_offset:
711 ; CHECK: i32.const $push0=, 24{{$}}
712 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
713 ; CHECK: i32.atomic.rmw.add $push2=, 0($pop1), $1{{$}}
714 define i32 @rmw_add_i32_with_unfolded_offset(i32* %p, i32 %v) {
715 %q = ptrtoint i32* %p to i32
716 %r = add nsw i32 %q, 24
717 %s = inttoptr i32 %r to i32*
718 %old = atomicrmw add i32* %s, i32 %v seq_cst
722 ; Without inbounds, we can't fold a gep offset.
724 ; CHECK-LABEL: rmw_add_i32_with_unfolded_gep_offset:
725 ; CHECK: i32.const $push0=, 24{{$}}
726 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
727 ; CHECK: i32.atomic.rmw.add $push2=, 0($pop1), $1{{$}}
728 define i32 @rmw_add_i32_with_unfolded_gep_offset(i32* %p, i32 %v) {
729 %s = getelementptr i32, i32* %p, i32 6
730 %old = atomicrmw add i32* %s, i32 %v seq_cst
734 ; When loading from a fixed address, materialize a zero.
736 ; CHECK-LABEL: rmw_add_i32_from_numeric_address
737 ; CHECK: i32.const $push0=, 0{{$}}
738 ; CHECK: i32.atomic.rmw.add $push1=, 42($pop0), $0{{$}}
739 define i32 @rmw_add_i32_from_numeric_address(i32 %v) {
740 %s = inttoptr i32 42 to i32*
741 %old = atomicrmw add i32* %s, i32 %v seq_cst
745 ; CHECK-LABEL: rmw_add_i32_from_global_address
746 ; CHECK: i32.const $push0=, 0{{$}}
747 ; CHECK: i32.atomic.rmw.add $push1=, gv($pop0), $0{{$}}
748 define i32 @rmw_add_i32_from_global_address(i32 %v) {
749 %old = atomicrmw add i32* @gv, i32 %v seq_cst
753 ;===----------------------------------------------------------------------------
754 ; Atomic binary read-modify-writes: 64-bit
755 ;===----------------------------------------------------------------------------
759 ; CHECK-LABEL: rmw_add_i64_no_offset:
760 ; CHECK-NEXT: .functype rmw_add_i64_no_offset (i32, i64) -> (i64){{$}}
761 ; CHECK: i64.atomic.rmw.add $push0=, 0($0), $1{{$}}
762 ; CHECK-NEXT: return $pop0{{$}}
763 define i64 @rmw_add_i64_no_offset(i64* %p, i64 %v) {
764 %old = atomicrmw add i64* %p, i64 %v seq_cst
768 ; With an nuw add, we can fold an offset.
770 ; CHECK-LABEL: rmw_add_i64_with_folded_offset:
771 ; CHECK: i64.atomic.rmw.add $push0=, 24($0), $1{{$}}
772 define i64 @rmw_add_i64_with_folded_offset(i64* %p, i64 %v) {
773 %q = ptrtoint i64* %p to i32
774 %r = add nuw i32 %q, 24
775 %s = inttoptr i32 %r to i64*
776 %old = atomicrmw add i64* %s, i64 %v seq_cst
780 ; With an inbounds gep, we can fold an offset.
782 ; CHECK-LABEL: rmw_add_i64_with_folded_gep_offset:
783 ; CHECK: i64.atomic.rmw.add $push0=, 24($0), $1{{$}}
784 define i64 @rmw_add_i64_with_folded_gep_offset(i64* %p, i64 %v) {
785 %s = getelementptr inbounds i64, i64* %p, i32 3
786 %old = atomicrmw add i64* %s, i64 %v seq_cst
790 ; We can't fold a negative offset though, even with an inbounds gep.
792 ; CHECK-LABEL: rmw_add_i64_with_unfolded_gep_negative_offset:
793 ; CHECK: i32.const $push0=, -24{{$}}
794 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
795 ; CHECK: i64.atomic.rmw.add $push2=, 0($pop1), $1{{$}}
796 define i64 @rmw_add_i64_with_unfolded_gep_negative_offset(i64* %p, i64 %v) {
797 %s = getelementptr inbounds i64, i64* %p, i32 -3
798 %old = atomicrmw add i64* %s, i64 %v seq_cst
802 ; Without nuw, and even with nsw, we can't fold an offset.
804 ; CHECK-LABEL: rmw_add_i64_with_unfolded_offset:
805 ; CHECK: i32.const $push0=, 24{{$}}
806 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
807 ; CHECK: i64.atomic.rmw.add $push2=, 0($pop1), $1{{$}}
808 define i64 @rmw_add_i64_with_unfolded_offset(i64* %p, i64 %v) {
809 %q = ptrtoint i64* %p to i32
810 %r = add nsw i32 %q, 24
811 %s = inttoptr i32 %r to i64*
812 %old = atomicrmw add i64* %s, i64 %v seq_cst
816 ; Without inbounds, we can't fold a gep offset.
818 ; CHECK-LABEL: rmw_add_i64_with_unfolded_gep_offset:
819 ; CHECK: i32.const $push0=, 24{{$}}
820 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
821 ; CHECK: i64.atomic.rmw.add $push2=, 0($pop1), $1{{$}}
822 define i64 @rmw_add_i64_with_unfolded_gep_offset(i64* %p, i64 %v) {
823 %s = getelementptr i64, i64* %p, i32 3
824 %old = atomicrmw add i64* %s, i64 %v seq_cst
828 ;===----------------------------------------------------------------------------
829 ; Atomic truncating & sign-extending binary RMWs
830 ;===----------------------------------------------------------------------------
832 ; Fold an offset into a sign-extending rmw.
834 ; CHECK-LABEL: rmw_add_i8_i32_s_with_folded_offset:
835 ; CHECK: i32.atomic.rmw8.add_u $push0=, 24($0), $1{{$}}
836 ; CHECK-NEXT: i32.extend8_s $push1=, $pop0
837 define i32 @rmw_add_i8_i32_s_with_folded_offset(i8* %p, i32 %v) {
838 %q = ptrtoint i8* %p to i32
839 %r = add nuw i32 %q, 24
840 %s = inttoptr i32 %r to i8*
841 %t = trunc i32 %v to i8
842 %old = atomicrmw add i8* %s, i8 %t seq_cst
843 %u = sext i8 %old to i32
847 ; 32->64 sext rmw gets selected as i32.atomic.rmw.add, i64.extend_i32_s
848 ; CHECK-LABEL: rmw_add_i32_i64_s_with_folded_offset:
849 ; CHECK: i32.wrap_i64 $push0=, $1
850 ; CHECK-NEXT: i32.atomic.rmw.add $push1=, 24($0), $pop0{{$}}
851 ; CHECK-NEXT: i64.extend_i32_s $push2=, $pop1{{$}}
852 define i64 @rmw_add_i32_i64_s_with_folded_offset(i32* %p, i64 %v) {
853 %q = ptrtoint i32* %p to i32
854 %r = add nuw i32 %q, 24
855 %s = inttoptr i32 %r to i32*
856 %t = trunc i64 %v to i32
857 %old = atomicrmw add i32* %s, i32 %t seq_cst
858 %u = sext i32 %old to i64
862 ; Fold a gep offset into a sign-extending rmw.
864 ; CHECK-LABEL: rmw_add_i8_i32_s_with_folded_gep_offset:
865 ; CHECK: i32.atomic.rmw8.add_u $push0=, 24($0), $1{{$}}
866 ; CHECK-NEXT: i32.extend8_s $push1=, $pop0
867 define i32 @rmw_add_i8_i32_s_with_folded_gep_offset(i8* %p, i32 %v) {
868 %s = getelementptr inbounds i8, i8* %p, i32 24
869 %t = trunc i32 %v to i8
870 %old = atomicrmw add i8* %s, i8 %t seq_cst
871 %u = sext i8 %old to i32
875 ; CHECK-LABEL: rmw_add_i16_i32_s_with_folded_gep_offset:
876 ; CHECK: i32.atomic.rmw16.add_u $push0=, 48($0), $1{{$}}
877 ; CHECK-NEXT: i32.extend16_s $push1=, $pop0
878 define i32 @rmw_add_i16_i32_s_with_folded_gep_offset(i16* %p, i32 %v) {
879 %s = getelementptr inbounds i16, i16* %p, i32 24
880 %t = trunc i32 %v to i16
881 %old = atomicrmw add i16* %s, i16 %t seq_cst
882 %u = sext i16 %old to i32
886 ; CHECK-LABEL: rmw_add_i16_i64_s_with_folded_gep_offset:
887 ; CHECK: i64.atomic.rmw16.add_u $push0=, 48($0), $1{{$}}
888 ; CHECK-NEXT: i64.extend16_s $push1=, $pop0
889 define i64 @rmw_add_i16_i64_s_with_folded_gep_offset(i16* %p, i64 %v) {
890 %s = getelementptr inbounds i16, i16* %p, i32 24
891 %t = trunc i64 %v to i16
892 %old = atomicrmw add i16* %s, i16 %t seq_cst
893 %u = sext i16 %old to i64
897 ; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as
898 ; an 'add' if the or'ed bits are known to be zero.
900 ; CHECK-LABEL: rmw_add_i8_i32_s_with_folded_or_offset:
901 ; CHECK: i32.atomic.rmw8.add_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1{{$}}
902 ; CHECK-NEXT: i32.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}
903 define i32 @rmw_add_i8_i32_s_with_folded_or_offset(i32 %x, i32 %v) {
904 %and = and i32 %x, -4
905 %t0 = inttoptr i32 %and to i8*
906 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
907 %t = trunc i32 %v to i8
908 %old = atomicrmw add i8* %arrayidx, i8 %t seq_cst
909 %conv = sext i8 %old to i32
913 ; CHECK-LABEL: rmw_add_i8_i64_s_with_folded_or_offset:
914 ; CHECK: i64.atomic.rmw8.add_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1{{$}}
915 ; CHECK-NEXT: i64.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}
916 define i64 @rmw_add_i8_i64_s_with_folded_or_offset(i32 %x, i64 %v) {
917 %and = and i32 %x, -4
918 %t0 = inttoptr i32 %and to i8*
919 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
920 %t = trunc i64 %v to i8
921 %old = atomicrmw add i8* %arrayidx, i8 %t seq_cst
922 %conv = sext i8 %old to i64
926 ; When loading from a fixed address, materialize a zero.
928 ; CHECK-LABEL: rmw_add_i16_i32_s_from_numeric_address
929 ; CHECK: i32.const $push0=, 0{{$}}
930 ; CHECK: i32.atomic.rmw16.add_u $push1=, 42($pop0), $0{{$}}
931 ; CHECK-NEXT: i32.extend16_s $push2=, $pop1
932 define i32 @rmw_add_i16_i32_s_from_numeric_address(i32 %v) {
933 %s = inttoptr i32 42 to i16*
934 %t = trunc i32 %v to i16
935 %old = atomicrmw add i16* %s, i16 %t seq_cst
936 %u = sext i16 %old to i32
940 ; CHECK-LABEL: rmw_add_i8_i32_s_from_global_address
941 ; CHECK: i32.const $push0=, 0{{$}}
942 ; CHECK: i32.atomic.rmw8.add_u $push1=, gv8($pop0), $0{{$}}
943 ; CHECK-NEXT: i32.extend8_s $push2=, $pop1{{$}}
944 define i32 @rmw_add_i8_i32_s_from_global_address(i32 %v) {
945 %t = trunc i32 %v to i8
946 %old = atomicrmw add i8* @gv8, i8 %t seq_cst
947 %u = sext i8 %old to i32
951 ;===----------------------------------------------------------------------------
952 ; Atomic truncating & zero-extending binary RMWs
953 ;===----------------------------------------------------------------------------
955 ; Fold an offset into a zero-extending rmw.
957 ; CHECK-LABEL: rmw_add_i8_i32_z_with_folded_offset:
958 ; CHECK: i32.atomic.rmw8.add_u $push0=, 24($0), $1{{$}}
959 define i32 @rmw_add_i8_i32_z_with_folded_offset(i8* %p, i32 %v) {
960 %q = ptrtoint i8* %p to i32
961 %r = add nuw i32 %q, 24
962 %s = inttoptr i32 %r to i8*
963 %t = trunc i32 %v to i8
964 %old = atomicrmw add i8* %s, i8 %t seq_cst
965 %u = zext i8 %old to i32
969 ; CHECK-LABEL: rmw_add_i32_i64_z_with_folded_offset:
970 ; CHECK: i64.atomic.rmw32.add_u $push0=, 24($0), $1{{$}}
971 define i64 @rmw_add_i32_i64_z_with_folded_offset(i32* %p, i64 %v) {
972 %q = ptrtoint i32* %p to i32
973 %r = add nuw i32 %q, 24
974 %s = inttoptr i32 %r to i32*
975 %t = trunc i64 %v to i32
976 %old = atomicrmw add i32* %s, i32 %t seq_cst
977 %u = zext i32 %old to i64
981 ; Fold a gep offset into a zero-extending rmw.
983 ; CHECK-LABEL: rmw_add_i8_i32_z_with_folded_gep_offset:
984 ; CHECK: i32.atomic.rmw8.add_u $push0=, 24($0), $1{{$}}
985 define i32 @rmw_add_i8_i32_z_with_folded_gep_offset(i8* %p, i32 %v) {
986 %s = getelementptr inbounds i8, i8* %p, i32 24
987 %t = trunc i32 %v to i8
988 %old = atomicrmw add i8* %s, i8 %t seq_cst
989 %u = zext i8 %old to i32
993 ; CHECK-LABEL: rmw_add_i16_i32_z_with_folded_gep_offset:
994 ; CHECK: i32.atomic.rmw16.add_u $push0=, 48($0), $1{{$}}
995 define i32 @rmw_add_i16_i32_z_with_folded_gep_offset(i16* %p, i32 %v) {
996 %s = getelementptr inbounds i16, i16* %p, i32 24
997 %t = trunc i32 %v to i16
998 %old = atomicrmw add i16* %s, i16 %t seq_cst
999 %u = zext i16 %old to i32
1003 ; CHECK-LABEL: rmw_add_i16_i64_z_with_folded_gep_offset:
1004 ; CHECK: i64.atomic.rmw16.add_u $push0=, 48($0), $1{{$}}
1005 define i64 @rmw_add_i16_i64_z_with_folded_gep_offset(i16* %p, i64 %v) {
1006 %s = getelementptr inbounds i16, i16* %p, i32 24
1007 %t = trunc i64 %v to i16
1008 %old = atomicrmw add i16* %s, i16 %t seq_cst
1009 %u = zext i16 %old to i64
1013 ; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as
1014 ; an 'add' if the or'ed bits are known to be zero.
1016 ; CHECK-LABEL: rmw_add_i8_i32_z_with_folded_or_offset:
1017 ; CHECK: i32.atomic.rmw8.add_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1{{$}}
1018 define i32 @rmw_add_i8_i32_z_with_folded_or_offset(i32 %x, i32 %v) {
1019 %and = and i32 %x, -4
1020 %t0 = inttoptr i32 %and to i8*
1021 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
1022 %t = trunc i32 %v to i8
1023 %old = atomicrmw add i8* %arrayidx, i8 %t seq_cst
1024 %conv = zext i8 %old to i32
1028 ; CHECK-LABEL: rmw_add_i8_i64_z_with_folded_or_offset:
1029 ; CHECK: i64.atomic.rmw8.add_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1{{$}}
1030 define i64 @rmw_add_i8_i64_z_with_folded_or_offset(i32 %x, i64 %v) {
1031 %and = and i32 %x, -4
1032 %t0 = inttoptr i32 %and to i8*
1033 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
1034 %t = trunc i64 %v to i8
1035 %old = atomicrmw add i8* %arrayidx, i8 %t seq_cst
1036 %conv = zext i8 %old to i64
1040 ; When loading from a fixed address, materialize a zero.
1042 ; CHECK-LABEL: rmw_add_i16_i32_z_from_numeric_address
1043 ; CHECK: i32.const $push0=, 0{{$}}
1044 ; CHECK: i32.atomic.rmw16.add_u $push1=, 42($pop0), $0{{$}}
1045 define i32 @rmw_add_i16_i32_z_from_numeric_address(i32 %v) {
1046 %s = inttoptr i32 42 to i16*
1047 %t = trunc i32 %v to i16
1048 %old = atomicrmw add i16* %s, i16 %t seq_cst
1049 %u = zext i16 %old to i32
1053 ; CHECK-LABEL: rmw_add_i8_i32_z_from_global_address
1054 ; CHECK: i32.const $push0=, 0{{$}}
1055 ; CHECK: i32.atomic.rmw8.add_u $push1=, gv8($pop0), $0{{$}}
1056 define i32 @rmw_add_i8_i32_z_from_global_address(i32 %v) {
1057 %t = trunc i32 %v to i8
1058 %old = atomicrmw add i8* @gv8, i8 %t seq_cst
1059 %u = zext i8 %old to i32
1063 ; i8 return value should test anyext RMWs
1065 ; CHECK-LABEL: rmw_add_i8_i32_retvalue:
1066 ; CHECK: i32.atomic.rmw8.add_u $push0=, 0($0), $1{{$}}
1067 ; CHECK-NEXT: return $pop0{{$}}
1068 define i8 @rmw_add_i8_i32_retvalue(i8 *%p, i32 %v) {
1069 %t = trunc i32 %v to i8
1070 %old = atomicrmw add i8* %p, i8 %t seq_cst
1074 ;===----------------------------------------------------------------------------
1075 ; Atomic ternary read-modify-writes: 32-bit
1076 ;===----------------------------------------------------------------------------
1080 ; CHECK-LABEL: cmpxchg_i32_no_offset:
1081 ; CHECK-NEXT: .functype cmpxchg_i32_no_offset (i32, i32, i32) -> (i32){{$}}
1082 ; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
1083 ; CHECK-NEXT: return $pop0{{$}}
1084 define i32 @cmpxchg_i32_no_offset(i32* %p, i32 %exp, i32 %new) {
1085 %pair = cmpxchg i32* %p, i32 %exp, i32 %new seq_cst seq_cst
1086 %old = extractvalue { i32, i1 } %pair, 0
1090 ; With an nuw add, we can fold an offset.
1092 ; CHECK-LABEL: cmpxchg_i32_with_folded_offset:
1093 ; CHECK: i32.atomic.rmw.cmpxchg $push0=, 24($0), $1, $2{{$}}
1094 define i32 @cmpxchg_i32_with_folded_offset(i32* %p, i32 %exp, i32 %new) {
1095 %q = ptrtoint i32* %p to i32
1096 %r = add nuw i32 %q, 24
1097 %s = inttoptr i32 %r to i32*
1098 %pair = cmpxchg i32* %s, i32 %exp, i32 %new seq_cst seq_cst
1099 %old = extractvalue { i32, i1 } %pair, 0
1103 ; With an inbounds gep, we can fold an offset.
1105 ; CHECK-LABEL: cmpxchg_i32_with_folded_gep_offset:
1106 ; CHECK: i32.atomic.rmw.cmpxchg $push0=, 24($0), $1, $2{{$}}
1107 define i32 @cmpxchg_i32_with_folded_gep_offset(i32* %p, i32 %exp, i32 %new) {
1108 %s = getelementptr inbounds i32, i32* %p, i32 6
1109 %pair = cmpxchg i32* %s, i32 %exp, i32 %new seq_cst seq_cst
1110 %old = extractvalue { i32, i1 } %pair, 0
1114 ; We can't fold a negative offset though, even with an inbounds gep.
1116 ; CHECK-LABEL: cmpxchg_i32_with_unfolded_gep_negative_offset:
1117 ; CHECK: i32.const $push0=, -24{{$}}
1118 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1119 ; CHECK: i32.atomic.rmw.cmpxchg $push2=, 0($pop1), $1, $2{{$}}
1120 define i32 @cmpxchg_i32_with_unfolded_gep_negative_offset(i32* %p, i32 %exp, i32 %new) {
1121 %s = getelementptr inbounds i32, i32* %p, i32 -6
1122 %pair = cmpxchg i32* %s, i32 %exp, i32 %new seq_cst seq_cst
1123 %old = extractvalue { i32, i1 } %pair, 0
1127 ; Without nuw, and even with nsw, we can't fold an offset.
1129 ; CHECK-LABEL: cmpxchg_i32_with_unfolded_offset:
1130 ; CHECK: i32.const $push0=, 24{{$}}
1131 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1132 ; CHECK: i32.atomic.rmw.cmpxchg $push2=, 0($pop1), $1, $2{{$}}
1133 define i32 @cmpxchg_i32_with_unfolded_offset(i32* %p, i32 %exp, i32 %new) {
1134 %q = ptrtoint i32* %p to i32
1135 %r = add nsw i32 %q, 24
1136 %s = inttoptr i32 %r to i32*
1137 %pair = cmpxchg i32* %s, i32 %exp, i32 %new seq_cst seq_cst
1138 %old = extractvalue { i32, i1 } %pair, 0
1142 ; Without inbounds, we can't fold a gep offset.
1144 ; CHECK-LABEL: cmpxchg_i32_with_unfolded_gep_offset:
1145 ; CHECK: i32.const $push0=, 24{{$}}
1146 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1147 ; CHECK: i32.atomic.rmw.cmpxchg $push2=, 0($pop1), $1, $2{{$}}
1148 define i32 @cmpxchg_i32_with_unfolded_gep_offset(i32* %p, i32 %exp, i32 %new) {
1149 %s = getelementptr i32, i32* %p, i32 6
1150 %pair = cmpxchg i32* %s, i32 %exp, i32 %new seq_cst seq_cst
1151 %old = extractvalue { i32, i1 } %pair, 0
1155 ; When loading from a fixed address, materialize a zero.
1157 ; CHECK-LABEL: cmpxchg_i32_from_numeric_address
1158 ; CHECK: i32.const $push0=, 0{{$}}
1159 ; CHECK: i32.atomic.rmw.cmpxchg $push1=, 42($pop0), $0, $1{{$}}
1160 define i32 @cmpxchg_i32_from_numeric_address(i32 %exp, i32 %new) {
1161 %s = inttoptr i32 42 to i32*
1162 %pair = cmpxchg i32* %s, i32 %exp, i32 %new seq_cst seq_cst
1163 %old = extractvalue { i32, i1 } %pair, 0
1167 ; CHECK-LABEL: cmpxchg_i32_from_global_address
1168 ; CHECK: i32.const $push0=, 0{{$}}
1169 ; CHECK: i32.atomic.rmw.cmpxchg $push1=, gv($pop0), $0, $1{{$}}
1170 define i32 @cmpxchg_i32_from_global_address(i32 %exp, i32 %new) {
1171 %pair = cmpxchg i32* @gv, i32 %exp, i32 %new seq_cst seq_cst
1172 %old = extractvalue { i32, i1 } %pair, 0
1176 ;===----------------------------------------------------------------------------
1177 ; Atomic ternary read-modify-writes: 64-bit
1178 ;===----------------------------------------------------------------------------
1182 ; CHECK-LABEL: cmpxchg_i64_no_offset:
1183 ; CHECK-NEXT: .functype cmpxchg_i64_no_offset (i32, i64, i64) -> (i64){{$}}
1184 ; CHECK: i64.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
1185 ; CHECK-NEXT: return $pop0{{$}}
1186 define i64 @cmpxchg_i64_no_offset(i64* %p, i64 %exp, i64 %new) {
1187 %pair = cmpxchg i64* %p, i64 %exp, i64 %new seq_cst seq_cst
1188 %old = extractvalue { i64, i1 } %pair, 0
1192 ; With an nuw add, we can fold an offset.
1194 ; CHECK-LABEL: cmpxchg_i64_with_folded_offset:
1195 ; CHECK: i64.atomic.rmw.cmpxchg $push0=, 24($0), $1, $2{{$}}
1196 define i64 @cmpxchg_i64_with_folded_offset(i64* %p, i64 %exp, i64 %new) {
1197 %q = ptrtoint i64* %p to i32
1198 %r = add nuw i32 %q, 24
1199 %s = inttoptr i32 %r to i64*
1200 %pair = cmpxchg i64* %s, i64 %exp, i64 %new seq_cst seq_cst
1201 %old = extractvalue { i64, i1 } %pair, 0
1205 ; With an inbounds gep, we can fold an offset.
1207 ; CHECK-LABEL: cmpxchg_i64_with_folded_gep_offset:
1208 ; CHECK: i64.atomic.rmw.cmpxchg $push0=, 24($0), $1, $2{{$}}
1209 define i64 @cmpxchg_i64_with_folded_gep_offset(i64* %p, i64 %exp, i64 %new) {
1210 %s = getelementptr inbounds i64, i64* %p, i32 3
1211 %pair = cmpxchg i64* %s, i64 %exp, i64 %new seq_cst seq_cst
1212 %old = extractvalue { i64, i1 } %pair, 0
1216 ; We can't fold a negative offset though, even with an inbounds gep.
1218 ; CHECK-LABEL: cmpxchg_i64_with_unfolded_gep_negative_offset:
1219 ; CHECK: i32.const $push0=, -24{{$}}
1220 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1221 ; CHECK: i64.atomic.rmw.cmpxchg $push2=, 0($pop1), $1, $2{{$}}
1222 define i64 @cmpxchg_i64_with_unfolded_gep_negative_offset(i64* %p, i64 %exp, i64 %new) {
1223 %s = getelementptr inbounds i64, i64* %p, i32 -3
1224 %pair = cmpxchg i64* %s, i64 %exp, i64 %new seq_cst seq_cst
1225 %old = extractvalue { i64, i1 } %pair, 0
1229 ; Without nuw, and even with nsw, we can't fold an offset.
1231 ; CHECK-LABEL: cmpxchg_i64_with_unfolded_offset:
1232 ; CHECK: i32.const $push0=, 24{{$}}
1233 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1234 ; CHECK: i64.atomic.rmw.cmpxchg $push2=, 0($pop1), $1, $2{{$}}
1235 define i64 @cmpxchg_i64_with_unfolded_offset(i64* %p, i64 %exp, i64 %new) {
1236 %q = ptrtoint i64* %p to i32
1237 %r = add nsw i32 %q, 24
1238 %s = inttoptr i32 %r to i64*
1239 %pair = cmpxchg i64* %s, i64 %exp, i64 %new seq_cst seq_cst
1240 %old = extractvalue { i64, i1 } %pair, 0
1244 ; Without inbounds, we can't fold a gep offset.
1246 ; CHECK-LABEL: cmpxchg_i64_with_unfolded_gep_offset:
1247 ; CHECK: i32.const $push0=, 24{{$}}
1248 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1249 ; CHECK: i64.atomic.rmw.cmpxchg $push2=, 0($pop1), $1, $2{{$}}
1250 define i64 @cmpxchg_i64_with_unfolded_gep_offset(i64* %p, i64 %exp, i64 %new) {
1251 %s = getelementptr i64, i64* %p, i32 3
1252 %pair = cmpxchg i64* %s, i64 %exp, i64 %new seq_cst seq_cst
1253 %old = extractvalue { i64, i1 } %pair, 0
1257 ;===----------------------------------------------------------------------------
1258 ; Atomic truncating & sign-extending ternary RMWs
1259 ;===----------------------------------------------------------------------------
1261 ; Fold an offset into a sign-extending rmw.
1263 ; CHECK-LABEL: cmpxchg_i8_i32_s_with_folded_offset:
1264 ; CHECK: i32.atomic.rmw8.cmpxchg_u $push0=, 24($0), $1, $2{{$}}
1265 ; CHECK-NEXT: i32.extend8_s $push1=, $pop0
1266 define i32 @cmpxchg_i8_i32_s_with_folded_offset(i8* %p, i32 %exp, i32 %new) {
1267 %q = ptrtoint i8* %p to i32
1268 %r = add nuw i32 %q, 24
1269 %s = inttoptr i32 %r to i8*
1270 %exp_t = trunc i32 %exp to i8
1271 %new_t = trunc i32 %new to i8
1272 %pair = cmpxchg i8* %s, i8 %exp_t, i8 %new_t seq_cst seq_cst
1273 %old = extractvalue { i8, i1 } %pair, 0
1274 %u = sext i8 %old to i32
1278 ; 32->64 sext rmw gets selected as i32.atomic.rmw.cmpxchg, i64.extend_i32_s
1279 ; CHECK-LABEL: cmpxchg_i32_i64_s_with_folded_offset:
1280 ; CHECK: i32.wrap_i64 $push1=, $1
1281 ; CHECK-NEXT: i32.wrap_i64 $push0=, $2
1282 ; CHECK-NEXT: i32.atomic.rmw.cmpxchg $push2=, 24($0), $pop1, $pop0{{$}}
1283 ; CHECK-NEXT: i64.extend_i32_s $push3=, $pop2{{$}}
1284 define i64 @cmpxchg_i32_i64_s_with_folded_offset(i32* %p, i64 %exp, i64 %new) {
1285 %q = ptrtoint i32* %p to i32
1286 %r = add nuw i32 %q, 24
1287 %s = inttoptr i32 %r to i32*
1288 %exp_t = trunc i64 %exp to i32
1289 %new_t = trunc i64 %new to i32
1290 %pair = cmpxchg i32* %s, i32 %exp_t, i32 %new_t seq_cst seq_cst
1291 %old = extractvalue { i32, i1 } %pair, 0
1292 %u = sext i32 %old to i64
1296 ; Fold a gep offset into a sign-extending rmw.
1298 ; CHECK-LABEL: cmpxchg_i8_i32_s_with_folded_gep_offset:
1299 ; CHECK: i32.atomic.rmw8.cmpxchg_u $push0=, 24($0), $1, $2{{$}}
1300 ; CHECK-NEXT: i32.extend8_s $push1=, $pop0
1301 define i32 @cmpxchg_i8_i32_s_with_folded_gep_offset(i8* %p, i32 %exp, i32 %new) {
1302 %s = getelementptr inbounds i8, i8* %p, i32 24
1303 %exp_t = trunc i32 %exp to i8
1304 %new_t = trunc i32 %new to i8
1305 %pair = cmpxchg i8* %s, i8 %exp_t, i8 %new_t seq_cst seq_cst
1306 %old = extractvalue { i8, i1 } %pair, 0
1307 %u = sext i8 %old to i32
1311 ; CHECK-LABEL: cmpxchg_i16_i32_s_with_folded_gep_offset:
1312 ; CHECK: i32.atomic.rmw16.cmpxchg_u $push0=, 48($0), $1, $2{{$}}
1313 ; CHECK-NEXT: i32.extend16_s $push1=, $pop0
1314 define i32 @cmpxchg_i16_i32_s_with_folded_gep_offset(i16* %p, i32 %exp, i32 %new) {
1315 %s = getelementptr inbounds i16, i16* %p, i32 24
1316 %exp_t = trunc i32 %exp to i16
1317 %new_t = trunc i32 %new to i16
1318 %pair = cmpxchg i16* %s, i16 %exp_t, i16 %new_t seq_cst seq_cst
1319 %old = extractvalue { i16, i1 } %pair, 0
1320 %u = sext i16 %old to i32
1324 ; CHECK-LABEL: cmpxchg_i16_i64_s_with_folded_gep_offset:
1325 ; CHECK: i64.atomic.rmw16.cmpxchg_u $push0=, 48($0), $1, $2{{$}}
1326 ; CHECK-NEXT: i64.extend16_s $push1=, $pop0
1327 define i64 @cmpxchg_i16_i64_s_with_folded_gep_offset(i16* %p, i64 %exp, i64 %new) {
1328 %s = getelementptr inbounds i16, i16* %p, i32 24
1329 %exp_t = trunc i64 %exp to i16
1330 %new_t = trunc i64 %new to i16
1331 %pair = cmpxchg i16* %s, i16 %exp_t, i16 %new_t seq_cst seq_cst
1332 %old = extractvalue { i16, i1 } %pair, 0
1333 %u = sext i16 %old to i64
1337 ; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as
1338 ; an 'add' if the or'ed bits are known to be zero.
1340 ; CHECK-LABEL: cmpxchg_i8_i32_s_with_folded_or_offset:
1341 ; CHECK: i32.atomic.rmw8.cmpxchg_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1, $2{{$}}
1342 ; CHECK-NEXT: i32.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}
1343 define i32 @cmpxchg_i8_i32_s_with_folded_or_offset(i32 %x, i32 %exp, i32 %new) {
1344 %and = and i32 %x, -4
1345 %t0 = inttoptr i32 %and to i8*
1346 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
1347 %exp_t = trunc i32 %exp to i8
1348 %new_t = trunc i32 %new to i8
1349 %pair = cmpxchg i8* %arrayidx, i8 %exp_t, i8 %new_t seq_cst seq_cst
1350 %old = extractvalue { i8, i1 } %pair, 0
1351 %conv = sext i8 %old to i32
1355 ; CHECK-LABEL: cmpxchg_i8_i64_s_with_folded_or_offset:
1356 ; CHECK: i64.atomic.rmw8.cmpxchg_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1, $2{{$}}
1357 ; CHECK-NEXT: i64.extend8_s $push{{[0-9]+}}=, $pop[[R1]]{{$}}
1358 define i64 @cmpxchg_i8_i64_s_with_folded_or_offset(i32 %x, i64 %exp, i64 %new) {
1359 %and = and i32 %x, -4
1360 %t0 = inttoptr i32 %and to i8*
1361 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
1362 %exp_t = trunc i64 %exp to i8
1363 %new_t = trunc i64 %new to i8
1364 %pair = cmpxchg i8* %arrayidx, i8 %exp_t, i8 %new_t seq_cst seq_cst
1365 %old = extractvalue { i8, i1 } %pair, 0
1366 %conv = sext i8 %old to i64
1370 ; When loading from a fixed address, materialize a zero.
1372 ; CHECK-LABEL: cmpxchg_i16_i32_s_from_numeric_address
1373 ; CHECK: i32.const $push0=, 0{{$}}
1374 ; CHECK: i32.atomic.rmw16.cmpxchg_u $push1=, 42($pop0), $0, $1{{$}}
1375 ; CHECK-NEXT: i32.extend16_s $push2=, $pop1
1376 define i32 @cmpxchg_i16_i32_s_from_numeric_address(i32 %exp, i32 %new) {
1377 %s = inttoptr i32 42 to i16*
1378 %exp_t = trunc i32 %exp to i16
1379 %new_t = trunc i32 %new to i16
1380 %pair = cmpxchg i16* %s, i16 %exp_t, i16 %new_t seq_cst seq_cst
1381 %old = extractvalue { i16, i1 } %pair, 0
1382 %u = sext i16 %old to i32
1386 ; CHECK-LABEL: cmpxchg_i8_i32_s_from_global_address
1387 ; CHECK: i32.const $push0=, 0{{$}}
1388 ; CHECK: i32.atomic.rmw8.cmpxchg_u $push1=, gv8($pop0), $0, $1{{$}}
1389 ; CHECK-NEXT: i32.extend8_s $push2=, $pop1{{$}}
1390 define i32 @cmpxchg_i8_i32_s_from_global_address(i32 %exp, i32 %new) {
1391 %exp_t = trunc i32 %exp to i8
1392 %new_t = trunc i32 %new to i8
1393 %pair = cmpxchg i8* @gv8, i8 %exp_t, i8 %new_t seq_cst seq_cst
1394 %old = extractvalue { i8, i1 } %pair, 0
1395 %u = sext i8 %old to i32
1399 ;===----------------------------------------------------------------------------
1400 ; Atomic truncating & zero-extending ternary RMWs
1401 ;===----------------------------------------------------------------------------
1403 ; Fold an offset into a sign-extending rmw.
1405 ; CHECK-LABEL: cmpxchg_i8_i32_z_with_folded_offset:
1406 ; CHECK: i32.atomic.rmw8.cmpxchg_u $push0=, 24($0), $1, $2{{$}}
1407 define i32 @cmpxchg_i8_i32_z_with_folded_offset(i8* %p, i32 %exp, i32 %new) {
1408 %q = ptrtoint i8* %p to i32
1409 %r = add nuw i32 %q, 24
1410 %s = inttoptr i32 %r to i8*
1411 %exp_t = trunc i32 %exp to i8
1412 %new_t = trunc i32 %new to i8
1413 %pair = cmpxchg i8* %s, i8 %exp_t, i8 %new_t seq_cst seq_cst
1414 %old = extractvalue { i8, i1 } %pair, 0
1415 %u = zext i8 %old to i32
1419 ; CHECK-LABEL: cmpxchg_i32_i64_z_with_folded_offset:
1420 ; CHECK: i64.atomic.rmw32.cmpxchg_u $push0=, 24($0), $1, $2{{$}}
1421 define i64 @cmpxchg_i32_i64_z_with_folded_offset(i32* %p, i64 %exp, i64 %new) {
1422 %q = ptrtoint i32* %p to i32
1423 %r = add nuw i32 %q, 24
1424 %s = inttoptr i32 %r to i32*
1425 %exp_t = trunc i64 %exp to i32
1426 %new_t = trunc i64 %new to i32
1427 %pair = cmpxchg i32* %s, i32 %exp_t, i32 %new_t seq_cst seq_cst
1428 %old = extractvalue { i32, i1 } %pair, 0
1429 %u = zext i32 %old to i64
1433 ; Fold a gep offset into a sign-extending rmw.
1435 ; CHECK-LABEL: cmpxchg_i8_i32_z_with_folded_gep_offset:
1436 ; CHECK: i32.atomic.rmw8.cmpxchg_u $push0=, 24($0), $1, $2{{$}}
1437 define i32 @cmpxchg_i8_i32_z_with_folded_gep_offset(i8* %p, i32 %exp, i32 %new) {
1438 %s = getelementptr inbounds i8, i8* %p, i32 24
1439 %exp_t = trunc i32 %exp to i8
1440 %new_t = trunc i32 %new to i8
1441 %pair = cmpxchg i8* %s, i8 %exp_t, i8 %new_t seq_cst seq_cst
1442 %old = extractvalue { i8, i1 } %pair, 0
1443 %u = zext i8 %old to i32
1447 ; CHECK-LABEL: cmpxchg_i16_i32_z_with_folded_gep_offset:
1448 ; CHECK: i32.atomic.rmw16.cmpxchg_u $push0=, 48($0), $1, $2{{$}}
1449 define i32 @cmpxchg_i16_i32_z_with_folded_gep_offset(i16* %p, i32 %exp, i32 %new) {
1450 %s = getelementptr inbounds i16, i16* %p, i32 24
1451 %exp_t = trunc i32 %exp to i16
1452 %new_t = trunc i32 %new to i16
1453 %pair = cmpxchg i16* %s, i16 %exp_t, i16 %new_t seq_cst seq_cst
1454 %old = extractvalue { i16, i1 } %pair, 0
1455 %u = zext i16 %old to i32
1459 ; CHECK-LABEL: cmpxchg_i16_i64_z_with_folded_gep_offset:
1460 ; CHECK: i64.atomic.rmw16.cmpxchg_u $push0=, 48($0), $1, $2{{$}}
1461 define i64 @cmpxchg_i16_i64_z_with_folded_gep_offset(i16* %p, i64 %exp, i64 %new) {
1462 %s = getelementptr inbounds i16, i16* %p, i32 24
1463 %exp_t = trunc i64 %exp to i16
1464 %new_t = trunc i64 %new to i16
1465 %pair = cmpxchg i16* %s, i16 %exp_t, i16 %new_t seq_cst seq_cst
1466 %old = extractvalue { i16, i1 } %pair, 0
1467 %u = zext i16 %old to i64
1471 ; 'add' in this code becomes 'or' after DAG optimization. Treat an 'or' node as
1472 ; an 'add' if the or'ed bits are known to be zero.
1474 ; CHECK-LABEL: cmpxchg_i8_i32_z_with_folded_or_offset:
1475 ; CHECK: i32.atomic.rmw8.cmpxchg_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1, $2{{$}}
1476 define i32 @cmpxchg_i8_i32_z_with_folded_or_offset(i32 %x, i32 %exp, i32 %new) {
1477 %and = and i32 %x, -4
1478 %t0 = inttoptr i32 %and to i8*
1479 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
1480 %exp_t = trunc i32 %exp to i8
1481 %new_t = trunc i32 %new to i8
1482 %pair = cmpxchg i8* %arrayidx, i8 %exp_t, i8 %new_t seq_cst seq_cst
1483 %old = extractvalue { i8, i1 } %pair, 0
1484 %conv = zext i8 %old to i32
1488 ; CHECK-LABEL: cmpxchg_i8_i64_z_with_folded_or_offset:
1489 ; CHECK: i64.atomic.rmw8.cmpxchg_u $push[[R1:[0-9]+]]=, 2($pop{{[0-9]+}}), $1, $2{{$}}
1490 define i64 @cmpxchg_i8_i64_z_with_folded_or_offset(i32 %x, i64 %exp, i64 %new) {
1491 %and = and i32 %x, -4
1492 %t0 = inttoptr i32 %and to i8*
1493 %arrayidx = getelementptr inbounds i8, i8* %t0, i32 2
1494 %exp_t = trunc i64 %exp to i8
1495 %new_t = trunc i64 %new to i8
1496 %pair = cmpxchg i8* %arrayidx, i8 %exp_t, i8 %new_t seq_cst seq_cst
1497 %old = extractvalue { i8, i1 } %pair, 0
1498 %conv = zext i8 %old to i64
1502 ; When loading from a fixed address, materialize a zero.
1504 ; CHECK-LABEL: cmpxchg_i16_i32_z_from_numeric_address
1505 ; CHECK: i32.const $push0=, 0{{$}}
1506 ; CHECK: i32.atomic.rmw16.cmpxchg_u $push1=, 42($pop0), $0, $1{{$}}
1507 define i32 @cmpxchg_i16_i32_z_from_numeric_address(i32 %exp, i32 %new) {
1508 %s = inttoptr i32 42 to i16*
1509 %exp_t = trunc i32 %exp to i16
1510 %new_t = trunc i32 %new to i16
1511 %pair = cmpxchg i16* %s, i16 %exp_t, i16 %new_t seq_cst seq_cst
1512 %old = extractvalue { i16, i1 } %pair, 0
1513 %u = zext i16 %old to i32
1517 ; CHECK-LABEL: cmpxchg_i8_i32_z_from_global_address
1518 ; CHECK: i32.const $push0=, 0{{$}}
1519 ; CHECK: i32.atomic.rmw8.cmpxchg_u $push1=, gv8($pop0), $0, $1{{$}}
1520 define i32 @cmpxchg_i8_i32_z_from_global_address(i32 %exp, i32 %new) {
1521 %exp_t = trunc i32 %exp to i8
1522 %new_t = trunc i32 %new to i8
1523 %pair = cmpxchg i8* @gv8, i8 %exp_t, i8 %new_t seq_cst seq_cst
1524 %old = extractvalue { i8, i1 } %pair, 0
1525 %u = zext i8 %old to i32
1529 ;===----------------------------------------------------------------------------
1531 ;===----------------------------------------------------------------------------
1533 declare i32 @llvm.wasm.atomic.wait.i32(i32*, i32, i64)
1537 ; CHECK-LABEL: wait_i32_no_offset:
1538 ; CHECK: i32.atomic.wait $push0=, 0($0), $1, $2{{$}}
1539 ; CHECK-NEXT: return $pop0{{$}}
1540 define i32 @wait_i32_no_offset(i32* %p, i32 %exp, i64 %timeout) {
1541 %v = call i32 @llvm.wasm.atomic.wait.i32(i32* %p, i32 %exp, i64 %timeout)
1545 ; With an nuw add, we can fold an offset.
1547 ; CHECK-LABEL: wait_i32_with_folded_offset:
1548 ; CHECK: i32.atomic.wait $push0=, 24($0), $1, $2{{$}}
1549 define i32 @wait_i32_with_folded_offset(i32* %p, i32 %exp, i64 %timeout) {
1550 %q = ptrtoint i32* %p to i32
1551 %r = add nuw i32 %q, 24
1552 %s = inttoptr i32 %r to i32*
1553 %t = call i32 @llvm.wasm.atomic.wait.i32(i32* %s, i32 %exp, i64 %timeout)
1557 ; With an inbounds gep, we can fold an offset.
1559 ; CHECK-LABEL: wait_i32_with_folded_gep_offset:
1560 ; CHECK: i32.atomic.wait $push0=, 24($0), $1, $2{{$}}
1561 define i32 @wait_i32_with_folded_gep_offset(i32* %p, i32 %exp, i64 %timeout) {
1562 %s = getelementptr inbounds i32, i32* %p, i32 6
1563 %t = call i32 @llvm.wasm.atomic.wait.i32(i32* %s, i32 %exp, i64 %timeout)
1567 ; We can't fold a negative offset though, even with an inbounds gep.
1569 ; CHECK-LABEL: wait_i32_with_unfolded_gep_negative_offset:
1570 ; CHECK: i32.const $push0=, -24{{$}}
1571 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1572 ; CHECK: i32.atomic.wait $push2=, 0($pop1), $1, $2{{$}}
1573 define i32 @wait_i32_with_unfolded_gep_negative_offset(i32* %p, i32 %exp, i64 %timeout) {
1574 %s = getelementptr inbounds i32, i32* %p, i32 -6
1575 %t = call i32 @llvm.wasm.atomic.wait.i32(i32* %s, i32 %exp, i64 %timeout)
1579 ; Without nuw, and even with nsw, we can't fold an offset.
1581 ; CHECK-LABEL: wait_i32_with_unfolded_offset:
1582 ; CHECK: i32.const $push0=, 24{{$}}
1583 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1584 ; CHECK: i32.atomic.wait $push2=, 0($pop1), $1, $2{{$}}
1585 define i32 @wait_i32_with_unfolded_offset(i32* %p, i32 %exp, i64 %timeout) {
1586 %q = ptrtoint i32* %p to i32
1587 %r = add nsw i32 %q, 24
1588 %s = inttoptr i32 %r to i32*
1589 %t = call i32 @llvm.wasm.atomic.wait.i32(i32* %s, i32 %exp, i64 %timeout)
1593 ; Without inbounds, we can't fold a gep offset.
1595 ; CHECK-LABEL: wait_i32_with_unfolded_gep_offset:
1596 ; CHECK: i32.const $push0=, 24{{$}}
1597 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1598 ; CHECK: i32.atomic.wait $push2=, 0($pop1), $1, $2{{$}}
1599 define i32 @wait_i32_with_unfolded_gep_offset(i32* %p, i32 %exp, i64 %timeout) {
1600 %s = getelementptr i32, i32* %p, i32 6
1601 %t = call i32 @llvm.wasm.atomic.wait.i32(i32* %s, i32 %exp, i64 %timeout)
1605 ; When waiting from a fixed address, materialize a zero.
1607 ; CHECK-LABEL: wait_i32_from_numeric_address
1608 ; CHECK: i32.const $push0=, 0{{$}}
1609 ; CHECK: i32.atomic.wait $push1=, 42($pop0), $0, $1{{$}}
1610 define i32 @wait_i32_from_numeric_address(i32 %exp, i64 %timeout) {
1611 %s = inttoptr i32 42 to i32*
1612 %t = call i32 @llvm.wasm.atomic.wait.i32(i32* %s, i32 %exp, i64 %timeout)
1616 ; CHECK-LABEL: wait_i32_from_global_address
1617 ; CHECK: i32.const $push0=, 0{{$}}
1618 ; CHECK: i32.atomic.wait $push1=, gv($pop0), $0, $1{{$}}
1619 define i32 @wait_i32_from_global_address(i32 %exp, i64 %timeout) {
1620 %t = call i32 @llvm.wasm.atomic.wait.i32(i32* @gv, i32 %exp, i64 %timeout)
1624 ;===----------------------------------------------------------------------------
1626 ;===----------------------------------------------------------------------------
1628 declare i32 @llvm.wasm.atomic.wait.i64(i64*, i64, i64)
1632 ; CHECK-LABEL: wait_i64_no_offset:
1633 ; CHECK: i64.atomic.wait $push0=, 0($0), $1, $2{{$}}
1634 ; CHECK-NEXT: return $pop0{{$}}
1635 define i32 @wait_i64_no_offset(i64* %p, i64 %exp, i64 %timeout) {
1636 %v = call i32 @llvm.wasm.atomic.wait.i64(i64* %p, i64 %exp, i64 %timeout)
1640 ; With an nuw add, we can fold an offset.
1642 ; CHECK-LABEL: wait_i64_with_folded_offset:
1643 ; CHECK: i64.atomic.wait $push0=, 24($0), $1, $2{{$}}
1644 define i32 @wait_i64_with_folded_offset(i64* %p, i64 %exp, i64 %timeout) {
1645 %q = ptrtoint i64* %p to i32
1646 %r = add nuw i32 %q, 24
1647 %s = inttoptr i32 %r to i64*
1648 %t = call i32 @llvm.wasm.atomic.wait.i64(i64* %s, i64 %exp, i64 %timeout)
1652 ; With an inbounds gep, we can fold an offset.
1654 ; CHECK-LABEL: wait_i64_with_folded_gep_offset:
1655 ; CHECK: i64.atomic.wait $push0=, 24($0), $1, $2{{$}}
1656 define i32 @wait_i64_with_folded_gep_offset(i64* %p, i64 %exp, i64 %timeout) {
1657 %s = getelementptr inbounds i64, i64* %p, i32 3
1658 %t = call i32 @llvm.wasm.atomic.wait.i64(i64* %s, i64 %exp, i64 %timeout)
1662 ; We can't fold a negative offset though, even with an inbounds gep.
1664 ; CHECK-LABEL: wait_i64_with_unfolded_gep_negative_offset:
1665 ; CHECK: i32.const $push0=, -24{{$}}
1666 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1667 ; CHECK: i64.atomic.wait $push2=, 0($pop1), $1, $2{{$}}
1668 define i32 @wait_i64_with_unfolded_gep_negative_offset(i64* %p, i64 %exp, i64 %timeout) {
1669 %s = getelementptr inbounds i64, i64* %p, i32 -3
1670 %t = call i32 @llvm.wasm.atomic.wait.i64(i64* %s, i64 %exp, i64 %timeout)
1674 ; Without nuw, and even with nsw, we can't fold an offset.
1676 ; CHECK-LABEL: wait_i64_with_unfolded_offset:
1677 ; CHECK: i32.const $push0=, 24{{$}}
1678 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1679 ; CHECK: i64.atomic.wait $push2=, 0($pop1), $1, $2{{$}}
1680 define i32 @wait_i64_with_unfolded_offset(i64* %p, i64 %exp, i64 %timeout) {
1681 %q = ptrtoint i64* %p to i32
1682 %r = add nsw i32 %q, 24
1683 %s = inttoptr i32 %r to i64*
1684 %t = call i32 @llvm.wasm.atomic.wait.i64(i64* %s, i64 %exp, i64 %timeout)
1688 ; Without inbounds, we can't fold a gep offset.
1690 ; CHECK-LABEL: wait_i64_with_unfolded_gep_offset:
1691 ; CHECK: i32.const $push0=, 24{{$}}
1692 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1693 ; CHECK: i64.atomic.wait $push2=, 0($pop1), $1, $2{{$}}
1694 define i32 @wait_i64_with_unfolded_gep_offset(i64* %p, i64 %exp, i64 %timeout) {
1695 %s = getelementptr i64, i64* %p, i32 3
1696 %t = call i32 @llvm.wasm.atomic.wait.i64(i64* %s, i64 %exp, i64 %timeout)
1700 ;===----------------------------------------------------------------------------
1702 ;===----------------------------------------------------------------------------
1704 declare i32 @llvm.wasm.atomic.notify(i32*, i32)
1708 ; CHECK-LABEL: notify_no_offset:
1709 ; CHECK: atomic.notify $push0=, 0($0), $1{{$}}
1710 ; CHECK-NEXT: return $pop0{{$}}
1711 define i32 @notify_no_offset(i32* %p, i32 %notify_count) {
1712 %v = call i32 @llvm.wasm.atomic.notify(i32* %p, i32 %notify_count)
1716 ; With an nuw add, we can fold an offset.
1718 ; CHECK-LABEL: notify_with_folded_offset:
1719 ; CHECK: atomic.notify $push0=, 24($0), $1{{$}}
1720 define i32 @notify_with_folded_offset(i32* %p, i32 %notify_count) {
1721 %q = ptrtoint i32* %p to i32
1722 %r = add nuw i32 %q, 24
1723 %s = inttoptr i32 %r to i32*
1724 %t = call i32 @llvm.wasm.atomic.notify(i32* %s, i32 %notify_count)
1728 ; With an inbounds gep, we can fold an offset.
1730 ; CHECK-LABEL: notify_with_folded_gep_offset:
1731 ; CHECK: atomic.notify $push0=, 24($0), $1{{$}}
1732 define i32 @notify_with_folded_gep_offset(i32* %p, i32 %notify_count) {
1733 %s = getelementptr inbounds i32, i32* %p, i32 6
1734 %t = call i32 @llvm.wasm.atomic.notify(i32* %s, i32 %notify_count)
1738 ; We can't fold a negative offset though, even with an inbounds gep.
1740 ; CHECK-LABEL: notify_with_unfolded_gep_negative_offset:
1741 ; CHECK: i32.const $push0=, -24{{$}}
1742 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1743 ; CHECK: atomic.notify $push2=, 0($pop1), $1{{$}}
1744 define i32 @notify_with_unfolded_gep_negative_offset(i32* %p, i32 %notify_count) {
1745 %s = getelementptr inbounds i32, i32* %p, i32 -6
1746 %t = call i32 @llvm.wasm.atomic.notify(i32* %s, i32 %notify_count)
1750 ; Without nuw, and even with nsw, we can't fold an offset.
1752 ; CHECK-LABEL: notify_with_unfolded_offset:
1753 ; CHECK: i32.const $push0=, 24{{$}}
1754 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1755 ; CHECK: atomic.notify $push2=, 0($pop1), $1{{$}}
1756 define i32 @notify_with_unfolded_offset(i32* %p, i32 %notify_count) {
1757 %q = ptrtoint i32* %p to i32
1758 %r = add nsw i32 %q, 24
1759 %s = inttoptr i32 %r to i32*
1760 %t = call i32 @llvm.wasm.atomic.notify(i32* %s, i32 %notify_count)
1764 ; Without inbounds, we can't fold a gep offset.
1766 ; CHECK-LABEL: notify_with_unfolded_gep_offset:
1767 ; CHECK: i32.const $push0=, 24{{$}}
1768 ; CHECK: i32.add $push1=, $0, $pop0{{$}}
1769 ; CHECK: atomic.notify $push2=, 0($pop1), $1{{$}}
1770 define i32 @notify_with_unfolded_gep_offset(i32* %p, i32 %notify_count) {
1771 %s = getelementptr i32, i32* %p, i32 6
1772 %t = call i32 @llvm.wasm.atomic.notify(i32* %s, i32 %notify_count)
1776 ; When notifying from a fixed address, materialize a zero.
1778 ; CHECK-LABEL: notify_from_numeric_address
1779 ; CHECK: i32.const $push0=, 0{{$}}
1780 ; CHECK: atomic.notify $push1=, 42($pop0), $0{{$}}
1781 define i32 @notify_from_numeric_address(i32 %notify_count) {
1782 %s = inttoptr i32 42 to i32*
1783 %t = call i32 @llvm.wasm.atomic.notify(i32* %s, i32 %notify_count)
1787 ; CHECK-LABEL: notify_from_global_address
1788 ; CHECK: i32.const $push0=, 0{{$}}
1789 ; CHECK: atomic.notify $push1=, gv($pop0), $0{{$}}
1790 define i32 @notify_from_global_address(i32 %notify_count) {
1791 %t = call i32 @llvm.wasm.atomic.notify(i32* @gv, i32 %notify_count)