xref: /llvm-project/llvm/test/CodeGen/WebAssembly/atomic-mem-consistency.ll (revision 73856247eef35f5336e485dc009842a5b991c421)
1; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt
2; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+atomics,+sign-ext | FileCheck %s
3
4; Currently all wasm atomic memory access instructions are sequentially
5; consistent, so even if LLVM IR specifies weaker orderings than that, we
6; should upgrade them to sequential ordering and treat them in the same way.
7
8target triple = "wasm32-unknown-unknown"
9
10;===----------------------------------------------------------------------------
11; Atomic loads
12;===----------------------------------------------------------------------------
13
14; The 'release' and 'acq_rel' orderings are not valid on load instructions.
15
16; CHECK-LABEL: load_i32_unordered:
17; CHECK: i32.atomic.load $push0=, 0($0){{$}}
18; CHECK-NEXT: return $pop0{{$}}
19define i32 @load_i32_unordered(ptr %p) {
20  %v = load atomic i32, ptr %p unordered, align 4
21  ret i32 %v
22}
23
24; CHECK-LABEL: load_i32_monotonic:
25; CHECK: i32.atomic.load $push0=, 0($0){{$}}
26; CHECK-NEXT: return $pop0{{$}}
27define i32 @load_i32_monotonic(ptr %p) {
28  %v = load atomic i32, ptr %p monotonic, align 4
29  ret i32 %v
30}
31
32; CHECK-LABEL: load_i32_acquire:
33; CHECK: i32.atomic.load $push0=, 0($0){{$}}
34; CHECK-NEXT: return $pop0{{$}}
35define i32 @load_i32_acquire(ptr %p) {
36  %v = load atomic i32, ptr %p acquire, align 4
37  ret i32 %v
38}
39
40; CHECK-LABEL: load_i32_seq_cst:
41; CHECK: i32.atomic.load $push0=, 0($0){{$}}
42; CHECK-NEXT: return $pop0{{$}}
43define i32 @load_i32_seq_cst(ptr %p) {
44  %v = load atomic i32, ptr %p seq_cst, align 4
45  ret i32 %v
46}
47
48;===----------------------------------------------------------------------------
49; Atomic stores
50;===----------------------------------------------------------------------------
51
52; The 'acquire' and 'acq_rel' orderings aren’t valid on store instructions.
53
54; CHECK-LABEL: store_i32_unordered:
55; CHECK-NEXT: .functype store_i32_unordered (i32, i32) -> (){{$}}
56; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
57; CHECK-NEXT: return{{$}}
58define void @store_i32_unordered(ptr %p, i32 %v) {
59  store atomic i32 %v, ptr %p unordered, align 4
60  ret void
61}
62
63; CHECK-LABEL: store_i32_monotonic:
64; CHECK-NEXT: .functype store_i32_monotonic (i32, i32) -> (){{$}}
65; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
66; CHECK-NEXT: return{{$}}
67define void @store_i32_monotonic(ptr %p, i32 %v) {
68  store atomic i32 %v, ptr %p monotonic, align 4
69  ret void
70}
71
72; CHECK-LABEL: store_i32_release:
73; CHECK-NEXT: .functype store_i32_release (i32, i32) -> (){{$}}
74; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
75; CHECK-NEXT: return{{$}}
76define void @store_i32_release(ptr %p, i32 %v) {
77  store atomic i32 %v, ptr %p release, align 4
78  ret void
79}
80
81; CHECK-LABEL: store_i32_seq_cst:
82; CHECK-NEXT: .functype store_i32_seq_cst (i32, i32) -> (){{$}}
83; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
84; CHECK-NEXT: return{{$}}
85define void @store_i32_seq_cst(ptr %p, i32 %v) {
86  store atomic i32 %v, ptr %p seq_cst, align 4
87  ret void
88}
89
90;===----------------------------------------------------------------------------
91; Atomic read-modify-writes
92;===----------------------------------------------------------------------------
93
94; Out of several binary RMW instructions, here we test 'add' as an example.
95; The 'unordered' ordering is not valid on atomicrmw instructions.
96
97; CHECK-LABEL: add_i32_monotonic:
98; CHECK-NEXT: .functype add_i32_monotonic (i32, i32) -> (i32){{$}}
99; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
100; CHECK-NEXT: return $pop0{{$}}
101define i32 @add_i32_monotonic(ptr %p, i32 %v) {
102  %old = atomicrmw add ptr %p, i32 %v monotonic
103  ret i32 %old
104}
105
106; CHECK-LABEL: add_i32_acquire:
107; CHECK-NEXT: .functype add_i32_acquire (i32, i32) -> (i32){{$}}
108; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
109; CHECK-NEXT: return $pop0{{$}}
110define i32 @add_i32_acquire(ptr %p, i32 %v) {
111  %old = atomicrmw add ptr %p, i32 %v acquire
112  ret i32 %old
113}
114
115; CHECK-LABEL: add_i32_release:
116; CHECK-NEXT: .functype add_i32_release (i32, i32) -> (i32){{$}}
117; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
118; CHECK-NEXT: return $pop0{{$}}
119define i32 @add_i32_release(ptr %p, i32 %v) {
120  %old = atomicrmw add ptr %p, i32 %v release
121  ret i32 %old
122}
123
124; CHECK-LABEL: add_i32_acq_rel:
125; CHECK-NEXT: .functype add_i32_acq_rel (i32, i32) -> (i32){{$}}
126; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
127; CHECK-NEXT: return $pop0{{$}}
128define i32 @add_i32_acq_rel(ptr %p, i32 %v) {
129  %old = atomicrmw add ptr %p, i32 %v acq_rel
130  ret i32 %old
131}
132
133; CHECK-LABEL: add_i32_seq_cst:
134; CHECK-NEXT: .functype add_i32_seq_cst (i32, i32) -> (i32){{$}}
135; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
136; CHECK-NEXT: return $pop0{{$}}
137define i32 @add_i32_seq_cst(ptr %p, i32 %v) {
138  %old = atomicrmw add ptr %p, i32 %v seq_cst
139  ret i32 %old
140}
141
142; Ternary RMW instruction: cmpxchg
143; The success and failure ordering arguments specify how this cmpxchg
144; synchronizes with other atomic operations. Both ordering parameters must be at
145; least monotonic, the ordering constraint on failure must be no stronger than
146; that on success, and the failure ordering cannot be either release or acq_rel.
147
148; CHECK-LABEL: cmpxchg_i32_monotonic_monotonic:
149; CHECK-NEXT: .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32){{$}}
150; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
151; CHECK-NEXT: return $pop0{{$}}
152define i32 @cmpxchg_i32_monotonic_monotonic(ptr %p, i32 %exp, i32 %new) {
153  %pair = cmpxchg ptr %p, i32 %exp, i32 %new monotonic monotonic
154  %old = extractvalue { i32, i1 } %pair, 0
155  ret i32 %old
156}
157
158; CHECK-LABEL: cmpxchg_i32_acquire_monotonic:
159; CHECK-NEXT: .functype cmpxchg_i32_acquire_monotonic (i32, i32, i32) -> (i32){{$}}
160; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
161; CHECK-NEXT: return $pop0{{$}}
162define i32 @cmpxchg_i32_acquire_monotonic(ptr %p, i32 %exp, i32 %new) {
163  %pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire monotonic
164  %old = extractvalue { i32, i1 } %pair, 0
165  ret i32 %old
166}
167
168; CHECK-LABEL: cmpxchg_i32_release_monotonic:
169; CHECK-NEXT: .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32){{$}}
170; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
171; CHECK-NEXT: return $pop0{{$}}
172define i32 @cmpxchg_i32_release_monotonic(ptr %p, i32 %exp, i32 %new) {
173  %pair = cmpxchg ptr %p, i32 %exp, i32 %new release monotonic
174  %old = extractvalue { i32, i1 } %pair, 0
175  ret i32 %old
176}
177
178; CHECK-LABEL: cmpxchg_i32_acq_rel_monotonic:
179; CHECK-NEXT: .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32){{$}}
180; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
181; CHECK-NEXT: return $pop0{{$}}
182define i32 @cmpxchg_i32_acq_rel_monotonic(ptr %p, i32 %exp, i32 %new) {
183  %pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel monotonic
184  %old = extractvalue { i32, i1 } %pair, 0
185  ret i32 %old
186}
187
188; CHECK-LABEL: cmpxchg_i32_seq_cst_monotonic:
189; CHECK-NEXT: .functype cmpxchg_i32_seq_cst_monotonic (i32, i32, i32) -> (i32){{$}}
190; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
191; CHECK-NEXT: return $pop0{{$}}
192define i32 @cmpxchg_i32_seq_cst_monotonic(ptr %p, i32 %exp, i32 %new) {
193  %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst monotonic
194  %old = extractvalue { i32, i1 } %pair, 0
195  ret i32 %old
196}
197
198; CHECK-LABEL: cmpxchg_i32_acquire_acquire:
199; CHECK-NEXT: .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32){{$}}
200; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
201; CHECK-NEXT: return $pop0{{$}}
202define i32 @cmpxchg_i32_acquire_acquire(ptr %p, i32 %exp, i32 %new) {
203  %pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire acquire
204  %old = extractvalue { i32, i1 } %pair, 0
205  ret i32 %old
206}
207
208; CHECK-LABEL: cmpxchg_i32_release_acquire:
209; CHECK-NEXT: .functype cmpxchg_i32_release_acquire (i32, i32, i32) -> (i32){{$}}
210; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
211; CHECK-NEXT: return $pop0{{$}}
212define i32 @cmpxchg_i32_release_acquire(ptr %p, i32 %exp, i32 %new) {
213  %pair = cmpxchg ptr %p, i32 %exp, i32 %new release acquire
214  %old = extractvalue { i32, i1 } %pair, 0
215  ret i32 %old
216}
217
218; CHECK-LABEL: cmpxchg_i32_acq_rel_acquire:
219; CHECK-NEXT: .functype cmpxchg_i32_acq_rel_acquire (i32, i32, i32) -> (i32){{$}}
220; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
221; CHECK-NEXT: return $pop0{{$}}
222define i32 @cmpxchg_i32_acq_rel_acquire(ptr %p, i32 %exp, i32 %new) {
223  %pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel acquire
224  %old = extractvalue { i32, i1 } %pair, 0
225  ret i32 %old
226}
227
228; CHECK-LABEL: cmpxchg_i32_seq_cst_acquire:
229; CHECK-NEXT: .functype cmpxchg_i32_seq_cst_acquire (i32, i32, i32) -> (i32){{$}}
230; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
231; CHECK-NEXT: return $pop0{{$}}
232define i32 @cmpxchg_i32_seq_cst_acquire(ptr %p, i32 %exp, i32 %new) {
233  %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst acquire
234  %old = extractvalue { i32, i1 } %pair, 0
235  ret i32 %old
236}
237
238; CHECK-LABEL: cmpxchg_i32_seq_cst_seq_cst:
239; CHECK-NEXT: .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32){{$}}
240; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
241; CHECK-NEXT: return $pop0{{$}}
242define i32 @cmpxchg_i32_seq_cst_seq_cst(ptr %p, i32 %exp, i32 %new) {
243  %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst
244  %old = extractvalue { i32, i1 } %pair, 0
245  ret i32 %old
246}
247