• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 -disable-wasm-explicit-locals -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: .param 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: .param 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: .param 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: .param 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: .param 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: .param 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;===----------------------------------------------------------------------------
68; Atomic read-modify-writes: 64-bit
69;===----------------------------------------------------------------------------
70
71; CHECK-LABEL: add_i64:
72; CHECK-NEXT: .param i32, i64{{$}}
73; CHECK: i64.atomic.rmw.add $push0=, 0($0), $1{{$}}
74; CHECK-NEXT: return $pop0{{$}}
75define i64 @add_i64(i64* %p, i64 %v) {
76  %old = atomicrmw add i64* %p, i64 %v seq_cst
77  ret i64 %old
78}
79
80; CHECK-LABEL: sub_i64:
81; CHECK-NEXT: .param i32, i64{{$}}
82; CHECK: i64.atomic.rmw.sub $push0=, 0($0), $1{{$}}
83; CHECK-NEXT: return $pop0{{$}}
84define i64 @sub_i64(i64* %p, i64 %v) {
85  %old = atomicrmw sub i64* %p, i64 %v seq_cst
86  ret i64 %old
87}
88
89; CHECK-LABEL: and_i64:
90; CHECK-NEXT: .param i32, i64{{$}}
91; CHECK: i64.atomic.rmw.and $push0=, 0($0), $1{{$}}
92; CHECK-NEXT: return $pop0{{$}}
93define i64 @and_i64(i64* %p, i64 %v) {
94  %old = atomicrmw and i64* %p, i64 %v seq_cst
95  ret i64 %old
96}
97
98; CHECK-LABEL: or_i64:
99; CHECK-NEXT: .param i32, i64{{$}}
100; CHECK: i64.atomic.rmw.or $push0=, 0($0), $1{{$}}
101; CHECK-NEXT: return $pop0{{$}}
102define i64 @or_i64(i64* %p, i64 %v) {
103  %old = atomicrmw or i64* %p, i64 %v seq_cst
104  ret i64 %old
105}
106
107; CHECK-LABEL: xor_i64:
108; CHECK-NEXT: .param i32, i64{{$}}
109; CHECK: i64.atomic.rmw.xor $push0=, 0($0), $1{{$}}
110; CHECK-NEXT: return $pop0{{$}}
111define i64 @xor_i64(i64* %p, i64 %v) {
112  %old = atomicrmw xor i64* %p, i64 %v seq_cst
113  ret i64 %old
114}
115
116; CHECK-LABEL: xchg_i64:
117; CHECK-NEXT: .param i32, i64{{$}}
118; CHECK: i64.atomic.rmw.xchg $push0=, 0($0), $1{{$}}
119; CHECK-NEXT: return $pop0{{$}}
120define i64 @xchg_i64(i64* %p, i64 %v) {
121  %old = atomicrmw xchg i64* %p, i64 %v seq_cst
122  ret i64 %old
123}
124
125;===----------------------------------------------------------------------------
126; Atomic truncating & sign-extending RMWs
127;===----------------------------------------------------------------------------
128
129; add
130
131; CHECK-LABEL: add_sext_i8_i32:
132; CHECK-NEXT: .param i32, i32{{$}}
133; CHECK: i32.atomic.rmw8_u.add $push0=, 0($0), $1{{$}}
134; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}}
135; CHECK-NEXT: return $pop1{{$}}
136define i32 @add_sext_i8_i32(i8* %p, i32 %v) {
137  %t = trunc i32 %v to i8
138  %old = atomicrmw add i8* %p, i8 %t seq_cst
139  %e = sext i8 %old to i32
140  ret i32 %e
141}
142
143; CHECK-LABEL: add_sext_i16_i32:
144; CHECK-NEXT: .param i32, i32{{$}}
145; CHECK: i32.atomic.rmw16_u.add $push0=, 0($0), $1{{$}}
146; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}}
147; CHECK-NEXT: return $pop1{{$}}
148define i32 @add_sext_i16_i32(i16* %p, i32 %v) {
149  %t = trunc i32 %v to i16
150  %old = atomicrmw add i16* %p, i16 %t seq_cst
151  %e = sext i16 %old to i32
152  ret i32 %e
153}
154
155; CHECK-LABEL: add_sext_i8_i64:
156; CHECK-NEXT: .param i32, i64{{$}}
157; CHECK: i64.atomic.rmw8_u.add $push0=, 0($0), $1{{$}}
158; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}}
159; CHECK-NEXT: return $pop1{{$}}
160define i64 @add_sext_i8_i64(i8* %p, i64 %v) {
161  %t = trunc i64 %v to i8
162  %old = atomicrmw add i8* %p, i8 %t seq_cst
163  %e = sext i8 %old to i64
164  ret i64 %e
165}
166
167; CHECK-LABEL: add_sext_i16_i64:
168; CHECK-NEXT: .param i32, i64{{$}}
169; CHECK: i64.atomic.rmw16_u.add $push0=, 0($0), $1{{$}}
170; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}}
171; CHECK-NEXT: return $pop1{{$}}
172define i64 @add_sext_i16_i64(i16* %p, i64 %v) {
173  %t = trunc i64 %v to i16
174  %old = atomicrmw add i16* %p, i16 %t seq_cst
175  %e = sext i16 %old to i64
176  ret i64 %e
177}
178
179; 32->64 sext rmw gets selected as i32.atomic.rmw.add, i64_extend_s/i32
180; CHECK-LABEL: add_sext_i32_i64:
181; CHECK-NEXT: .param i32, i64{{$}}
182; CHECK: i32.wrap/i64 $push0=, $1{{$}}
183; CHECK: i32.atomic.rmw.add $push1=, 0($0), $pop0{{$}}
184; CHECK-NEXT: i64.extend_s/i32 $push2=, $pop1{{$}}
185; CHECK-NEXT: return $pop2{{$}}
186define i64 @add_sext_i32_i64(i32* %p, i64 %v) {
187  %t = trunc i64 %v to i32
188  %old = atomicrmw add i32* %p, i32 %t seq_cst
189  %e = sext i32 %old to i64
190  ret i64 %e
191}
192
193; sub
194
195; CHECK-LABEL: sub_sext_i8_i32:
196; CHECK-NEXT: .param i32, i32{{$}}
197; CHECK: i32.atomic.rmw8_u.sub $push0=, 0($0), $1{{$}}
198; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}}
199; CHECK-NEXT: return $pop1{{$}}
200define i32 @sub_sext_i8_i32(i8* %p, i32 %v) {
201  %t = trunc i32 %v to i8
202  %old = atomicrmw sub i8* %p, i8 %t seq_cst
203  %e = sext i8 %old to i32
204  ret i32 %e
205}
206
207; CHECK-LABEL: sub_sext_i16_i32:
208; CHECK-NEXT: .param i32, i32{{$}}
209; CHECK: i32.atomic.rmw16_u.sub $push0=, 0($0), $1{{$}}
210; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}}
211; CHECK-NEXT: return $pop1{{$}}
212define i32 @sub_sext_i16_i32(i16* %p, i32 %v) {
213  %t = trunc i32 %v to i16
214  %old = atomicrmw sub i16* %p, i16 %t seq_cst
215  %e = sext i16 %old to i32
216  ret i32 %e
217}
218
219; CHECK-LABEL: sub_sext_i8_i64:
220; CHECK-NEXT: .param i32, i64{{$}}
221; CHECK: i64.atomic.rmw8_u.sub $push0=, 0($0), $1{{$}}
222; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}}
223; CHECK-NEXT: return $pop1{{$}}
224define i64 @sub_sext_i8_i64(i8* %p, i64 %v) {
225  %t = trunc i64 %v to i8
226  %old = atomicrmw sub i8* %p, i8 %t seq_cst
227  %e = sext i8 %old to i64
228  ret i64 %e
229}
230
231; CHECK-LABEL: sub_sext_i16_i64:
232; CHECK-NEXT: .param i32, i64{{$}}
233; CHECK: i64.atomic.rmw16_u.sub $push0=, 0($0), $1{{$}}
234; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}}
235; CHECK-NEXT: return $pop1{{$}}
236define i64 @sub_sext_i16_i64(i16* %p, i64 %v) {
237  %t = trunc i64 %v to i16
238  %old = atomicrmw sub i16* %p, i16 %t seq_cst
239  %e = sext i16 %old to i64
240  ret i64 %e
241}
242
243; 32->64 sext rmw gets selected as i32.atomic.rmw.sub, i64_extend_s/i32
244; CHECK-LABEL: sub_sext_i32_i64:
245; CHECK-NEXT: .param i32, i64{{$}}
246; CHECK: i32.wrap/i64 $push0=, $1
247; CHECK: i32.atomic.rmw.sub $push1=, 0($0), $pop0{{$}}
248; CHECK-NEXT: i64.extend_s/i32 $push2=, $pop1{{$}}
249; CHECK-NEXT: return $pop2{{$}}
250define i64 @sub_sext_i32_i64(i32* %p, i64 %v) {
251  %t = trunc i64 %v to i32
252  %old = atomicrmw sub i32* %p, i32 %t seq_cst
253  %e = sext i32 %old to i64
254  ret i64 %e
255}
256
257; and
258
259; CHECK-LABEL: and_sext_i8_i32:
260; CHECK-NEXT: .param i32, i32{{$}}
261; CHECK: i32.atomic.rmw8_u.and $push0=, 0($0), $1{{$}}
262; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}}
263; CHECK-NEXT: return $pop1{{$}}
264define i32 @and_sext_i8_i32(i8* %p, i32 %v) {
265  %t = trunc i32 %v to i8
266  %old = atomicrmw and i8* %p, i8 %t seq_cst
267  %e = sext i8 %old to i32
268  ret i32 %e
269}
270
271; CHECK-LABEL: and_sext_i16_i32:
272; CHECK-NEXT: .param i32, i32{{$}}
273; CHECK: i32.atomic.rmw16_u.and $push0=, 0($0), $1{{$}}
274; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}}
275; CHECK-NEXT: return $pop1{{$}}
276define i32 @and_sext_i16_i32(i16* %p, i32 %v) {
277  %t = trunc i32 %v to i16
278  %old = atomicrmw and i16* %p, i16 %t seq_cst
279  %e = sext i16 %old to i32
280  ret i32 %e
281}
282
283; CHECK-LABEL: and_sext_i8_i64:
284; CHECK-NEXT: .param i32, i64{{$}}
285; CHECK: i64.atomic.rmw8_u.and $push0=, 0($0), $1{{$}}
286; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}}
287; CHECK-NEXT: return $pop1{{$}}
288define i64 @and_sext_i8_i64(i8* %p, i64 %v) {
289  %t = trunc i64 %v to i8
290  %old = atomicrmw and i8* %p, i8 %t seq_cst
291  %e = sext i8 %old to i64
292  ret i64 %e
293}
294
295; CHECK-LABEL: and_sext_i16_i64:
296; CHECK-NEXT: .param i32, i64{{$}}
297; CHECK: i64.atomic.rmw16_u.and $push0=, 0($0), $1{{$}}
298; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}}
299; CHECK-NEXT: return $pop1{{$}}
300define i64 @and_sext_i16_i64(i16* %p, i64 %v) {
301  %t = trunc i64 %v to i16
302  %old = atomicrmw and i16* %p, i16 %t seq_cst
303  %e = sext i16 %old to i64
304  ret i64 %e
305}
306
307; 32->64 sext rmw gets selected as i32.atomic.rmw.and, i64_extend_s/i32
308; CHECK-LABEL: and_sext_i32_i64:
309; CHECK-NEXT: .param i32, i64{{$}}
310; CHECK: i32.wrap/i64 $push0=, $1{{$}}
311; CHECK: i32.atomic.rmw.and $push1=, 0($0), $pop0{{$}}
312; CHECK-NEXT: i64.extend_s/i32 $push2=, $pop1{{$}}
313; CHECK-NEXT: return $pop2{{$}}
314define i64 @and_sext_i32_i64(i32* %p, i64 %v) {
315  %t = trunc i64 %v to i32
316  %old = atomicrmw and i32* %p, i32 %t seq_cst
317  %e = sext i32 %old to i64
318  ret i64 %e
319}
320
321; or
322
323; CHECK-LABEL: or_sext_i8_i32:
324; CHECK-NEXT: .param i32, i32{{$}}
325; CHECK: i32.atomic.rmw8_u.or $push0=, 0($0), $1{{$}}
326; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}}
327; CHECK-NEXT: return $pop1{{$}}
328define i32 @or_sext_i8_i32(i8* %p, i32 %v) {
329  %t = trunc i32 %v to i8
330  %old = atomicrmw or i8* %p, i8 %t seq_cst
331  %e = sext i8 %old to i32
332  ret i32 %e
333}
334
335; CHECK-LABEL: or_sext_i16_i32:
336; CHECK-NEXT: .param i32, i32{{$}}
337; CHECK: i32.atomic.rmw16_u.or $push0=, 0($0), $1{{$}}
338; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}}
339; CHECK-NEXT: return $pop1{{$}}
340define i32 @or_sext_i16_i32(i16* %p, i32 %v) {
341  %t = trunc i32 %v to i16
342  %old = atomicrmw or i16* %p, i16 %t seq_cst
343  %e = sext i16 %old to i32
344  ret i32 %e
345}
346
347; CHECK-LABEL: or_sext_i8_i64:
348; CHECK-NEXT: .param i32, i64{{$}}
349; CHECK: i64.atomic.rmw8_u.or $push0=, 0($0), $1{{$}}
350; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}}
351; CHECK-NEXT: return $pop1{{$}}
352define i64 @or_sext_i8_i64(i8* %p, i64 %v) {
353  %t = trunc i64 %v to i8
354  %old = atomicrmw or i8* %p, i8 %t seq_cst
355  %e = sext i8 %old to i64
356  ret i64 %e
357}
358
359; CHECK-LABEL: or_sext_i16_i64:
360; CHECK-NEXT: .param i32, i64{{$}}
361; CHECK: i64.atomic.rmw16_u.or $push0=, 0($0), $1{{$}}
362; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}}
363; CHECK-NEXT: return $pop1{{$}}
364define i64 @or_sext_i16_i64(i16* %p, i64 %v) {
365  %t = trunc i64 %v to i16
366  %old = atomicrmw or i16* %p, i16 %t seq_cst
367  %e = sext i16 %old to i64
368  ret i64 %e
369}
370
371; 32->64 sext rmw gets selected as i32.atomic.rmw.or, i64_extend_s/i32
372; CHECK-LABEL: or_sext_i32_i64:
373; CHECK-NEXT: .param i32, i64{{$}}
374; CHECK: i32.wrap/i64 $push0=, $1{{$}}
375; CHECK: i32.atomic.rmw.or $push1=, 0($0), $pop0{{$}}
376; CHECK-NEXT: i64.extend_s/i32 $push2=, $pop1{{$}}
377; CHECK-NEXT: return $pop2{{$}}
378define i64 @or_sext_i32_i64(i32* %p, i64 %v) {
379  %t = trunc i64 %v to i32
380  %old = atomicrmw or i32* %p, i32 %t seq_cst
381  %e = sext i32 %old to i64
382  ret i64 %e
383}
384
385; xor
386
387; CHECK-LABEL: xor_sext_i8_i32:
388; CHECK-NEXT: .param i32, i32{{$}}
389; CHECK: i32.atomic.rmw8_u.xor $push0=, 0($0), $1{{$}}
390; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}}
391; CHECK-NEXT: return $pop1{{$}}
392define i32 @xor_sext_i8_i32(i8* %p, i32 %v) {
393  %t = trunc i32 %v to i8
394  %old = atomicrmw xor i8* %p, i8 %t seq_cst
395  %e = sext i8 %old to i32
396  ret i32 %e
397}
398
399; CHECK-LABEL: xor_sext_i16_i32:
400; CHECK-NEXT: .param i32, i32{{$}}
401; CHECK: i32.atomic.rmw16_u.xor $push0=, 0($0), $1{{$}}
402; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}}
403; CHECK-NEXT: return $pop1{{$}}
404define i32 @xor_sext_i16_i32(i16* %p, i32 %v) {
405  %t = trunc i32 %v to i16
406  %old = atomicrmw xor i16* %p, i16 %t seq_cst
407  %e = sext i16 %old to i32
408  ret i32 %e
409}
410
411; CHECK-LABEL: xor_sext_i8_i64:
412; CHECK-NEXT: .param i32, i64{{$}}
413; CHECK: i64.atomic.rmw8_u.xor $push0=, 0($0), $1{{$}}
414; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}}
415; CHECK-NEXT: return $pop1{{$}}
416define i64 @xor_sext_i8_i64(i8* %p, i64 %v) {
417  %t = trunc i64 %v to i8
418  %old = atomicrmw xor i8* %p, i8 %t seq_cst
419  %e = sext i8 %old to i64
420  ret i64 %e
421}
422
423; CHECK-LABEL: xor_sext_i16_i64:
424; CHECK-NEXT: .param i32, i64{{$}}
425; CHECK: i64.atomic.rmw16_u.xor $push0=, 0($0), $1{{$}}
426; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}}
427; CHECK-NEXT: return $pop1{{$}}
428define i64 @xor_sext_i16_i64(i16* %p, i64 %v) {
429  %t = trunc i64 %v to i16
430  %old = atomicrmw xor i16* %p, i16 %t seq_cst
431  %e = sext i16 %old to i64
432  ret i64 %e
433}
434
435; 32->64 sext rmw gets selected as i32.atomic.rmw.xor, i64_extend_s/i32
436; CHECK-LABEL: xor_sext_i32_i64:
437; CHECK-NEXT: .param i32, i64{{$}}
438; CHECK: i32.wrap/i64 $push0=, $1{{$}}
439; CHECK: i32.atomic.rmw.xor $push1=, 0($0), $pop0{{$}}
440; CHECK-NEXT: i64.extend_s/i32 $push2=, $pop1{{$}}
441; CHECK-NEXT: return $pop2{{$}}
442define i64 @xor_sext_i32_i64(i32* %p, i64 %v) {
443  %t = trunc i64 %v to i32
444  %old = atomicrmw xor i32* %p, i32 %t seq_cst
445  %e = sext i32 %old to i64
446  ret i64 %e
447}
448
449; xchg
450
451; CHECK-LABEL: xchg_sext_i8_i32:
452; CHECK-NEXT: .param i32, i32{{$}}
453; CHECK: i32.atomic.rmw8_u.xchg $push0=, 0($0), $1{{$}}
454; CHECK-NEXT: i32.extend8_s $push1=, $pop0{{$}}
455; CHECK-NEXT: return $pop1{{$}}
456define i32 @xchg_sext_i8_i32(i8* %p, i32 %v) {
457  %t = trunc i32 %v to i8
458  %old = atomicrmw xchg i8* %p, i8 %t seq_cst
459  %e = sext i8 %old to i32
460  ret i32 %e
461}
462
463; CHECK-LABEL: xchg_sext_i16_i32:
464; CHECK-NEXT: .param i32, i32{{$}}
465; CHECK: i32.atomic.rmw16_u.xchg $push0=, 0($0), $1{{$}}
466; CHECK-NEXT: i32.extend16_s $push1=, $pop0{{$}}
467; CHECK-NEXT: return $pop1{{$}}
468define i32 @xchg_sext_i16_i32(i16* %p, i32 %v) {
469  %t = trunc i32 %v to i16
470  %old = atomicrmw xchg i16* %p, i16 %t seq_cst
471  %e = sext i16 %old to i32
472  ret i32 %e
473}
474
475; CHECK-LABEL: xchg_sext_i8_i64:
476; CHECK-NEXT: .param i32, i64{{$}}
477; CHECK: i64.atomic.rmw8_u.xchg $push0=, 0($0), $1{{$}}
478; CHECK-NEXT: i64.extend8_s $push1=, $pop0{{$}}
479; CHECK-NEXT: return $pop1{{$}}
480define i64 @xchg_sext_i8_i64(i8* %p, i64 %v) {
481  %t = trunc i64 %v to i8
482  %old = atomicrmw xchg i8* %p, i8 %t seq_cst
483  %e = sext i8 %old to i64
484  ret i64 %e
485}
486
487; CHECK-LABEL: xchg_sext_i16_i64:
488; CHECK-NEXT: .param i32, i64{{$}}
489; CHECK: i64.atomic.rmw16_u.xchg $push0=, 0($0), $1{{$}}
490; CHECK-NEXT: i64.extend16_s $push1=, $pop0{{$}}
491; CHECK-NEXT: return $pop1{{$}}
492define i64 @xchg_sext_i16_i64(i16* %p, i64 %v) {
493  %t = trunc i64 %v to i16
494  %old = atomicrmw xchg i16* %p, i16 %t seq_cst
495  %e = sext i16 %old to i64
496  ret i64 %e
497}
498
499; 32->64 sext rmw gets selected as i32.atomic.rmw.xchg, i64_extend_s/i32
500; CHECK-LABEL: xchg_sext_i32_i64:
501; CHECK-NEXT: .param i32, i64{{$}}
502; CHECK: i32.wrap/i64 $push0=, $1{{$}}
503; CHECK: i32.atomic.rmw.xchg $push1=, 0($0), $pop0{{$}}
504; CHECK-NEXT: i64.extend_s/i32 $push2=, $pop1{{$}}
505; CHECK-NEXT: return $pop2{{$}}
506define i64 @xchg_sext_i32_i64(i32* %p, i64 %v) {
507  %t = trunc i64 %v to i32
508  %old = atomicrmw xchg i32* %p, i32 %t seq_cst
509  %e = sext i32 %old to i64
510  ret i64 %e
511}
512
513;===----------------------------------------------------------------------------
514; Atomic truncating & zero-extending RMWs
515;===----------------------------------------------------------------------------
516
517; add
518
519; CHECK-LABEL: add_zext_i8_i32:
520; CHECK-NEXT: .param i32, i32{{$}}
521; CHECK: i32.atomic.rmw8_u.add $push0=, 0($0), $1{{$}}
522; CHECK-NEXT: return $pop0{{$}}
523define i32 @add_zext_i8_i32(i8* %p, i32 %v) {
524  %t = trunc i32 %v to i8
525  %old = atomicrmw add i8* %p, i8 %t seq_cst
526  %e = zext i8 %old to i32
527  ret i32 %e
528}
529
530; CHECK-LABEL: add_zext_i16_i32:
531; CHECK-NEXT: .param i32, i32{{$}}
532; CHECK: i32.atomic.rmw16_u.add $push0=, 0($0), $1{{$}}
533; CHECK-NEXT: return $pop0{{$}}
534define i32 @add_zext_i16_i32(i16* %p, i32 %v) {
535  %t = trunc i32 %v to i16
536  %old = atomicrmw add i16* %p, i16 %t seq_cst
537  %e = zext i16 %old to i32
538  ret i32 %e
539}
540
541; CHECK-LABEL: add_zext_i8_i64:
542; CHECK-NEXT: .param i32, i64{{$}}
543; CHECK: i64.atomic.rmw8_u.add $push0=, 0($0), $1{{$}}
544; CHECK-NEXT: return $pop0{{$}}
545define i64 @add_zext_i8_i64(i8* %p, i64 %v) {
546  %t = trunc i64 %v to i8
547  %old = atomicrmw add i8* %p, i8 %t seq_cst
548  %e = zext i8 %old to i64
549  ret i64 %e
550}
551
552; CHECK-LABEL: add_zext_i16_i64:
553; CHECK-NEXT: .param i32, i64{{$}}
554; CHECK: i64.atomic.rmw16_u.add $push0=, 0($0), $1{{$}}
555; CHECK-NEXT: return $pop0{{$}}
556define i64 @add_zext_i16_i64(i16* %p, i64 %v) {
557  %t = trunc i64 %v to i16
558  %old = atomicrmw add i16* %p, i16 %t seq_cst
559  %e = zext i16 %old to i64
560  ret i64 %e
561}
562
563; CHECK-LABEL: add_zext_i32_i64:
564; CHECK-NEXT: .param i32, i64{{$}}
565; CHECK: i64.atomic.rmw32_u.add $push0=, 0($0), $1{{$}}
566; CHECK-NEXT: return $pop0{{$}}
567define i64 @add_zext_i32_i64(i32* %p, i64 %v) {
568  %t = trunc i64 %v to i32
569  %old = atomicrmw add i32* %p, i32 %t seq_cst
570  %e = zext i32 %old to i64
571  ret i64 %e
572}
573
574; sub
575
576; CHECK-LABEL: sub_zext_i8_i32:
577; CHECK-NEXT: .param i32, i32{{$}}
578; CHECK: i32.atomic.rmw8_u.sub $push0=, 0($0), $1{{$}}
579; CHECK-NEXT: return $pop0{{$}}
580define i32 @sub_zext_i8_i32(i8* %p, i32 %v) {
581  %t = trunc i32 %v to i8
582  %old = atomicrmw sub i8* %p, i8 %t seq_cst
583  %e = zext i8 %old to i32
584  ret i32 %e
585}
586
587; CHECK-LABEL: sub_zext_i16_i32:
588; CHECK-NEXT: .param i32, i32{{$}}
589; CHECK: i32.atomic.rmw16_u.sub $push0=, 0($0), $1{{$}}
590; CHECK-NEXT: return $pop0{{$}}
591define i32 @sub_zext_i16_i32(i16* %p, i32 %v) {
592  %t = trunc i32 %v to i16
593  %old = atomicrmw sub i16* %p, i16 %t seq_cst
594  %e = zext i16 %old to i32
595  ret i32 %e
596}
597
598; CHECK-LABEL: sub_zext_i8_i64:
599; CHECK-NEXT: .param i32, i64{{$}}
600; CHECK: i64.atomic.rmw8_u.sub $push0=, 0($0), $1{{$}}
601; CHECK-NEXT: return $pop0{{$}}
602define i64 @sub_zext_i8_i64(i8* %p, i64 %v) {
603  %t = trunc i64 %v to i8
604  %old = atomicrmw sub i8* %p, i8 %t seq_cst
605  %e = zext i8 %old to i64
606  ret i64 %e
607}
608
609; CHECK-LABEL: sub_zext_i16_i64:
610; CHECK-NEXT: .param i32, i64{{$}}
611; CHECK: i64.atomic.rmw16_u.sub $push0=, 0($0), $1{{$}}
612; CHECK-NEXT: return $pop0{{$}}
613define i64 @sub_zext_i16_i64(i16* %p, i64 %v) {
614  %t = trunc i64 %v to i16
615  %old = atomicrmw sub i16* %p, i16 %t seq_cst
616  %e = zext i16 %old to i64
617  ret i64 %e
618}
619
620; CHECK-LABEL: sub_zext_i32_i64:
621; CHECK-NEXT: .param i32, i64{{$}}
622; CHECK: i64.atomic.rmw32_u.sub $push0=, 0($0), $1{{$}}
623; CHECK-NEXT: return $pop0{{$}}
624define i64 @sub_zext_i32_i64(i32* %p, i64 %v) {
625  %t = trunc i64 %v to i32
626  %old = atomicrmw sub i32* %p, i32 %t seq_cst
627  %e = zext i32 %old to i64
628  ret i64 %e
629}
630
631; and
632
633; CHECK-LABEL: and_zext_i8_i32:
634; CHECK-NEXT: .param i32, i32{{$}}
635; CHECK: i32.atomic.rmw8_u.and $push0=, 0($0), $1{{$}}
636; CHECK-NEXT: return $pop0{{$}}
637define i32 @and_zext_i8_i32(i8* %p, i32 %v) {
638  %t = trunc i32 %v to i8
639  %old = atomicrmw and i8* %p, i8 %t seq_cst
640  %e = zext i8 %old to i32
641  ret i32 %e
642}
643
644; CHECK-LABEL: and_zext_i16_i32:
645; CHECK-NEXT: .param i32, i32{{$}}
646; CHECK: i32.atomic.rmw16_u.and $push0=, 0($0), $1{{$}}
647; CHECK-NEXT: return $pop0{{$}}
648define i32 @and_zext_i16_i32(i16* %p, i32 %v) {
649  %t = trunc i32 %v to i16
650  %old = atomicrmw and i16* %p, i16 %t seq_cst
651  %e = zext i16 %old to i32
652  ret i32 %e
653}
654
655; CHECK-LABEL: and_zext_i8_i64:
656; CHECK-NEXT: .param i32, i64{{$}}
657; CHECK: i64.atomic.rmw8_u.and $push0=, 0($0), $1{{$}}
658; CHECK-NEXT: return $pop0{{$}}
659define i64 @and_zext_i8_i64(i8* %p, i64 %v) {
660  %t = trunc i64 %v to i8
661  %old = atomicrmw and i8* %p, i8 %t seq_cst
662  %e = zext i8 %old to i64
663  ret i64 %e
664}
665
666; CHECK-LABEL: and_zext_i16_i64:
667; CHECK-NEXT: .param i32, i64{{$}}
668; CHECK: i64.atomic.rmw16_u.and $push0=, 0($0), $1{{$}}
669; CHECK-NEXT: return $pop0{{$}}
670define i64 @and_zext_i16_i64(i16* %p, i64 %v) {
671  %t = trunc i64 %v to i16
672  %old = atomicrmw and i16* %p, i16 %t seq_cst
673  %e = zext i16 %old to i64
674  ret i64 %e
675}
676
677; CHECK-LABEL: and_zext_i32_i64:
678; CHECK-NEXT: .param i32, i64{{$}}
679; CHECK: i64.atomic.rmw32_u.and $push0=, 0($0), $1{{$}}
680; CHECK-NEXT: return $pop0{{$}}
681define i64 @and_zext_i32_i64(i32* %p, i64 %v) {
682  %t = trunc i64 %v to i32
683  %old = atomicrmw and i32* %p, i32 %t seq_cst
684  %e = zext i32 %old to i64
685  ret i64 %e
686}
687
688; or
689
690; CHECK-LABEL: or_zext_i8_i32:
691; CHECK-NEXT: .param i32, i32{{$}}
692; CHECK: i32.atomic.rmw8_u.or $push0=, 0($0), $1{{$}}
693; CHECK-NEXT: return $pop0{{$}}
694define i32 @or_zext_i8_i32(i8* %p, i32 %v) {
695  %t = trunc i32 %v to i8
696  %old = atomicrmw or i8* %p, i8 %t seq_cst
697  %e = zext i8 %old to i32
698  ret i32 %e
699}
700
701; CHECK-LABEL: or_zext_i16_i32:
702; CHECK-NEXT: .param i32, i32{{$}}
703; CHECK: i32.atomic.rmw16_u.or $push0=, 0($0), $1{{$}}
704; CHECK-NEXT: return $pop0{{$}}
705define i32 @or_zext_i16_i32(i16* %p, i32 %v) {
706  %t = trunc i32 %v to i16
707  %old = atomicrmw or i16* %p, i16 %t seq_cst
708  %e = zext i16 %old to i32
709  ret i32 %e
710}
711
712; CHECK-LABEL: or_zext_i8_i64:
713; CHECK-NEXT: .param i32, i64{{$}}
714; CHECK: i64.atomic.rmw8_u.or $push0=, 0($0), $1{{$}}
715; CHECK-NEXT: return $pop0{{$}}
716define i64 @or_zext_i8_i64(i8* %p, i64 %v) {
717  %t = trunc i64 %v to i8
718  %old = atomicrmw or i8* %p, i8 %t seq_cst
719  %e = zext i8 %old to i64
720  ret i64 %e
721}
722
723; CHECK-LABEL: or_zext_i16_i64:
724; CHECK-NEXT: .param i32, i64{{$}}
725; CHECK: i64.atomic.rmw16_u.or $push0=, 0($0), $1{{$}}
726; CHECK-NEXT: return $pop0{{$}}
727define i64 @or_zext_i16_i64(i16* %p, i64 %v) {
728  %t = trunc i64 %v to i16
729  %old = atomicrmw or i16* %p, i16 %t seq_cst
730  %e = zext i16 %old to i64
731  ret i64 %e
732}
733
734; CHECK-LABEL: or_zext_i32_i64:
735; CHECK-NEXT: .param i32, i64{{$}}
736; CHECK: i64.atomic.rmw32_u.or $push0=, 0($0), $1{{$}}
737; CHECK-NEXT: return $pop0{{$}}
738define i64 @or_zext_i32_i64(i32* %p, i64 %v) {
739  %t = trunc i64 %v to i32
740  %old = atomicrmw or i32* %p, i32 %t seq_cst
741  %e = zext i32 %old to i64
742  ret i64 %e
743}
744
745; xor
746
747; CHECK-LABEL: xor_zext_i8_i32:
748; CHECK-NEXT: .param i32, i32{{$}}
749; CHECK: i32.atomic.rmw8_u.xor $push0=, 0($0), $1{{$}}
750; CHECK-NEXT: return $pop0{{$}}
751define i32 @xor_zext_i8_i32(i8* %p, i32 %v) {
752  %t = trunc i32 %v to i8
753  %old = atomicrmw xor i8* %p, i8 %t seq_cst
754  %e = zext i8 %old to i32
755  ret i32 %e
756}
757
758; CHECK-LABEL: xor_zext_i16_i32:
759; CHECK-NEXT: .param i32, i32{{$}}
760; CHECK: i32.atomic.rmw16_u.xor $push0=, 0($0), $1{{$}}
761; CHECK-NEXT: return $pop0{{$}}
762define i32 @xor_zext_i16_i32(i16* %p, i32 %v) {
763  %t = trunc i32 %v to i16
764  %old = atomicrmw xor i16* %p, i16 %t seq_cst
765  %e = zext i16 %old to i32
766  ret i32 %e
767}
768
769; CHECK-LABEL: xor_zext_i8_i64:
770; CHECK-NEXT: .param i32, i64{{$}}
771; CHECK: i64.atomic.rmw8_u.xor $push0=, 0($0), $1{{$}}
772; CHECK-NEXT: return $pop0{{$}}
773define i64 @xor_zext_i8_i64(i8* %p, i64 %v) {
774  %t = trunc i64 %v to i8
775  %old = atomicrmw xor i8* %p, i8 %t seq_cst
776  %e = zext i8 %old to i64
777  ret i64 %e
778}
779
780; CHECK-LABEL: xor_zext_i16_i64:
781; CHECK-NEXT: .param i32, i64{{$}}
782; CHECK: i64.atomic.rmw16_u.xor $push0=, 0($0), $1{{$}}
783; CHECK-NEXT: return $pop0{{$}}
784define i64 @xor_zext_i16_i64(i16* %p, i64 %v) {
785  %t = trunc i64 %v to i16
786  %old = atomicrmw xor i16* %p, i16 %t seq_cst
787  %e = zext i16 %old to i64
788  ret i64 %e
789}
790
791; CHECK-LABEL: xor_zext_i32_i64:
792; CHECK-NEXT: .param i32, i64{{$}}
793; CHECK: i64.atomic.rmw32_u.xor $push0=, 0($0), $1{{$}}
794; CHECK-NEXT: return $pop0{{$}}
795define i64 @xor_zext_i32_i64(i32* %p, i64 %v) {
796  %t = trunc i64 %v to i32
797  %old = atomicrmw xor i32* %p, i32 %t seq_cst
798  %e = zext i32 %old to i64
799  ret i64 %e
800}
801
802; xchg
803
804; CHECK-LABEL: xchg_zext_i8_i32:
805; CHECK-NEXT: .param i32, i32{{$}}
806; CHECK: i32.atomic.rmw8_u.xchg $push0=, 0($0), $1{{$}}
807; CHECK-NEXT: return $pop0{{$}}
808define i32 @xchg_zext_i8_i32(i8* %p, i32 %v) {
809  %t = trunc i32 %v to i8
810  %old = atomicrmw xchg i8* %p, i8 %t seq_cst
811  %e = zext i8 %old to i32
812  ret i32 %e
813}
814
815; CHECK-LABEL: xchg_zext_i16_i32:
816; CHECK-NEXT: .param i32, i32{{$}}
817; CHECK: i32.atomic.rmw16_u.xchg $push0=, 0($0), $1{{$}}
818; CHECK-NEXT: return $pop0{{$}}
819define i32 @xchg_zext_i16_i32(i16* %p, i32 %v) {
820  %t = trunc i32 %v to i16
821  %old = atomicrmw xchg i16* %p, i16 %t seq_cst
822  %e = zext i16 %old to i32
823  ret i32 %e
824}
825
826; CHECK-LABEL: xchg_zext_i8_i64:
827; CHECK-NEXT: .param i32, i64{{$}}
828; CHECK: i64.atomic.rmw8_u.xchg $push0=, 0($0), $1{{$}}
829; CHECK-NEXT: return $pop0{{$}}
830define i64 @xchg_zext_i8_i64(i8* %p, i64 %v) {
831  %t = trunc i64 %v to i8
832  %old = atomicrmw xchg i8* %p, i8 %t seq_cst
833  %e = zext i8 %old to i64
834  ret i64 %e
835}
836
837; CHECK-LABEL: xchg_zext_i16_i64:
838; CHECK-NEXT: .param i32, i64{{$}}
839; CHECK: i64.atomic.rmw16_u.xchg $push0=, 0($0), $1{{$}}
840; CHECK-NEXT: return $pop0{{$}}
841define i64 @xchg_zext_i16_i64(i16* %p, i64 %v) {
842  %t = trunc i64 %v to i16
843  %old = atomicrmw xchg i16* %p, i16 %t seq_cst
844  %e = zext i16 %old to i64
845  ret i64 %e
846}
847
848; CHECK-LABEL: xchg_zext_i32_i64:
849; CHECK-NEXT: .param i32, i64{{$}}
850; CHECK: i64.atomic.rmw32_u.xchg $push0=, 0($0), $1{{$}}
851; CHECK-NEXT: return $pop0{{$}}
852define i64 @xchg_zext_i32_i64(i32* %p, i64 %v) {
853  %t = trunc i64 %v to i32
854  %old = atomicrmw xchg i32* %p, i32 %t seq_cst
855  %e = zext i32 %old to i64
856  ret i64 %e
857}
858