xref: /llvm-project/llvm/test/CodeGen/WebAssembly/atomic-rmw.ll (revision 73856247eef35f5336e485dc009842a5b991c421)
1; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers
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
3
4; Test atomic RMW (read-modify-write) instructions are assembled properly.
5
6target triple = "wasm32-unknown-unknown"
7
8;===----------------------------------------------------------------------------
9; Atomic read-modify-writes: 32-bit
10;===----------------------------------------------------------------------------
11
12; CHECK-LABEL: add_i32:
13; CHECK-NEXT: .functype add_i32 (i32, i32) -> (i32){{$}}
14; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
15; CHECK-NEXT: return $pop0{{$}}
16define i32 @add_i32(ptr %p, i32 %v) {
17  %old = atomicrmw add ptr %p, i32 %v seq_cst
18  ret i32 %old
19}
20
21; CHECK-LABEL: sub_i32:
22; CHECK-NEXT: .functype sub_i32 (i32, i32) -> (i32){{$}}
23; CHECK: i32.atomic.rmw.sub $push0=, 0($0), $1{{$}}
24; CHECK-NEXT: return $pop0{{$}}
25define i32 @sub_i32(ptr %p, i32 %v) {
26  %old = atomicrmw sub ptr %p, i32 %v seq_cst
27  ret i32 %old
28}
29
30; CHECK-LABEL: and_i32:
31; CHECK-NEXT: .functype and_i32 (i32, i32) -> (i32){{$}}
32; CHECK: i32.atomic.rmw.and $push0=, 0($0), $1{{$}}
33; CHECK-NEXT: return $pop0{{$}}
34define i32 @and_i32(ptr %p, i32 %v) {
35  %old = atomicrmw and ptr %p, i32 %v seq_cst
36  ret i32 %old
37}
38
39; CHECK-LABEL: or_i32:
40; CHECK-NEXT: .functype or_i32 (i32, i32) -> (i32){{$}}
41; CHECK: i32.atomic.rmw.or $push0=, 0($0), $1{{$}}
42; CHECK-NEXT: return $pop0{{$}}
43define i32 @or_i32(ptr %p, i32 %v) {
44  %old = atomicrmw or ptr %p, i32 %v seq_cst
45  ret i32 %old
46}
47
48; CHECK-LABEL: xor_i32:
49; CHECK-NEXT: .functype xor_i32 (i32, i32) -> (i32){{$}}
50; CHECK: i32.atomic.rmw.xor $push0=, 0($0), $1{{$}}
51; CHECK-NEXT: return $pop0{{$}}
52define i32 @xor_i32(ptr %p, i32 %v) {
53  %old = atomicrmw xor ptr %p, i32 %v seq_cst
54  ret i32 %old
55}
56
57; CHECK-LABEL: xchg_i32:
58; CHECK-NEXT: .functype xchg_i32 (i32, i32) -> (i32){{$}}
59; CHECK: i32.atomic.rmw.xchg $push0=, 0($0), $1{{$}}
60; CHECK-NEXT: return $pop0{{$}}
61define i32 @xchg_i32(ptr %p, i32 %v) {
62  %old = atomicrmw xchg ptr %p, i32 %v seq_cst
63  ret i32 %old
64}
65
66; CHECK-LABEL: cmpxchg_i32_loaded_value:
67; CHECK-NEXT: .functype cmpxchg_i32_loaded_value (i32, i32, i32) -> (i32){{$}}
68; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
69; CHECK-NEXT: return $pop0{{$}}
70define i32 @cmpxchg_i32_loaded_value(ptr %p, i32 %exp, i32 %new) {
71  %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst
72  %old = extractvalue { i32, i1 } %pair, 0
73  ret i32 %old
74}
75
76; CHECK-LABEL: cmpxchg_i32_success:
77; CHECK-NEXT: .functype cmpxchg_i32_success (i32, i32, i32) -> (i32){{$}}
78; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
79; CHECK-NEXT: i32.eq $push1=, $pop0, $1{{$}}
80; CHECK-NEXT: return $pop1{{$}}
81define i1 @cmpxchg_i32_success(ptr %p, i32 %exp, i32 %new) {
82  %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst
83  %succ = extractvalue { i32, i1 } %pair, 1
84  ret i1 %succ
85}
86
87; Unsupported instructions are expanded using cmpxchg with a loop.
88
89; CHECK-LABEL: nand_i32:
90; CHECK: loop
91; CHECK: i32.atomic.rmw.cmpxchg
92; CHECK: br_if 0
93; CHECK: end_loop
94define i32 @nand_i32(ptr %p, i32 %v) {
95  %old = atomicrmw nand ptr %p, i32 %v seq_cst
96  ret i32 %old
97}
98
99; CHECK-LABEL: max_i32:
100; CHECK: loop
101; CHECK: i32.atomic.rmw.cmpxchg
102; CHECK: br_if 0
103; CHECK: end_loop
104define i32 @max_i32(ptr %p, i32 %v) {
105  %old = atomicrmw max ptr %p, i32 %v seq_cst
106  ret i32 %old
107}
108
109; CHECK-LABEL: min_i32:
110; CHECK: loop
111; CHECK: i32.atomic.rmw.cmpxchg
112; CHECK: br_if 0
113; CHECK: end_loop
114define i32 @min_i32(ptr %p, i32 %v) {
115  %old = atomicrmw min ptr %p, i32 %v seq_cst
116  ret i32 %old
117}
118
119; CHECK-LABEL: umax_i32:
120; CHECK: loop
121; CHECK: i32.atomic.rmw.cmpxchg
122; CHECK: br_if 0
123; CHECK: end_loop
124define i32 @umax_i32(ptr %p, i32 %v) {
125  %old = atomicrmw umax ptr %p, i32 %v seq_cst
126  ret i32 %old
127}
128
129; CHECK-LABEL: umin_i32:
130; CHECK: loop
131; CHECK: i32.atomic.rmw.cmpxchg
132; CHECK: br_if 0
133; CHECK: end_loop
134define i32 @umin_i32(ptr %p, i32 %v) {
135  %old = atomicrmw umin ptr %p, i32 %v seq_cst
136  ret i32 %old
137}
138
139;===----------------------------------------------------------------------------
140; Atomic read-modify-writes: 64-bit
141;===----------------------------------------------------------------------------
142
143; CHECK-LABEL: add_i64:
144; CHECK-NEXT: .functype add_i64 (i32, i64) -> (i64){{$}}
145; CHECK: i64.atomic.rmw.add $push0=, 0($0), $1{{$}}
146; CHECK-NEXT: return $pop0{{$}}
147define i64 @add_i64(ptr %p, i64 %v) {
148  %old = atomicrmw add ptr %p, i64 %v seq_cst
149  ret i64 %old
150}
151
152; CHECK-LABEL: sub_i64:
153; CHECK-NEXT: .functype sub_i64 (i32, i64) -> (i64){{$}}
154; CHECK: i64.atomic.rmw.sub $push0=, 0($0), $1{{$}}
155; CHECK-NEXT: return $pop0{{$}}
156define i64 @sub_i64(ptr %p, i64 %v) {
157  %old = atomicrmw sub ptr %p, i64 %v seq_cst
158  ret i64 %old
159}
160
161; CHECK-LABEL: and_i64:
162; CHECK-NEXT: .functype and_i64 (i32, i64) -> (i64){{$}}
163; CHECK: i64.atomic.rmw.and $push0=, 0($0), $1{{$}}
164; CHECK-NEXT: return $pop0{{$}}
165define i64 @and_i64(ptr %p, i64 %v) {
166  %old = atomicrmw and ptr %p, i64 %v seq_cst
167  ret i64 %old
168}
169
170; CHECK-LABEL: or_i64:
171; CHECK-NEXT: .functype or_i64 (i32, i64) -> (i64){{$}}
172; CHECK: i64.atomic.rmw.or $push0=, 0($0), $1{{$}}
173; CHECK-NEXT: return $pop0{{$}}
174define i64 @or_i64(ptr %p, i64 %v) {
175  %old = atomicrmw or ptr %p, i64 %v seq_cst
176  ret i64 %old
177}
178
179; CHECK-LABEL: xor_i64:
180; CHECK-NEXT: .functype xor_i64 (i32, i64) -> (i64){{$}}
181; CHECK: i64.atomic.rmw.xor $push0=, 0($0), $1{{$}}
182; CHECK-NEXT: return $pop0{{$}}
183define i64 @xor_i64(ptr %p, i64 %v) {
184  %old = atomicrmw xor ptr %p, i64 %v seq_cst
185  ret i64 %old
186}
187
188; CHECK-LABEL: xchg_i64:
189; CHECK-NEXT: .functype xchg_i64 (i32, i64) -> (i64){{$}}
190; CHECK: i64.atomic.rmw.xchg $push0=, 0($0), $1{{$}}
191; CHECK-NEXT: return $pop0{{$}}
192define i64 @xchg_i64(ptr %p, i64 %v) {
193  %old = atomicrmw xchg ptr %p, i64 %v seq_cst
194  ret i64 %old
195}
196
197; CHECK-LABEL: cmpxchg_i64_loaded_value:
198; CHECK-NEXT: .functype cmpxchg_i64_loaded_value (i32, i64, i64) -> (i64){{$}}
199; CHECK: i64.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
200; CHECK-NEXT: return $pop0{{$}}
201define i64 @cmpxchg_i64_loaded_value(ptr %p, i64 %exp, i64 %new) {
202  %pair = cmpxchg ptr %p, i64 %exp, i64 %new seq_cst seq_cst
203  %old = extractvalue { i64, i1 } %pair, 0
204  ret i64 %old
205}
206
207; CHECK-LABEL: cmpxchg_i64_success:
208; CHECK-NEXT: .functype cmpxchg_i64_success (i32, i64, i64) -> (i32){{$}}
209; CHECK: i64.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
210; CHECK-NEXT: i64.eq $push1=, $pop0, $1{{$}}
211; CHECK-NEXT: return $pop1{{$}}
212define i1 @cmpxchg_i64_success(ptr %p, i64 %exp, i64 %new) {
213  %pair = cmpxchg ptr %p, i64 %exp, i64 %new seq_cst seq_cst
214  %succ = extractvalue { i64, i1 } %pair, 1
215  ret i1 %succ
216}
217
218; Unsupported instructions are expanded using cmpxchg with a loop.
219
220; CHECK-LABEL: nand_i64:
221; CHECK: loop
222; CHECK: i64.atomic.rmw.cmpxchg
223; CHECK: br_if 0
224; CHECK: end_loop
225define i64 @nand_i64(ptr %p, i64 %v) {
226  %old = atomicrmw nand ptr %p, i64 %v seq_cst
227  ret i64 %old
228}
229
230; CHECK-LABEL: max_i64:
231; CHECK: loop
232; CHECK: i64.atomic.rmw.cmpxchg
233; CHECK: br_if 0
234; CHECK: end_loop
235define i64 @max_i64(ptr %p, i64 %v) {
236  %old = atomicrmw max ptr %p, i64 %v seq_cst
237  ret i64 %old
238}
239
240; CHECK-LABEL: min_i64:
241; CHECK: loop
242; CHECK: i64.atomic.rmw.cmpxchg
243; CHECK: br_if 0
244; CHECK: end_loop
245define i64 @min_i64(ptr %p, i64 %v) {
246  %old = atomicrmw min ptr %p, i64 %v seq_cst
247  ret i64 %old
248}
249
250; CHECK-LABEL: umax_i64:
251; CHECK: loop
252; CHECK: i64.atomic.rmw.cmpxchg
253; CHECK: br_if 0
254; CHECK: end_loop
255define i64 @umax_i64(ptr %p, i64 %v) {
256  %old = atomicrmw umax ptr %p, i64 %v seq_cst
257  ret i64 %old
258}
259
260; CHECK-LABEL: umin_i64:
261; CHECK: loop
262; CHECK: i64.atomic.rmw.cmpxchg
263; CHECK: br_if 0
264; CHECK: end_loop
265define i64 @umin_i64(ptr %p, i64 %v) {
266  %old = atomicrmw umin ptr %p, i64 %v seq_cst
267  ret i64 %old
268}
269
270;===----------------------------------------------------------------------------
271; Atomic truncating & sign-extending RMWs
272;===----------------------------------------------------------------------------
273
274; add
275
276; CHECK-LABEL: add_sext_i8_i32:
277; CHECK-NEXT: .functype add_sext_i8_i32 (i32, i32) -> (i32){{$}}
278; CHECK: i32.atomic.rmw8.add_u $push0=, 0($0), $1{{$}}
279; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}}
280; CHECK-NEXT: return $pop1{{$}}
281define i32 @add_sext_i8_i32(ptr %p, i32 %v) {
282  %t = trunc i32 %v to i8
283  %old = atomicrmw add ptr %p, i8 %t seq_cst
284  %e = sext i8 %old to i32
285  ret i32 %e
286}
287
288; CHECK-LABEL: add_sext_i16_i32:
289; CHECK-NEXT: .functype add_sext_i16_i32 (i32, i32) -> (i32){{$}}
290; CHECK: i32.atomic.rmw16.add_u $push0=, 0($0), $1{{$}}
291; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}}
292; CHECK-NEXT: return $pop1{{$}}
293define i32 @add_sext_i16_i32(ptr %p, i32 %v) {
294  %t = trunc i32 %v to i16
295  %old = atomicrmw add ptr %p, i16 %t seq_cst
296  %e = sext i16 %old to i32
297  ret i32 %e
298}
299
300; CHECK-LABEL: add_sext_i8_i64:
301; CHECK-NEXT: .functype add_sext_i8_i64 (i32, i64) -> (i64){{$}}
302; CHECK: i64.atomic.rmw8.add_u $push0=, 0($0), $1{{$}}
303; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}}
304; CHECK-NEXT: return $pop1{{$}}
305define i64 @add_sext_i8_i64(ptr %p, i64 %v) {
306  %t = trunc i64 %v to i8
307  %old = atomicrmw add ptr %p, i8 %t seq_cst
308  %e = sext i8 %old to i64
309  ret i64 %e
310}
311
312; CHECK-LABEL: add_sext_i16_i64:
313; CHECK-NEXT: .functype add_sext_i16_i64 (i32, i64) -> (i64){{$}}
314; CHECK: i64.atomic.rmw16.add_u $push0=, 0($0), $1{{$}}
315; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}}
316; CHECK-NEXT: return $pop1{{$}}
317define i64 @add_sext_i16_i64(ptr %p, i64 %v) {
318  %t = trunc i64 %v to i16
319  %old = atomicrmw add ptr %p, i16 %t seq_cst
320  %e = sext i16 %old to i64
321  ret i64 %e
322}
323
324; 32->64 sext rmw gets selected as i32.atomic.rmw.add, i64.extend_i32_s
325; CHECK-LABEL: add_sext_i32_i64:
326; CHECK-NEXT: .functype add_sext_i32_i64 (i32, i64) -> (i64){{$}}
327; CHECK: i32.wrap_i64 $push0=, $1{{$}}
328; CHECK: i32.atomic.rmw.add $push1=, 0($0), $pop0{{$}}
329; CHECK-NEXT: i64.extend_i32_s $push2=, $pop1{{$}}
330; CHECK-NEXT: return $pop2{{$}}
331define i64 @add_sext_i32_i64(ptr %p, i64 %v) {
332  %t = trunc i64 %v to i32
333  %old = atomicrmw add ptr %p, i32 %t seq_cst
334  %e = sext i32 %old to i64
335  ret i64 %e
336}
337
338; sub
339
340; CHECK-LABEL: sub_sext_i8_i32:
341; CHECK-NEXT: .functype sub_sext_i8_i32 (i32, i32) -> (i32){{$}}
342; CHECK: i32.atomic.rmw8.sub_u $push0=, 0($0), $1{{$}}
343; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}}
344; CHECK-NEXT: return $pop1{{$}}
345define i32 @sub_sext_i8_i32(ptr %p, i32 %v) {
346  %t = trunc i32 %v to i8
347  %old = atomicrmw sub ptr %p, i8 %t seq_cst
348  %e = sext i8 %old to i32
349  ret i32 %e
350}
351
352; CHECK-LABEL: sub_sext_i16_i32:
353; CHECK-NEXT: .functype sub_sext_i16_i32 (i32, i32) -> (i32){{$}}
354; CHECK: i32.atomic.rmw16.sub_u $push0=, 0($0), $1{{$}}
355; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}}
356; CHECK-NEXT: return $pop1{{$}}
357define i32 @sub_sext_i16_i32(ptr %p, i32 %v) {
358  %t = trunc i32 %v to i16
359  %old = atomicrmw sub ptr %p, i16 %t seq_cst
360  %e = sext i16 %old to i32
361  ret i32 %e
362}
363
364; CHECK-LABEL: sub_sext_i8_i64:
365; CHECK-NEXT: .functype sub_sext_i8_i64 (i32, i64) -> (i64){{$}}
366; CHECK: i64.atomic.rmw8.sub_u $push0=, 0($0), $1{{$}}
367; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}}
368; CHECK-NEXT: return $pop1{{$}}
369define i64 @sub_sext_i8_i64(ptr %p, i64 %v) {
370  %t = trunc i64 %v to i8
371  %old = atomicrmw sub ptr %p, i8 %t seq_cst
372  %e = sext i8 %old to i64
373  ret i64 %e
374}
375
376; CHECK-LABEL: sub_sext_i16_i64:
377; CHECK-NEXT: .functype sub_sext_i16_i64 (i32, i64) -> (i64){{$}}
378; CHECK: i64.atomic.rmw16.sub_u $push0=, 0($0), $1{{$}}
379; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}}
380; CHECK-NEXT: return $pop1{{$}}
381define i64 @sub_sext_i16_i64(ptr %p, i64 %v) {
382  %t = trunc i64 %v to i16
383  %old = atomicrmw sub ptr %p, i16 %t seq_cst
384  %e = sext i16 %old to i64
385  ret i64 %e
386}
387
388; 32->64 sext rmw gets selected as i32.atomic.rmw.sub, i64.extend_i32_s
389; CHECK-LABEL: sub_sext_i32_i64:
390; CHECK-NEXT: .functype sub_sext_i32_i64 (i32, i64) -> (i64){{$}}
391; CHECK: i32.wrap_i64 $push0=, $1
392; CHECK: i32.atomic.rmw.sub $push1=, 0($0), $pop0{{$}}
393; CHECK-NEXT: i64.extend_i32_s $push2=, $pop1{{$}}
394; CHECK-NEXT: return $pop2{{$}}
395define i64 @sub_sext_i32_i64(ptr %p, i64 %v) {
396  %t = trunc i64 %v to i32
397  %old = atomicrmw sub ptr %p, i32 %t seq_cst
398  %e = sext i32 %old to i64
399  ret i64 %e
400}
401
402; and
403
404; CHECK-LABEL: and_sext_i8_i32:
405; CHECK-NEXT: .functype and_sext_i8_i32 (i32, i32) -> (i32){{$}}
406; CHECK: i32.atomic.rmw8.and_u $push0=, 0($0), $1{{$}}
407; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}}
408; CHECK-NEXT: return $pop1{{$}}
409define i32 @and_sext_i8_i32(ptr %p, i32 %v) {
410  %t = trunc i32 %v to i8
411  %old = atomicrmw and ptr %p, i8 %t seq_cst
412  %e = sext i8 %old to i32
413  ret i32 %e
414}
415
416; CHECK-LABEL: and_sext_i16_i32:
417; CHECK-NEXT: .functype and_sext_i16_i32 (i32, i32) -> (i32){{$}}
418; CHECK: i32.atomic.rmw16.and_u $push0=, 0($0), $1{{$}}
419; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}}
420; CHECK-NEXT: return $pop1{{$}}
421define i32 @and_sext_i16_i32(ptr %p, i32 %v) {
422  %t = trunc i32 %v to i16
423  %old = atomicrmw and ptr %p, i16 %t seq_cst
424  %e = sext i16 %old to i32
425  ret i32 %e
426}
427
428; CHECK-LABEL: and_sext_i8_i64:
429; CHECK-NEXT: .functype and_sext_i8_i64 (i32, i64) -> (i64){{$}}
430; CHECK: i64.atomic.rmw8.and_u $push0=, 0($0), $1{{$}}
431; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}}
432; CHECK-NEXT: return $pop1{{$}}
433define i64 @and_sext_i8_i64(ptr %p, i64 %v) {
434  %t = trunc i64 %v to i8
435  %old = atomicrmw and ptr %p, i8 %t seq_cst
436  %e = sext i8 %old to i64
437  ret i64 %e
438}
439
440; CHECK-LABEL: and_sext_i16_i64:
441; CHECK-NEXT: .functype and_sext_i16_i64 (i32, i64) -> (i64){{$}}
442; CHECK: i64.atomic.rmw16.and_u $push0=, 0($0), $1{{$}}
443; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}}
444; CHECK-NEXT: return $pop1{{$}}
445define i64 @and_sext_i16_i64(ptr %p, i64 %v) {
446  %t = trunc i64 %v to i16
447  %old = atomicrmw and ptr %p, i16 %t seq_cst
448  %e = sext i16 %old to i64
449  ret i64 %e
450}
451
452; 32->64 sext rmw gets selected as i32.atomic.rmw.and, i64.extend_i32_s
453; CHECK-LABEL: and_sext_i32_i64:
454; CHECK-NEXT: .functype and_sext_i32_i64 (i32, i64) -> (i64){{$}}
455; CHECK: i32.wrap_i64 $push0=, $1{{$}}
456; CHECK: i32.atomic.rmw.and $push1=, 0($0), $pop0{{$}}
457; CHECK-NEXT: i64.extend_i32_s $push2=, $pop1{{$}}
458; CHECK-NEXT: return $pop2{{$}}
459define i64 @and_sext_i32_i64(ptr %p, i64 %v) {
460  %t = trunc i64 %v to i32
461  %old = atomicrmw and ptr %p, i32 %t seq_cst
462  %e = sext i32 %old to i64
463  ret i64 %e
464}
465
466; or
467
468; CHECK-LABEL: or_sext_i8_i32:
469; CHECK-NEXT: .functype or_sext_i8_i32 (i32, i32) -> (i32){{$}}
470; CHECK: i32.atomic.rmw8.or_u $push0=, 0($0), $1{{$}}
471; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}}
472; CHECK-NEXT: return $pop1{{$}}
473define i32 @or_sext_i8_i32(ptr %p, i32 %v) {
474  %t = trunc i32 %v to i8
475  %old = atomicrmw or ptr %p, i8 %t seq_cst
476  %e = sext i8 %old to i32
477  ret i32 %e
478}
479
480; CHECK-LABEL: or_sext_i16_i32:
481; CHECK-NEXT: .functype or_sext_i16_i32 (i32, i32) -> (i32){{$}}
482; CHECK: i32.atomic.rmw16.or_u $push0=, 0($0), $1{{$}}
483; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}}
484; CHECK-NEXT: return $pop1{{$}}
485define i32 @or_sext_i16_i32(ptr %p, i32 %v) {
486  %t = trunc i32 %v to i16
487  %old = atomicrmw or ptr %p, i16 %t seq_cst
488  %e = sext i16 %old to i32
489  ret i32 %e
490}
491
492; CHECK-LABEL: or_sext_i8_i64:
493; CHECK-NEXT: .functype or_sext_i8_i64 (i32, i64) -> (i64){{$}}
494; CHECK: i64.atomic.rmw8.or_u $push0=, 0($0), $1{{$}}
495; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}}
496; CHECK-NEXT: return $pop1{{$}}
497define i64 @or_sext_i8_i64(ptr %p, i64 %v) {
498  %t = trunc i64 %v to i8
499  %old = atomicrmw or ptr %p, i8 %t seq_cst
500  %e = sext i8 %old to i64
501  ret i64 %e
502}
503
504; CHECK-LABEL: or_sext_i16_i64:
505; CHECK-NEXT: .functype or_sext_i16_i64 (i32, i64) -> (i64){{$}}
506; CHECK: i64.atomic.rmw16.or_u $push0=, 0($0), $1{{$}}
507; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}}
508; CHECK-NEXT: return $pop1{{$}}
509define i64 @or_sext_i16_i64(ptr %p, i64 %v) {
510  %t = trunc i64 %v to i16
511  %old = atomicrmw or ptr %p, i16 %t seq_cst
512  %e = sext i16 %old to i64
513  ret i64 %e
514}
515
516; 32->64 sext rmw gets selected as i32.atomic.rmw.or, i64.extend_i32_s
517; CHECK-LABEL: or_sext_i32_i64:
518; CHECK-NEXT: .functype or_sext_i32_i64 (i32, i64) -> (i64){{$}}
519; CHECK: i32.wrap_i64 $push0=, $1{{$}}
520; CHECK: i32.atomic.rmw.or $push1=, 0($0), $pop0{{$}}
521; CHECK-NEXT: i64.extend_i32_s $push2=, $pop1{{$}}
522; CHECK-NEXT: return $pop2{{$}}
523define i64 @or_sext_i32_i64(ptr %p, i64 %v) {
524  %t = trunc i64 %v to i32
525  %old = atomicrmw or ptr %p, i32 %t seq_cst
526  %e = sext i32 %old to i64
527  ret i64 %e
528}
529
530; xor
531
532; CHECK-LABEL: xor_sext_i8_i32:
533; CHECK-NEXT: .functype xor_sext_i8_i32 (i32, i32) -> (i32){{$}}
534; CHECK: i32.atomic.rmw8.xor_u $push0=, 0($0), $1{{$}}
535; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}}
536; CHECK-NEXT: return $pop1{{$}}
537define i32 @xor_sext_i8_i32(ptr %p, i32 %v) {
538  %t = trunc i32 %v to i8
539  %old = atomicrmw xor ptr %p, i8 %t seq_cst
540  %e = sext i8 %old to i32
541  ret i32 %e
542}
543
544; CHECK-LABEL: xor_sext_i16_i32:
545; CHECK-NEXT: .functype xor_sext_i16_i32 (i32, i32) -> (i32){{$}}
546; CHECK: i32.atomic.rmw16.xor_u $push0=, 0($0), $1{{$}}
547; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}}
548; CHECK-NEXT: return $pop1{{$}}
549define i32 @xor_sext_i16_i32(ptr %p, i32 %v) {
550  %t = trunc i32 %v to i16
551  %old = atomicrmw xor ptr %p, i16 %t seq_cst
552  %e = sext i16 %old to i32
553  ret i32 %e
554}
555
556; CHECK-LABEL: xor_sext_i8_i64:
557; CHECK-NEXT: .functype xor_sext_i8_i64 (i32, i64) -> (i64){{$}}
558; CHECK: i64.atomic.rmw8.xor_u $push0=, 0($0), $1{{$}}
559; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}}
560; CHECK-NEXT: return $pop1{{$}}
561define i64 @xor_sext_i8_i64(ptr %p, i64 %v) {
562  %t = trunc i64 %v to i8
563  %old = atomicrmw xor ptr %p, i8 %t seq_cst
564  %e = sext i8 %old to i64
565  ret i64 %e
566}
567
568; CHECK-LABEL: xor_sext_i16_i64:
569; CHECK-NEXT: .functype xor_sext_i16_i64 (i32, i64) -> (i64){{$}}
570; CHECK: i64.atomic.rmw16.xor_u $push0=, 0($0), $1{{$}}
571; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}}
572; CHECK-NEXT: return $pop1{{$}}
573define i64 @xor_sext_i16_i64(ptr %p, i64 %v) {
574  %t = trunc i64 %v to i16
575  %old = atomicrmw xor ptr %p, i16 %t seq_cst
576  %e = sext i16 %old to i64
577  ret i64 %e
578}
579
580; 32->64 sext rmw gets selected as i32.atomic.rmw.xor, i64.extend_i32_s
581; CHECK-LABEL: xor_sext_i32_i64:
582; CHECK-NEXT: .functype xor_sext_i32_i64 (i32, i64) -> (i64){{$}}
583; CHECK: i32.wrap_i64 $push0=, $1{{$}}
584; CHECK: i32.atomic.rmw.xor $push1=, 0($0), $pop0{{$}}
585; CHECK-NEXT: i64.extend_i32_s $push2=, $pop1{{$}}
586; CHECK-NEXT: return $pop2{{$}}
587define i64 @xor_sext_i32_i64(ptr %p, i64 %v) {
588  %t = trunc i64 %v to i32
589  %old = atomicrmw xor ptr %p, i32 %t seq_cst
590  %e = sext i32 %old to i64
591  ret i64 %e
592}
593
594; xchg
595
596; CHECK-LABEL: xchg_sext_i8_i32:
597; CHECK-NEXT: .functype xchg_sext_i8_i32 (i32, i32) -> (i32){{$}}
598; CHECK: i32.atomic.rmw8.xchg_u $push0=, 0($0), $1{{$}}
599; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}}
600; CHECK-NEXT: return $pop1{{$}}
601define i32 @xchg_sext_i8_i32(ptr %p, i32 %v) {
602  %t = trunc i32 %v to i8
603  %old = atomicrmw xchg ptr %p, i8 %t seq_cst
604  %e = sext i8 %old to i32
605  ret i32 %e
606}
607
608; CHECK-LABEL: xchg_sext_i16_i32:
609; CHECK-NEXT: .functype xchg_sext_i16_i32 (i32, i32) -> (i32){{$}}
610; CHECK: i32.atomic.rmw16.xchg_u $push0=, 0($0), $1{{$}}
611; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}}
612; CHECK-NEXT: return $pop1{{$}}
613define i32 @xchg_sext_i16_i32(ptr %p, i32 %v) {
614  %t = trunc i32 %v to i16
615  %old = atomicrmw xchg ptr %p, i16 %t seq_cst
616  %e = sext i16 %old to i32
617  ret i32 %e
618}
619
620; CHECK-LABEL: xchg_sext_i8_i64:
621; CHECK-NEXT: .functype xchg_sext_i8_i64 (i32, i64) -> (i64){{$}}
622; CHECK: i64.atomic.rmw8.xchg_u $push0=, 0($0), $1{{$}}
623; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}}
624; CHECK-NEXT: return $pop1{{$}}
625define i64 @xchg_sext_i8_i64(ptr %p, i64 %v) {
626  %t = trunc i64 %v to i8
627  %old = atomicrmw xchg ptr %p, i8 %t seq_cst
628  %e = sext i8 %old to i64
629  ret i64 %e
630}
631
632; CHECK-LABEL: xchg_sext_i16_i64:
633; CHECK-NEXT: .functype xchg_sext_i16_i64 (i32, i64) -> (i64){{$}}
634; CHECK: i64.atomic.rmw16.xchg_u $push0=, 0($0), $1{{$}}
635; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}}
636; CHECK-NEXT: return $pop1{{$}}
637define i64 @xchg_sext_i16_i64(ptr %p, i64 %v) {
638  %t = trunc i64 %v to i16
639  %old = atomicrmw xchg ptr %p, i16 %t seq_cst
640  %e = sext i16 %old to i64
641  ret i64 %e
642}
643
644; 32->64 sext rmw gets selected as i32.atomic.rmw.xchg, i64.extend_i32_s
645; CHECK-LABEL: xchg_sext_i32_i64:
646; CHECK-NEXT: .functype xchg_sext_i32_i64 (i32, i64) -> (i64){{$}}
647; CHECK: i32.wrap_i64 $push0=, $1{{$}}
648; CHECK: i32.atomic.rmw.xchg $push1=, 0($0), $pop0{{$}}
649; CHECK-NEXT: i64.extend_i32_s $push2=, $pop1{{$}}
650; CHECK-NEXT: return $pop2{{$}}
651define i64 @xchg_sext_i32_i64(ptr %p, i64 %v) {
652  %t = trunc i64 %v to i32
653  %old = atomicrmw xchg ptr %p, i32 %t seq_cst
654  %e = sext i32 %old to i64
655  ret i64 %e
656}
657
658; cmpxchg
659
660; CHECK-LABEL: cmpxchg_sext_i8_i32:
661; CHECK-NEXT: .functype cmpxchg_sext_i8_i32 (i32, i32, i32) -> (i32){{$}}
662; CHECK: i32.atomic.rmw8.cmpxchg_u $push0=, 0($0), $1, $2{{$}}
663; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}}
664; CHECK-NEXT: return $pop1{{$}}
665define i32 @cmpxchg_sext_i8_i32(ptr %p, i32 %exp, i32 %new) {
666  %exp_t = trunc i32 %exp to i8
667  %new_t = trunc i32 %new to i8
668  %pair = cmpxchg ptr %p, i8 %exp_t, i8 %new_t seq_cst seq_cst
669  %old = extractvalue { i8, i1 } %pair, 0
670  %e = sext i8 %old to i32
671  ret i32 %e
672}
673
674; CHECK-LABEL: cmpxchg_sext_i16_i32:
675; CHECK-NEXT: .functype cmpxchg_sext_i16_i32 (i32, i32, i32) -> (i32){{$}}
676; CHECK: i32.atomic.rmw16.cmpxchg_u $push0=, 0($0), $1, $2{{$}}
677; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}}
678; CHECK-NEXT: return $pop1{{$}}
679define i32 @cmpxchg_sext_i16_i32(ptr %p, i32 %exp, i32 %new) {
680  %exp_t = trunc i32 %exp to i16
681  %new_t = trunc i32 %new to i16
682  %pair = cmpxchg ptr %p, i16 %exp_t, i16 %new_t seq_cst seq_cst
683  %old = extractvalue { i16, i1 } %pair, 0
684  %e = sext i16 %old to i32
685  ret i32 %e
686}
687
688; CHECK-LABEL: cmpxchg_sext_i8_i64:
689; CHECK-NEXT: .functype cmpxchg_sext_i8_i64 (i32, i64, i64) -> (i64){{$}}
690; CHECK: i64.atomic.rmw8.cmpxchg_u $push0=, 0($0), $1, $2{{$}}
691; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}}
692; CHECK-NEXT: return $pop1{{$}}
693define i64 @cmpxchg_sext_i8_i64(ptr %p, i64 %exp, i64 %new) {
694  %exp_t = trunc i64 %exp to i8
695  %new_t = trunc i64 %new to i8
696  %pair = cmpxchg ptr %p, i8 %exp_t, i8 %new_t seq_cst seq_cst
697  %old = extractvalue { i8, i1 } %pair, 0
698  %e = sext i8 %old to i64
699  ret i64 %e
700}
701
702; CHECK-LABEL: cmpxchg_sext_i16_i64:
703; CHECK-NEXT: .functype cmpxchg_sext_i16_i64 (i32, i64, i64) -> (i64){{$}}
704; CHECK: i64.atomic.rmw16.cmpxchg_u $push0=, 0($0), $1, $2{{$}}
705; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}}
706; CHECK-NEXT: return $pop1{{$}}
707define i64 @cmpxchg_sext_i16_i64(ptr %p, i64 %exp, i64 %new) {
708  %exp_t = trunc i64 %exp to i16
709  %new_t = trunc i64 %new to i16
710  %pair = cmpxchg ptr %p, i16 %exp_t, i16 %new_t seq_cst seq_cst
711  %old = extractvalue { i16, i1 } %pair, 0
712  %e = sext i16 %old to i64
713  ret i64 %e
714}
715
716; 32->64 sext rmw gets selected as i32.atomic.rmw.cmpxchg, i64.extend_i32_s
717; CHECK-LABEL: cmpxchg_sext_i32_i64:
718; CHECK-NEXT: .functype cmpxchg_sext_i32_i64 (i32, i64, i64) -> (i64){{$}}
719; CHECK: i32.wrap_i64 $push1=, $1{{$}}
720; CHECK-NEXT: i32.wrap_i64 $push0=, $2{{$}}
721; CHECK-NEXT: i32.atomic.rmw.cmpxchg $push2=, 0($0), $pop1, $pop0{{$}}
722; CHECK-NEXT: i64.extend_i32_s $push3=, $pop2{{$}}
723; CHECK-NEXT: return $pop3{{$}}
724define i64 @cmpxchg_sext_i32_i64(ptr %p, i64 %exp, i64 %new) {
725  %exp_t = trunc i64 %exp to i32
726  %new_t = trunc i64 %new to i32
727  %pair = cmpxchg ptr %p, i32 %exp_t, i32 %new_t seq_cst seq_cst
728  %old = extractvalue { i32, i1 } %pair, 0
729  %e = sext i32 %old to i64
730  ret i64 %e
731}
732
733; Unsupported instructions are expanded using cmpxchg with a loop.
734; Here we take a nand as an example.
735
736; nand
737
738; CHECK-LABEL: nand_sext_i8_i32:
739; CHECK-NEXT: .functype nand_sext_i8_i32 (i32, i32) -> (i32){{$}}
740; CHECK: loop
741; CHECK: i32.atomic.rmw8.cmpxchg_u
742; CHECK: i32.extend8_s
743define i32 @nand_sext_i8_i32(ptr %p, i32 %v) {
744  %t = trunc i32 %v to i8
745  %old = atomicrmw nand ptr %p, i8 %t seq_cst
746  %e = sext i8 %old to i32
747  ret i32 %e
748}
749
750; CHECK-LABEL: nand_sext_i16_i32:
751; CHECK-NEXT: .functype nand_sext_i16_i32 (i32, i32) -> (i32){{$}}
752; CHECK: loop
753; CHECK: i32.atomic.rmw16.cmpxchg_u
754; CHECK: i32.extend16_s
755define i32 @nand_sext_i16_i32(ptr %p, i32 %v) {
756  %t = trunc i32 %v to i16
757  %old = atomicrmw nand ptr %p, i16 %t seq_cst
758  %e = sext i16 %old to i32
759  ret i32 %e
760}
761
762; FIXME Currently this cannot make use of i64.atomic.rmw8.cmpxchg_u
763; CHECK-LABEL: nand_sext_i8_i64:
764; CHECK-NEXT: .functype nand_sext_i8_i64 (i32, i64) -> (i64){{$}}
765; CHECK: loop
766; CHECK: i32.atomic.rmw8.cmpxchg_u
767; CHECK: i64.extend_i32_u
768; CHECK: i64.extend8_s
769define i64 @nand_sext_i8_i64(ptr %p, i64 %v) {
770  %t = trunc i64 %v to i8
771  %old = atomicrmw nand ptr %p, i8 %t seq_cst
772  %e = sext i8 %old to i64
773  ret i64 %e
774}
775
776; FIXME Currently this cannot make use of i64.atomic.rmw16.cmpxchg_u
777; CHECK-LABEL: nand_sext_i16_i64:
778; CHECK-NEXT: .functype nand_sext_i16_i64 (i32, i64) -> (i64){{$}}
779; CHECK: loop
780; CHECK: i32.atomic.rmw16.cmpxchg_u
781; CHECK: i64.extend_i32_u
782; CHECK: i64.extend16_s
783define i64 @nand_sext_i16_i64(ptr %p, i64 %v) {
784  %t = trunc i64 %v to i16
785  %old = atomicrmw nand ptr %p, i16 %t seq_cst
786  %e = sext i16 %old to i64
787  ret i64 %e
788}
789
790; 32->64 sext rmw gets selected as i32.atomic.rmw.nand, i64.extend_i32_s
791; CHECK-LABEL: nand_sext_i32_i64:
792; CHECK-NEXT: .functype nand_sext_i32_i64 (i32, i64) -> (i64){{$}}
793; CHECK: loop
794; CHECK: i32.atomic.rmw.cmpxchg
795; CHECK: i64.extend_i32_s
796define i64 @nand_sext_i32_i64(ptr %p, i64 %v) {
797  %t = trunc i64 %v to i32
798  %old = atomicrmw nand ptr %p, i32 %t seq_cst
799  %e = sext i32 %old to i64
800  ret i64 %e
801}
802
803;===----------------------------------------------------------------------------
804; Atomic truncating & zero-extending RMWs
805;===----------------------------------------------------------------------------
806
807; add
808
809; CHECK-LABEL: add_zext_i8_i32:
810; CHECK-NEXT: .functype add_zext_i8_i32 (i32, i32) -> (i32){{$}}
811; CHECK: i32.atomic.rmw8.add_u $push0=, 0($0), $1{{$}}
812; CHECK-NEXT: return $pop0{{$}}
813define i32 @add_zext_i8_i32(ptr %p, i32 %v) {
814  %t = trunc i32 %v to i8
815  %old = atomicrmw add ptr %p, i8 %t seq_cst
816  %e = zext i8 %old to i32
817  ret i32 %e
818}
819
820; CHECK-LABEL: add_zext_i16_i32:
821; CHECK-NEXT: .functype add_zext_i16_i32 (i32, i32) -> (i32){{$}}
822; CHECK: i32.atomic.rmw16.add_u $push0=, 0($0), $1{{$}}
823; CHECK-NEXT: return $pop0{{$}}
824define i32 @add_zext_i16_i32(ptr %p, i32 %v) {
825  %t = trunc i32 %v to i16
826  %old = atomicrmw add ptr %p, i16 %t seq_cst
827  %e = zext i16 %old to i32
828  ret i32 %e
829}
830
831; CHECK-LABEL: add_zext_i8_i64:
832; CHECK-NEXT: .functype add_zext_i8_i64 (i32, i64) -> (i64){{$}}
833; CHECK: i64.atomic.rmw8.add_u $push0=, 0($0), $1{{$}}
834; CHECK-NEXT: return $pop0{{$}}
835define i64 @add_zext_i8_i64(ptr %p, i64 %v) {
836  %t = trunc i64 %v to i8
837  %old = atomicrmw add ptr %p, i8 %t seq_cst
838  %e = zext i8 %old to i64
839  ret i64 %e
840}
841
842; CHECK-LABEL: add_zext_i16_i64:
843; CHECK-NEXT: .functype add_zext_i16_i64 (i32, i64) -> (i64){{$}}
844; CHECK: i64.atomic.rmw16.add_u $push0=, 0($0), $1{{$}}
845; CHECK-NEXT: return $pop0{{$}}
846define i64 @add_zext_i16_i64(ptr %p, i64 %v) {
847  %t = trunc i64 %v to i16
848  %old = atomicrmw add ptr %p, i16 %t seq_cst
849  %e = zext i16 %old to i64
850  ret i64 %e
851}
852
853; CHECK-LABEL: add_zext_i32_i64:
854; CHECK-NEXT: .functype add_zext_i32_i64 (i32, i64) -> (i64){{$}}
855; CHECK: i64.atomic.rmw32.add_u $push0=, 0($0), $1{{$}}
856; CHECK-NEXT: return $pop0{{$}}
857define i64 @add_zext_i32_i64(ptr %p, i64 %v) {
858  %t = trunc i64 %v to i32
859  %old = atomicrmw add ptr %p, i32 %t seq_cst
860  %e = zext i32 %old to i64
861  ret i64 %e
862}
863
864; sub
865
866; CHECK-LABEL: sub_zext_i8_i32:
867; CHECK-NEXT: .functype sub_zext_i8_i32 (i32, i32) -> (i32){{$}}
868; CHECK: i32.atomic.rmw8.sub_u $push0=, 0($0), $1{{$}}
869; CHECK-NEXT: return $pop0{{$}}
870define i32 @sub_zext_i8_i32(ptr %p, i32 %v) {
871  %t = trunc i32 %v to i8
872  %old = atomicrmw sub ptr %p, i8 %t seq_cst
873  %e = zext i8 %old to i32
874  ret i32 %e
875}
876
877; CHECK-LABEL: sub_zext_i16_i32:
878; CHECK-NEXT: .functype sub_zext_i16_i32 (i32, i32) -> (i32){{$}}
879; CHECK: i32.atomic.rmw16.sub_u $push0=, 0($0), $1{{$}}
880; CHECK-NEXT: return $pop0{{$}}
881define i32 @sub_zext_i16_i32(ptr %p, i32 %v) {
882  %t = trunc i32 %v to i16
883  %old = atomicrmw sub ptr %p, i16 %t seq_cst
884  %e = zext i16 %old to i32
885  ret i32 %e
886}
887
888; CHECK-LABEL: sub_zext_i8_i64:
889; CHECK-NEXT: .functype sub_zext_i8_i64 (i32, i64) -> (i64){{$}}
890; CHECK: i64.atomic.rmw8.sub_u $push0=, 0($0), $1{{$}}
891; CHECK-NEXT: return $pop0{{$}}
892define i64 @sub_zext_i8_i64(ptr %p, i64 %v) {
893  %t = trunc i64 %v to i8
894  %old = atomicrmw sub ptr %p, i8 %t seq_cst
895  %e = zext i8 %old to i64
896  ret i64 %e
897}
898
899; CHECK-LABEL: sub_zext_i16_i64:
900; CHECK-NEXT: .functype sub_zext_i16_i64 (i32, i64) -> (i64){{$}}
901; CHECK: i64.atomic.rmw16.sub_u $push0=, 0($0), $1{{$}}
902; CHECK-NEXT: return $pop0{{$}}
903define i64 @sub_zext_i16_i64(ptr %p, i64 %v) {
904  %t = trunc i64 %v to i16
905  %old = atomicrmw sub ptr %p, i16 %t seq_cst
906  %e = zext i16 %old to i64
907  ret i64 %e
908}
909
910; CHECK-LABEL: sub_zext_i32_i64:
911; CHECK-NEXT: .functype sub_zext_i32_i64 (i32, i64) -> (i64){{$}}
912; CHECK: i64.atomic.rmw32.sub_u $push0=, 0($0), $1{{$}}
913; CHECK-NEXT: return $pop0{{$}}
914define i64 @sub_zext_i32_i64(ptr %p, i64 %v) {
915  %t = trunc i64 %v to i32
916  %old = atomicrmw sub ptr %p, i32 %t seq_cst
917  %e = zext i32 %old to i64
918  ret i64 %e
919}
920
921; and
922
923; CHECK-LABEL: and_zext_i8_i32:
924; CHECK-NEXT: .functype and_zext_i8_i32 (i32, i32) -> (i32){{$}}
925; CHECK: i32.atomic.rmw8.and_u $push0=, 0($0), $1{{$}}
926; CHECK-NEXT: return $pop0{{$}}
927define i32 @and_zext_i8_i32(ptr %p, i32 %v) {
928  %t = trunc i32 %v to i8
929  %old = atomicrmw and ptr %p, i8 %t seq_cst
930  %e = zext i8 %old to i32
931  ret i32 %e
932}
933
934; CHECK-LABEL: and_zext_i16_i32:
935; CHECK-NEXT: .functype and_zext_i16_i32 (i32, i32) -> (i32){{$}}
936; CHECK: i32.atomic.rmw16.and_u $push0=, 0($0), $1{{$}}
937; CHECK-NEXT: return $pop0{{$}}
938define i32 @and_zext_i16_i32(ptr %p, i32 %v) {
939  %t = trunc i32 %v to i16
940  %old = atomicrmw and ptr %p, i16 %t seq_cst
941  %e = zext i16 %old to i32
942  ret i32 %e
943}
944
945; CHECK-LABEL: and_zext_i8_i64:
946; CHECK-NEXT: .functype and_zext_i8_i64 (i32, i64) -> (i64){{$}}
947; CHECK: i64.atomic.rmw8.and_u $push0=, 0($0), $1{{$}}
948; CHECK-NEXT: return $pop0{{$}}
949define i64 @and_zext_i8_i64(ptr %p, i64 %v) {
950  %t = trunc i64 %v to i8
951  %old = atomicrmw and ptr %p, i8 %t seq_cst
952  %e = zext i8 %old to i64
953  ret i64 %e
954}
955
956; CHECK-LABEL: and_zext_i16_i64:
957; CHECK-NEXT: .functype and_zext_i16_i64 (i32, i64) -> (i64){{$}}
958; CHECK: i64.atomic.rmw16.and_u $push0=, 0($0), $1{{$}}
959; CHECK-NEXT: return $pop0{{$}}
960define i64 @and_zext_i16_i64(ptr %p, i64 %v) {
961  %t = trunc i64 %v to i16
962  %old = atomicrmw and ptr %p, i16 %t seq_cst
963  %e = zext i16 %old to i64
964  ret i64 %e
965}
966
967; CHECK-LABEL: and_zext_i32_i64:
968; CHECK-NEXT: .functype and_zext_i32_i64 (i32, i64) -> (i64){{$}}
969; CHECK: i64.atomic.rmw32.and_u $push0=, 0($0), $1{{$}}
970; CHECK-NEXT: return $pop0{{$}}
971define i64 @and_zext_i32_i64(ptr %p, i64 %v) {
972  %t = trunc i64 %v to i32
973  %old = atomicrmw and ptr %p, i32 %t seq_cst
974  %e = zext i32 %old to i64
975  ret i64 %e
976}
977
978; or
979
980; CHECK-LABEL: or_zext_i8_i32:
981; CHECK-NEXT: .functype or_zext_i8_i32 (i32, i32) -> (i32){{$}}
982; CHECK: i32.atomic.rmw8.or_u $push0=, 0($0), $1{{$}}
983; CHECK-NEXT: return $pop0{{$}}
984define i32 @or_zext_i8_i32(ptr %p, i32 %v) {
985  %t = trunc i32 %v to i8
986  %old = atomicrmw or ptr %p, i8 %t seq_cst
987  %e = zext i8 %old to i32
988  ret i32 %e
989}
990
991; CHECK-LABEL: or_zext_i16_i32:
992; CHECK-NEXT: .functype or_zext_i16_i32 (i32, i32) -> (i32){{$}}
993; CHECK: i32.atomic.rmw16.or_u $push0=, 0($0), $1{{$}}
994; CHECK-NEXT: return $pop0{{$}}
995define i32 @or_zext_i16_i32(ptr %p, i32 %v) {
996  %t = trunc i32 %v to i16
997  %old = atomicrmw or ptr %p, i16 %t seq_cst
998  %e = zext i16 %old to i32
999  ret i32 %e
1000}
1001
1002; CHECK-LABEL: or_zext_i8_i64:
1003; CHECK-NEXT: .functype or_zext_i8_i64 (i32, i64) -> (i64){{$}}
1004; CHECK: i64.atomic.rmw8.or_u $push0=, 0($0), $1{{$}}
1005; CHECK-NEXT: return $pop0{{$}}
1006define i64 @or_zext_i8_i64(ptr %p, i64 %v) {
1007  %t = trunc i64 %v to i8
1008  %old = atomicrmw or ptr %p, i8 %t seq_cst
1009  %e = zext i8 %old to i64
1010  ret i64 %e
1011}
1012
1013; CHECK-LABEL: or_zext_i16_i64:
1014; CHECK-NEXT: .functype or_zext_i16_i64 (i32, i64) -> (i64){{$}}
1015; CHECK: i64.atomic.rmw16.or_u $push0=, 0($0), $1{{$}}
1016; CHECK-NEXT: return $pop0{{$}}
1017define i64 @or_zext_i16_i64(ptr %p, i64 %v) {
1018  %t = trunc i64 %v to i16
1019  %old = atomicrmw or ptr %p, i16 %t seq_cst
1020  %e = zext i16 %old to i64
1021  ret i64 %e
1022}
1023
1024; CHECK-LABEL: or_zext_i32_i64:
1025; CHECK-NEXT: .functype or_zext_i32_i64 (i32, i64) -> (i64){{$}}
1026; CHECK: i64.atomic.rmw32.or_u $push0=, 0($0), $1{{$}}
1027; CHECK-NEXT: return $pop0{{$}}
1028define i64 @or_zext_i32_i64(ptr %p, i64 %v) {
1029  %t = trunc i64 %v to i32
1030  %old = atomicrmw or ptr %p, i32 %t seq_cst
1031  %e = zext i32 %old to i64
1032  ret i64 %e
1033}
1034
1035; xor
1036
1037; CHECK-LABEL: xor_zext_i8_i32:
1038; CHECK-NEXT: .functype xor_zext_i8_i32 (i32, i32) -> (i32){{$}}
1039; CHECK: i32.atomic.rmw8.xor_u $push0=, 0($0), $1{{$}}
1040; CHECK-NEXT: return $pop0{{$}}
1041define i32 @xor_zext_i8_i32(ptr %p, i32 %v) {
1042  %t = trunc i32 %v to i8
1043  %old = atomicrmw xor ptr %p, i8 %t seq_cst
1044  %e = zext i8 %old to i32
1045  ret i32 %e
1046}
1047
1048; CHECK-LABEL: xor_zext_i16_i32:
1049; CHECK-NEXT: .functype xor_zext_i16_i32 (i32, i32) -> (i32){{$}}
1050; CHECK: i32.atomic.rmw16.xor_u $push0=, 0($0), $1{{$}}
1051; CHECK-NEXT: return $pop0{{$}}
1052define i32 @xor_zext_i16_i32(ptr %p, i32 %v) {
1053  %t = trunc i32 %v to i16
1054  %old = atomicrmw xor ptr %p, i16 %t seq_cst
1055  %e = zext i16 %old to i32
1056  ret i32 %e
1057}
1058
1059; CHECK-LABEL: xor_zext_i8_i64:
1060; CHECK-NEXT: .functype xor_zext_i8_i64 (i32, i64) -> (i64){{$}}
1061; CHECK: i64.atomic.rmw8.xor_u $push0=, 0($0), $1{{$}}
1062; CHECK-NEXT: return $pop0{{$}}
1063define i64 @xor_zext_i8_i64(ptr %p, i64 %v) {
1064  %t = trunc i64 %v to i8
1065  %old = atomicrmw xor ptr %p, i8 %t seq_cst
1066  %e = zext i8 %old to i64
1067  ret i64 %e
1068}
1069
1070; CHECK-LABEL: xor_zext_i16_i64:
1071; CHECK-NEXT: .functype xor_zext_i16_i64 (i32, i64) -> (i64){{$}}
1072; CHECK: i64.atomic.rmw16.xor_u $push0=, 0($0), $1{{$}}
1073; CHECK-NEXT: return $pop0{{$}}
1074define i64 @xor_zext_i16_i64(ptr %p, i64 %v) {
1075  %t = trunc i64 %v to i16
1076  %old = atomicrmw xor ptr %p, i16 %t seq_cst
1077  %e = zext i16 %old to i64
1078  ret i64 %e
1079}
1080
1081; CHECK-LABEL: xor_zext_i32_i64:
1082; CHECK-NEXT: .functype xor_zext_i32_i64 (i32, i64) -> (i64){{$}}
1083; CHECK: i64.atomic.rmw32.xor_u $push0=, 0($0), $1{{$}}
1084; CHECK-NEXT: return $pop0{{$}}
1085define i64 @xor_zext_i32_i64(ptr %p, i64 %v) {
1086  %t = trunc i64 %v to i32
1087  %old = atomicrmw xor ptr %p, i32 %t seq_cst
1088  %e = zext i32 %old to i64
1089  ret i64 %e
1090}
1091
1092; xchg
1093
1094; CHECK-LABEL: xchg_zext_i8_i32:
1095; CHECK-NEXT: .functype xchg_zext_i8_i32 (i32, i32) -> (i32){{$}}
1096; CHECK: i32.atomic.rmw8.xchg_u $push0=, 0($0), $1{{$}}
1097; CHECK-NEXT: return $pop0{{$}}
1098define i32 @xchg_zext_i8_i32(ptr %p, i32 %v) {
1099  %t = trunc i32 %v to i8
1100  %old = atomicrmw xchg ptr %p, i8 %t seq_cst
1101  %e = zext i8 %old to i32
1102  ret i32 %e
1103}
1104
1105; CHECK-LABEL: xchg_zext_i16_i32:
1106; CHECK-NEXT: .functype xchg_zext_i16_i32 (i32, i32) -> (i32){{$}}
1107; CHECK: i32.atomic.rmw16.xchg_u $push0=, 0($0), $1{{$}}
1108; CHECK-NEXT: return $pop0{{$}}
1109define i32 @xchg_zext_i16_i32(ptr %p, i32 %v) {
1110  %t = trunc i32 %v to i16
1111  %old = atomicrmw xchg ptr %p, i16 %t seq_cst
1112  %e = zext i16 %old to i32
1113  ret i32 %e
1114}
1115
1116; CHECK-LABEL: xchg_zext_i8_i64:
1117; CHECK-NEXT: .functype xchg_zext_i8_i64 (i32, i64) -> (i64){{$}}
1118; CHECK: i64.atomic.rmw8.xchg_u $push0=, 0($0), $1{{$}}
1119; CHECK-NEXT: return $pop0{{$}}
1120define i64 @xchg_zext_i8_i64(ptr %p, i64 %v) {
1121  %t = trunc i64 %v to i8
1122  %old = atomicrmw xchg ptr %p, i8 %t seq_cst
1123  %e = zext i8 %old to i64
1124  ret i64 %e
1125}
1126
1127; CHECK-LABEL: xchg_zext_i16_i64:
1128; CHECK-NEXT: .functype xchg_zext_i16_i64 (i32, i64) -> (i64){{$}}
1129; CHECK: i64.atomic.rmw16.xchg_u $push0=, 0($0), $1{{$}}
1130; CHECK-NEXT: return $pop0{{$}}
1131define i64 @xchg_zext_i16_i64(ptr %p, i64 %v) {
1132  %t = trunc i64 %v to i16
1133  %old = atomicrmw xchg ptr %p, i16 %t seq_cst
1134  %e = zext i16 %old to i64
1135  ret i64 %e
1136}
1137
1138; CHECK-LABEL: xchg_zext_i32_i64:
1139; CHECK-NEXT: .functype xchg_zext_i32_i64 (i32, i64) -> (i64){{$}}
1140; CHECK: i64.atomic.rmw32.xchg_u $push0=, 0($0), $1{{$}}
1141; CHECK-NEXT: return $pop0{{$}}
1142define i64 @xchg_zext_i32_i64(ptr %p, i64 %v) {
1143  %t = trunc i64 %v to i32
1144  %old = atomicrmw xchg ptr %p, i32 %t seq_cst
1145  %e = zext i32 %old to i64
1146  ret i64 %e
1147}
1148
1149; cmpxchg
1150
1151; CHECK-LABEL: cmpxchg_zext_i8_i32:
1152; CHECK-NEXT: .functype cmpxchg_zext_i8_i32 (i32, i32, i32) -> (i32){{$}}
1153; CHECK: i32.atomic.rmw8.cmpxchg_u $push0=, 0($0), $1, $2{{$}}
1154; CHECK-NEXT: return $pop0{{$}}
1155define i32 @cmpxchg_zext_i8_i32(ptr %p, i32 %exp, i32 %new) {
1156  %exp_t = trunc i32 %exp to i8
1157  %new_t = trunc i32 %new to i8
1158  %pair = cmpxchg ptr %p, i8 %exp_t, i8 %new_t seq_cst seq_cst
1159  %old = extractvalue { i8, i1 } %pair, 0
1160  %e = zext i8 %old to i32
1161  ret i32 %e
1162}
1163
1164; CHECK-LABEL: cmpxchg_zext_i16_i32:
1165; CHECK-NEXT: .functype cmpxchg_zext_i16_i32 (i32, i32, i32) -> (i32){{$}}
1166; CHECK: i32.atomic.rmw16.cmpxchg_u $push0=, 0($0), $1, $2{{$}}
1167; CHECK-NEXT: return $pop0{{$}}
1168define i32 @cmpxchg_zext_i16_i32(ptr %p, i32 %exp, i32 %new) {
1169  %exp_t = trunc i32 %exp to i16
1170  %new_t = trunc i32 %new to i16
1171  %pair = cmpxchg ptr %p, i16 %exp_t, i16 %new_t seq_cst seq_cst
1172  %old = extractvalue { i16, i1 } %pair, 0
1173  %e = zext i16 %old to i32
1174  ret i32 %e
1175}
1176
1177; CHECK-LABEL: cmpxchg_zext_i8_i64:
1178; CHECK-NEXT: .functype cmpxchg_zext_i8_i64 (i32, i64, i64) -> (i64){{$}}
1179; CHECK: i64.atomic.rmw8.cmpxchg_u $push0=, 0($0), $1, $2{{$}}
1180; CHECK-NEXT: return $pop0{{$}}
1181define i64 @cmpxchg_zext_i8_i64(ptr %p, i64 %exp, i64 %new) {
1182  %exp_t = trunc i64 %exp to i8
1183  %new_t = trunc i64 %new to i8
1184  %pair = cmpxchg ptr %p, i8 %exp_t, i8 %new_t seq_cst seq_cst
1185  %old = extractvalue { i8, i1 } %pair, 0
1186  %e = zext i8 %old to i64
1187  ret i64 %e
1188}
1189
1190; CHECK-LABEL: cmpxchg_zext_i16_i64:
1191; CHECK-NEXT: .functype cmpxchg_zext_i16_i64 (i32, i64, i64) -> (i64){{$}}
1192; CHECK: i64.atomic.rmw16.cmpxchg_u $push0=, 0($0), $1, $2{{$}}
1193; CHECK-NEXT: return $pop0{{$}}
1194define i64 @cmpxchg_zext_i16_i64(ptr %p, i64 %exp, i64 %new) {
1195  %exp_t = trunc i64 %exp to i16
1196  %new_t = trunc i64 %new to i16
1197  %pair = cmpxchg ptr %p, i16 %exp_t, i16 %new_t seq_cst seq_cst
1198  %old = extractvalue { i16, i1 } %pair, 0
1199  %e = zext i16 %old to i64
1200  ret i64 %e
1201}
1202
1203; CHECK-LABEL: cmpxchg_zext_i32_i64:
1204; CHECK-NEXT: .functype cmpxchg_zext_i32_i64 (i32, i64, i64) -> (i64){{$}}
1205; CHECK: i64.atomic.rmw32.cmpxchg_u $push0=, 0($0), $1, $2{{$}}
1206; CHECK-NEXT: return $pop0{{$}}
1207define i64 @cmpxchg_zext_i32_i64(ptr %p, i64 %exp, i64 %new) {
1208  %exp_t = trunc i64 %exp to i32
1209  %new_t = trunc i64 %new to i32
1210  %pair = cmpxchg ptr %p, i32 %exp_t, i32 %new_t seq_cst seq_cst
1211  %old = extractvalue { i32, i1 } %pair, 0
1212  %e = zext i32 %old to i64
1213  ret i64 %e
1214}
1215
1216; Unsupported instructions are expanded using cmpxchg with a loop.
1217; Here we take a nand as an example.
1218
1219; nand
1220
1221; CHECK-LABEL: nand_zext_i8_i32:
1222; CHECK-NEXT: .functype nand_zext_i8_i32 (i32, i32) -> (i32){{$}}
1223; CHECK: loop
1224; CHECK: i32.atomic.rmw8.cmpxchg_u
1225define i32 @nand_zext_i8_i32(ptr %p, i32 %v) {
1226  %t = trunc i32 %v to i8
1227  %old = atomicrmw nand ptr %p, i8 %t seq_cst
1228  %e = zext i8 %old to i32
1229  ret i32 %e
1230}
1231
1232; CHECK-LABEL: nand_zext_i16_i32:
1233; CHECK-NEXT: .functype nand_zext_i16_i32 (i32, i32) -> (i32){{$}}
1234; CHECK: loop
1235; CHECK: i32.atomic.rmw16.cmpxchg_u
1236define i32 @nand_zext_i16_i32(ptr %p, i32 %v) {
1237  %t = trunc i32 %v to i16
1238  %old = atomicrmw nand ptr %p, i16 %t seq_cst
1239  %e = zext i16 %old to i32
1240  ret i32 %e
1241}
1242
1243; FIXME Currently this cannot make use of i64.atomic.rmw8.cmpxchg_u
1244; CHECK-LABEL: nand_zext_i8_i64:
1245; CHECK-NEXT: .functype nand_zext_i8_i64 (i32, i64) -> (i64){{$}}
1246; CHECK: loop
1247; CHECK: i32.atomic.rmw8.cmpxchg_u
1248; CHECK: i64.extend_i32_u
1249define i64 @nand_zext_i8_i64(ptr %p, i64 %v) {
1250  %t = trunc i64 %v to i8
1251  %old = atomicrmw nand ptr %p, i8 %t seq_cst
1252  %e = zext i8 %old to i64
1253  ret i64 %e
1254}
1255
1256; FIXME Currently this cannot make use of i64.atomic.rmw16.cmpxchg_u
1257; CHECK-LABEL: nand_zext_i16_i64:
1258; CHECK-NEXT: .functype nand_zext_i16_i64 (i32, i64) -> (i64){{$}}
1259; CHECK: loop
1260; CHECK: i32.atomic.rmw16.cmpxchg_u
1261; CHECK: i64.extend_i32_u
1262define i64 @nand_zext_i16_i64(ptr %p, i64 %v) {
1263  %t = trunc i64 %v to i16
1264  %old = atomicrmw nand ptr %p, i16 %t seq_cst
1265  %e = zext i16 %old to i64
1266  ret i64 %e
1267}
1268
1269; FIXME Currently this cannot make use of i64.atomic.rmw32.cmpxchg_u
1270; CHECK-LABEL: nand_zext_i32_i64:
1271; CHECK-NEXT: .functype nand_zext_i32_i64 (i32, i64) -> (i64){{$}}
1272; CHECK: loop
1273; CHECK: i32.atomic.rmw.cmpxchg
1274; CHECK: i64.extend_i32_u
1275define i64 @nand_zext_i32_i64(ptr %p, i64 %v) {
1276  %t = trunc i64 %v to i32
1277  %old = atomicrmw nand ptr %p, i32 %t seq_cst
1278  %e = zext i32 %old to i64
1279  ret i64 %e
1280}
1281