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