1 // WebAssemblyInstrAtomics.td-WebAssembly Atomic codegen support-*- tablegen -*-
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 /// WebAssembly Atomic operand code-gen constructs.
12 //===----------------------------------------------------------------------===//
14 let UseNamedOperandTable = 1 in
15 multiclass ATOMIC_I<dag oops_r, dag iops_r, dag oops_s, dag iops_s,
16 list<dag> pattern_r, string asmstr_r,
17 string asmstr_s, bits<32> atomic_op,
19 defm "" : I<oops_r, iops_r, oops_s, iops_s, pattern_r, asmstr_r, asmstr_s,
20 !or(0xfe00, !and(0xff, atomic_op)), is64>,
21 Requires<[HasAtomics]>;
24 multiclass ATOMIC_NRI<dag oops, dag iops, list<dag> pattern, string asmstr = "",
25 bits<32> atomic_op = -1> {
26 defm "" : NRI<oops, iops, pattern, asmstr,
27 !or(0xfe00, !and(0xff, atomic_op))>,
28 Requires<[HasAtomics]>;
31 //===----------------------------------------------------------------------===//
32 // Atomic wait / notify
33 //===----------------------------------------------------------------------===//
35 let hasSideEffects = 1 in {
36 defm MEMORY_ATOMIC_NOTIFY_A32 :
37 ATOMIC_I<(outs I32:$dst),
38 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$count),
39 (outs), (ins P2Align:$p2align, offset32_op:$off), [],
40 "memory.atomic.notify \t$dst, ${off}(${addr})${p2align}, $count",
41 "memory.atomic.notify \t${off}${p2align}", 0x00, false>;
42 defm MEMORY_ATOMIC_NOTIFY_A64 :
43 ATOMIC_I<(outs I32:$dst),
44 (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$count),
45 (outs), (ins P2Align:$p2align, offset64_op:$off), [],
46 "memory.atomic.notify \t$dst, ${off}(${addr})${p2align}, $count",
47 "memory.atomic.notify \t${off}${p2align}", 0x00, true>;
49 defm MEMORY_ATOMIC_WAIT32_A32 :
50 ATOMIC_I<(outs I32:$dst),
51 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$exp,
53 (outs), (ins P2Align:$p2align, offset32_op:$off), [],
54 "memory.atomic.wait32 \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
55 "memory.atomic.wait32 \t${off}${p2align}", 0x01, false>;
56 defm MEMORY_ATOMIC_WAIT32_A64 :
57 ATOMIC_I<(outs I32:$dst),
58 (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$exp,
60 (outs), (ins P2Align:$p2align, offset64_op:$off), [],
61 "memory.atomic.wait32 \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
62 "memory.atomic.wait32 \t${off}${p2align}", 0x01, true>;
63 defm MEMORY_ATOMIC_WAIT64_A32 :
64 ATOMIC_I<(outs I32:$dst),
65 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I64:$exp,
67 (outs), (ins P2Align:$p2align, offset32_op:$off), [],
68 "memory.atomic.wait64 \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
69 "memory.atomic.wait64 \t${off}${p2align}", 0x02, false>;
70 defm MEMORY_ATOMIC_WAIT64_A64 :
71 ATOMIC_I<(outs I32:$dst),
72 (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I64:$exp,
74 (outs), (ins P2Align:$p2align, offset64_op:$off), [],
75 "memory.atomic.wait64 \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
76 "memory.atomic.wait64 \t${off}${p2align}", 0x02, true>;
78 } // hasSideEffects = 1
81 Pat<(i32 (int_wasm_memory_atomic_notify (AddrOps32 offset32_op:$offset, I32:$addr), I32:$count)),
82 (MEMORY_ATOMIC_NOTIFY_A32 0, $offset, $addr, $count)>,
83 Requires<[HasAddr32, HasAtomics]>;
85 Pat<(i32 (int_wasm_memory_atomic_notify (AddrOps64 offset64_op:$offset, I64:$addr), I32:$count)),
86 (MEMORY_ATOMIC_NOTIFY_A64 0, $offset, $addr, $count)>,
87 Requires<[HasAddr64, HasAtomics]>;
90 multiclass WaitPat<ValueType ty, Intrinsic kind, string inst> {
92 Pat<(i32 (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$exp, I64:$timeout)),
93 (!cast<NI>(inst#_A32) 0, $offset, $addr, $exp, $timeout)>,
94 Requires<[HasAddr32, HasAtomics]>;
96 Pat<(i32 (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$exp, I64:$timeout)),
97 (!cast<NI>(inst#_A64) 0, $offset, $addr, $exp, $timeout)>,
98 Requires<[HasAddr64, HasAtomics]>;
101 defm : WaitPat<i32, int_wasm_memory_atomic_wait32, "MEMORY_ATOMIC_WAIT32">;
102 defm : WaitPat<i64, int_wasm_memory_atomic_wait64, "MEMORY_ATOMIC_WAIT64">;
104 //===----------------------------------------------------------------------===//
106 //===----------------------------------------------------------------------===//
108 // A compiler fence instruction that prevents reordering of instructions.
109 let Defs = [ARGUMENTS] in {
110 let isPseudo = 1, hasSideEffects = 1 in
111 defm COMPILER_FENCE : ATOMIC_NRI<(outs), (ins), [], "compiler_fence">;
112 let hasSideEffects = 1 in
113 defm ATOMIC_FENCE : ATOMIC_NRI<(outs), (ins i8imm:$flags), [], "atomic.fence",
115 } // Defs = [ARGUMENTS]
117 //===----------------------------------------------------------------------===//
119 //===----------------------------------------------------------------------===//
121 multiclass AtomicLoad<WebAssemblyRegClass rc, string name, int atomic_op> {
122 defm "" : WebAssemblyLoad<rc, name, !or(0xfe00, !and(0xff, atomic_op)),
126 defm ATOMIC_LOAD_I32 : AtomicLoad<I32, "i32.atomic.load", 0x10>;
127 defm ATOMIC_LOAD_I64 : AtomicLoad<I64, "i64.atomic.load", 0x11>;
130 defm : LoadPat<i32, atomic_load_32, "ATOMIC_LOAD_I32">;
131 defm : LoadPat<i64, atomic_load_64, "ATOMIC_LOAD_I64">;
133 // Extending loads. Note that there are only zero-extending atomic loads, no
134 // sign-extending loads.
135 defm ATOMIC_LOAD8_U_I32 : AtomicLoad<I32, "i32.atomic.load8_u", 0x12>;
136 defm ATOMIC_LOAD16_U_I32 : AtomicLoad<I32, "i32.atomic.load16_u", 0x13>;
137 defm ATOMIC_LOAD8_U_I64 : AtomicLoad<I64, "i64.atomic.load8_u", 0x14>;
138 defm ATOMIC_LOAD16_U_I64 : AtomicLoad<I64, "i64.atomic.load16_u", 0x15>;
139 defm ATOMIC_LOAD32_U_I64 : AtomicLoad<I64, "i64.atomic.load32_u", 0x16>;
141 // Fragments for extending loads. These are different from regular loads because
142 // the SDNodes are derived from AtomicSDNode rather than LoadSDNode and
143 // therefore don't have the extension type field. So instead of matching that,
144 // we match the patterns that the type legalizer expands them to.
146 // Unlike regular loads, extension to i64 is handled differently than i32.
147 // i64 (zext (i8 (atomic_load_8))) gets legalized to
148 // i64 (and (i64 (anyext (i32 (atomic_load_8)))), 255)
149 // Extension to i32 is elided by SelectionDAG as our atomic loads are
151 def zext_aload_8_64 :
152 PatFrag<(ops node:$addr),
153 (i64 (zext (i32 (atomic_load_8 node:$addr))))>;
154 def zext_aload_16_64 :
155 PatFrag<(ops node:$addr),
156 (i64 (zext (i32 (atomic_load_16 node:$addr))))>;
157 def zext_aload_32_64 :
158 PatFrag<(ops node:$addr),
159 (i64 (zext (i32 (atomic_load_32 node:$addr))))>;
161 // We don't have single sext atomic load instructions. So for sext loads, we
162 // match bare subword loads (for 32-bit results) and anyext loads (for 64-bit
163 // results) and select a zext load; the next instruction will be sext_inreg
164 // which is selected by itself.
165 def sext_aload_8_64 :
166 PatFrag<(ops node:$addr), (anyext (i32 (atomic_load_8 node:$addr)))>;
167 def sext_aload_16_64 :
168 PatFrag<(ops node:$addr), (anyext (i32 (atomic_load_16 node:$addr)))>;
170 // Select zero-extending loads
171 defm : LoadPat<i64, zext_aload_8_64, "ATOMIC_LOAD8_U_I64">;
172 defm : LoadPat<i64, zext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
173 defm : LoadPat<i64, zext_aload_32_64, "ATOMIC_LOAD32_U_I64">;
175 // Select sign-extending loads
176 defm : LoadPat<i32, atomic_load_8, "ATOMIC_LOAD8_U_I32">;
177 defm : LoadPat<i32, atomic_load_16, "ATOMIC_LOAD16_U_I32">;
178 defm : LoadPat<i64, sext_aload_8_64, "ATOMIC_LOAD8_U_I64">;
179 defm : LoadPat<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
180 // 32->64 sext load gets selected as i32.atomic.load, i64.extend_i32_s
183 //===----------------------------------------------------------------------===//
185 //===----------------------------------------------------------------------===//
187 multiclass AtomicStore<WebAssemblyRegClass rc, string name, int atomic_op> {
188 defm "" : WebAssemblyStore<rc, name, !or(0xfe00, !and(0xff, atomic_op)),
192 defm ATOMIC_STORE_I32 : AtomicStore<I32, "i32.atomic.store", 0x17>;
193 defm ATOMIC_STORE_I64 : AtomicStore<I64, "i64.atomic.store", 0x18>;
195 // We used to need an 'atomic' version of store patterns because store and atomic_store
196 // nodes have different operand orders.
198 // TODO: This is no longer true and atomic_store and store patterns
201 multiclass AStorePat<ValueType ty, PatFrag kind, string inst> {
202 def : Pat<(kind ty:$val, (AddrOps32 offset32_op:$offset, I32:$addr)),
203 (!cast<NI>(inst#_A32) 0, $offset, $addr, $val)>,
204 Requires<[HasAddr32, HasAtomics]>;
205 def : Pat<(kind ty:$val, (AddrOps64 offset64_op:$offset, I64:$addr)),
206 (!cast<NI>(inst#_A64) 0, $offset, $addr, $val)>,
207 Requires<[HasAddr64, HasAtomics]>;
209 defm : AStorePat<i32, atomic_store_32, "ATOMIC_STORE_I32">;
210 defm : AStorePat<i64, atomic_store_64, "ATOMIC_STORE_I64">;
212 // Truncating stores.
213 defm ATOMIC_STORE8_I32 : AtomicStore<I32, "i32.atomic.store8", 0x19>;
214 defm ATOMIC_STORE16_I32 : AtomicStore<I32, "i32.atomic.store16", 0x1a>;
215 defm ATOMIC_STORE8_I64 : AtomicStore<I64, "i64.atomic.store8", 0x1b>;
216 defm ATOMIC_STORE16_I64 : AtomicStore<I64, "i64.atomic.store16", 0x1c>;
217 defm ATOMIC_STORE32_I64 : AtomicStore<I64, "i64.atomic.store32", 0x1d>;
219 // Fragments for truncating stores.
221 // We don't have single truncating atomic store instructions. For 32-bit
222 // instructions, we just need to match bare atomic stores. On the other hand,
223 // truncating stores from i64 values are once truncated to i32 first.
224 class trunc_astore_64<PatFrag kind> :
225 PatFrag<(ops node:$val, node:$addr),
226 (kind (i32 (trunc (i64 node:$val))), node:$addr)>;
227 def trunc_astore_8_64 : trunc_astore_64<atomic_store_8>;
228 def trunc_astore_16_64 : trunc_astore_64<atomic_store_16>;
229 def trunc_astore_32_64 : trunc_astore_64<atomic_store_32>;
231 // Truncating stores with no constant offset
232 defm : AStorePat<i32, atomic_store_8, "ATOMIC_STORE8_I32">;
233 defm : AStorePat<i32, atomic_store_16, "ATOMIC_STORE16_I32">;
234 defm : AStorePat<i64, trunc_astore_8_64, "ATOMIC_STORE8_I64">;
235 defm : AStorePat<i64, trunc_astore_16_64, "ATOMIC_STORE16_I64">;
236 defm : AStorePat<i64, trunc_astore_32_64, "ATOMIC_STORE32_I64">;
238 //===----------------------------------------------------------------------===//
239 // Atomic binary read-modify-writes
240 //===----------------------------------------------------------------------===//
242 multiclass WebAssemblyBinRMW<WebAssemblyRegClass rc, string name,
245 ATOMIC_I<(outs rc:$dst),
246 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
247 (outs), (ins P2Align:$p2align, offset32_op:$off), [],
248 !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $val"),
249 !strconcat(name, "\t${off}${p2align}"), atomic_op, false>;
251 ATOMIC_I<(outs rc:$dst),
252 (ins P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$val),
253 (outs), (ins P2Align:$p2align, offset64_op:$off), [],
254 !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $val"),
255 !strconcat(name, "\t${off}${p2align}"), atomic_op, true>;
258 defm ATOMIC_RMW_ADD_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.add", 0x1e>;
259 defm ATOMIC_RMW_ADD_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.add", 0x1f>;
260 defm ATOMIC_RMW8_U_ADD_I32 :
261 WebAssemblyBinRMW<I32, "i32.atomic.rmw8.add_u", 0x20>;
262 defm ATOMIC_RMW16_U_ADD_I32 :
263 WebAssemblyBinRMW<I32, "i32.atomic.rmw16.add_u", 0x21>;
264 defm ATOMIC_RMW8_U_ADD_I64 :
265 WebAssemblyBinRMW<I64, "i64.atomic.rmw8.add_u", 0x22>;
266 defm ATOMIC_RMW16_U_ADD_I64 :
267 WebAssemblyBinRMW<I64, "i64.atomic.rmw16.add_u", 0x23>;
268 defm ATOMIC_RMW32_U_ADD_I64 :
269 WebAssemblyBinRMW<I64, "i64.atomic.rmw32.add_u", 0x24>;
271 defm ATOMIC_RMW_SUB_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.sub", 0x25>;
272 defm ATOMIC_RMW_SUB_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.sub", 0x26>;
273 defm ATOMIC_RMW8_U_SUB_I32 :
274 WebAssemblyBinRMW<I32, "i32.atomic.rmw8.sub_u", 0x27>;
275 defm ATOMIC_RMW16_U_SUB_I32 :
276 WebAssemblyBinRMW<I32, "i32.atomic.rmw16.sub_u", 0x28>;
277 defm ATOMIC_RMW8_U_SUB_I64 :
278 WebAssemblyBinRMW<I64, "i64.atomic.rmw8.sub_u", 0x29>;
279 defm ATOMIC_RMW16_U_SUB_I64 :
280 WebAssemblyBinRMW<I64, "i64.atomic.rmw16.sub_u", 0x2a>;
281 defm ATOMIC_RMW32_U_SUB_I64 :
282 WebAssemblyBinRMW<I64, "i64.atomic.rmw32.sub_u", 0x2b>;
284 defm ATOMIC_RMW_AND_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.and", 0x2c>;
285 defm ATOMIC_RMW_AND_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.and", 0x2d>;
286 defm ATOMIC_RMW8_U_AND_I32 :
287 WebAssemblyBinRMW<I32, "i32.atomic.rmw8.and_u", 0x2e>;
288 defm ATOMIC_RMW16_U_AND_I32 :
289 WebAssemblyBinRMW<I32, "i32.atomic.rmw16.and_u", 0x2f>;
290 defm ATOMIC_RMW8_U_AND_I64 :
291 WebAssemblyBinRMW<I64, "i64.atomic.rmw8.and_u", 0x30>;
292 defm ATOMIC_RMW16_U_AND_I64 :
293 WebAssemblyBinRMW<I64, "i64.atomic.rmw16.and_u", 0x31>;
294 defm ATOMIC_RMW32_U_AND_I64 :
295 WebAssemblyBinRMW<I64, "i64.atomic.rmw32.and_u", 0x32>;
297 defm ATOMIC_RMW_OR_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.or", 0x33>;
298 defm ATOMIC_RMW_OR_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.or", 0x34>;
299 defm ATOMIC_RMW8_U_OR_I32 :
300 WebAssemblyBinRMW<I32, "i32.atomic.rmw8.or_u", 0x35>;
301 defm ATOMIC_RMW16_U_OR_I32 :
302 WebAssemblyBinRMW<I32, "i32.atomic.rmw16.or_u", 0x36>;
303 defm ATOMIC_RMW8_U_OR_I64 :
304 WebAssemblyBinRMW<I64, "i64.atomic.rmw8.or_u", 0x37>;
305 defm ATOMIC_RMW16_U_OR_I64 :
306 WebAssemblyBinRMW<I64, "i64.atomic.rmw16.or_u", 0x38>;
307 defm ATOMIC_RMW32_U_OR_I64 :
308 WebAssemblyBinRMW<I64, "i64.atomic.rmw32.or_u", 0x39>;
310 defm ATOMIC_RMW_XOR_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.xor", 0x3a>;
311 defm ATOMIC_RMW_XOR_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.xor", 0x3b>;
312 defm ATOMIC_RMW8_U_XOR_I32 :
313 WebAssemblyBinRMW<I32, "i32.atomic.rmw8.xor_u", 0x3c>;
314 defm ATOMIC_RMW16_U_XOR_I32 :
315 WebAssemblyBinRMW<I32, "i32.atomic.rmw16.xor_u", 0x3d>;
316 defm ATOMIC_RMW8_U_XOR_I64 :
317 WebAssemblyBinRMW<I64, "i64.atomic.rmw8.xor_u", 0x3e>;
318 defm ATOMIC_RMW16_U_XOR_I64 :
319 WebAssemblyBinRMW<I64, "i64.atomic.rmw16.xor_u", 0x3f>;
320 defm ATOMIC_RMW32_U_XOR_I64 :
321 WebAssemblyBinRMW<I64, "i64.atomic.rmw32.xor_u", 0x40>;
323 defm ATOMIC_RMW_XCHG_I32 :
324 WebAssemblyBinRMW<I32, "i32.atomic.rmw.xchg", 0x41>;
325 defm ATOMIC_RMW_XCHG_I64 :
326 WebAssemblyBinRMW<I64, "i64.atomic.rmw.xchg", 0x42>;
327 defm ATOMIC_RMW8_U_XCHG_I32 :
328 WebAssemblyBinRMW<I32, "i32.atomic.rmw8.xchg_u", 0x43>;
329 defm ATOMIC_RMW16_U_XCHG_I32 :
330 WebAssemblyBinRMW<I32, "i32.atomic.rmw16.xchg_u", 0x44>;
331 defm ATOMIC_RMW8_U_XCHG_I64 :
332 WebAssemblyBinRMW<I64, "i64.atomic.rmw8.xchg_u", 0x45>;
333 defm ATOMIC_RMW16_U_XCHG_I64 :
334 WebAssemblyBinRMW<I64, "i64.atomic.rmw16.xchg_u", 0x46>;
335 defm ATOMIC_RMW32_U_XCHG_I64 :
336 WebAssemblyBinRMW<I64, "i64.atomic.rmw32.xchg_u", 0x47>;
338 multiclass BinRMWPat<ValueType ty, PatFrag kind, string inst> {
339 def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$val)),
340 (!cast<NI>(inst#_A32) 0, $offset, $addr, $val)>,
341 Requires<[HasAddr32, HasAtomics]>;
342 def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$val)),
343 (!cast<NI>(inst#_A64) 0, $offset, $addr, $val)>,
344 Requires<[HasAddr64, HasAtomics]>;
347 // Patterns for various addressing modes.
348 multiclass BinRMWPattern<PatFrag rmw_32, PatFrag rmw_64, string inst_32,
350 defm : BinRMWPat<i32, rmw_32, inst_32>;
351 defm : BinRMWPat<i64, rmw_64, inst_64>;
354 defm : BinRMWPattern<atomic_load_add_i32, atomic_load_add_i64,
355 "ATOMIC_RMW_ADD_I32", "ATOMIC_RMW_ADD_I64">;
356 defm : BinRMWPattern<atomic_load_sub_i32, atomic_load_sub_i64,
357 "ATOMIC_RMW_SUB_I32", "ATOMIC_RMW_SUB_I64">;
358 defm : BinRMWPattern<atomic_load_and_i32, atomic_load_and_i64,
359 "ATOMIC_RMW_AND_I32", "ATOMIC_RMW_AND_I64">;
360 defm : BinRMWPattern<atomic_load_or_i32, atomic_load_or_i64,
361 "ATOMIC_RMW_OR_I32", "ATOMIC_RMW_OR_I64">;
362 defm : BinRMWPattern<atomic_load_xor_i32, atomic_load_xor_i64,
363 "ATOMIC_RMW_XOR_I32", "ATOMIC_RMW_XOR_I64">;
364 defm : BinRMWPattern<atomic_swap_i32, atomic_swap_i64,
365 "ATOMIC_RMW_XCHG_I32", "ATOMIC_RMW_XCHG_I64">;
367 // Truncating & zero-extending binary RMW patterns.
368 // These are combined patterns of truncating store patterns and zero-extending
369 // load patterns above.
370 class zext_bin_rmw_8_32<PatFrag kind> :
371 PatFrag<(ops node:$addr, node:$val), (i32 (kind node:$addr, node:$val))>;
372 class zext_bin_rmw_16_32<PatFrag kind> : zext_bin_rmw_8_32<kind>;
373 class zext_bin_rmw_8_64<PatFrag kind> :
374 PatFrag<(ops node:$addr, node:$val),
375 (zext (i32 (kind node:$addr, (i32 (trunc (i64 node:$val))))))>;
376 class zext_bin_rmw_16_64<PatFrag kind> : zext_bin_rmw_8_64<kind>;
377 class zext_bin_rmw_32_64<PatFrag kind> : zext_bin_rmw_8_64<kind>;
379 // Truncating & sign-extending binary RMW patterns.
380 // These are combined patterns of truncating store patterns and sign-extending
381 // load patterns above. We match subword RMWs (for 32-bit) and anyext RMWs (for
382 // 64-bit) and select a zext RMW; the next instruction will be sext_inreg which
383 // is selected by itself.
384 class sext_bin_rmw_8_32<PatFrag kind> :
385 PatFrag<(ops node:$addr, node:$val), (kind node:$addr, node:$val)>;
386 class sext_bin_rmw_16_32<PatFrag kind> : sext_bin_rmw_8_32<kind>;
387 class sext_bin_rmw_8_64<PatFrag kind> :
388 PatFrag<(ops node:$addr, node:$val),
389 (anyext (i32 (kind node:$addr, (i32 (trunc (i64 node:$val))))))>;
390 class sext_bin_rmw_16_64<PatFrag kind> : sext_bin_rmw_8_64<kind>;
391 // 32->64 sext RMW gets selected as i32.atomic.rmw.***, i64.extend_i32_s
393 // Patterns for various addressing modes for truncating-extending binary RMWs.
394 multiclass BinRMWTruncExtPattern<
395 PatFrag rmw_8, PatFrag rmw_16, PatFrag rmw_32,
396 string inst8_32, string inst16_32, string inst8_64, string inst16_64, string inst32_64> {
397 // Truncating-extending binary RMWs
398 defm : BinRMWPat<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
399 defm : BinRMWPat<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
400 defm : BinRMWPat<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
401 defm : BinRMWPat<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
402 defm : BinRMWPat<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
404 defm : BinRMWPat<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
405 defm : BinRMWPat<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
406 defm : BinRMWPat<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
407 defm : BinRMWPat<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
410 defm : BinRMWTruncExtPattern<
411 atomic_load_add_i8, atomic_load_add_i16, atomic_load_add_i32,
412 "ATOMIC_RMW8_U_ADD_I32", "ATOMIC_RMW16_U_ADD_I32",
413 "ATOMIC_RMW8_U_ADD_I64", "ATOMIC_RMW16_U_ADD_I64", "ATOMIC_RMW32_U_ADD_I64">;
414 defm : BinRMWTruncExtPattern<
415 atomic_load_sub_i8, atomic_load_sub_i16, atomic_load_sub_i32,
416 "ATOMIC_RMW8_U_SUB_I32", "ATOMIC_RMW16_U_SUB_I32",
417 "ATOMIC_RMW8_U_SUB_I64", "ATOMIC_RMW16_U_SUB_I64", "ATOMIC_RMW32_U_SUB_I64">;
418 defm : BinRMWTruncExtPattern<
419 atomic_load_and_i8, atomic_load_and_i16, atomic_load_and_i32,
420 "ATOMIC_RMW8_U_AND_I32", "ATOMIC_RMW16_U_AND_I32",
421 "ATOMIC_RMW8_U_AND_I64", "ATOMIC_RMW16_U_AND_I64", "ATOMIC_RMW32_U_AND_I64">;
422 defm : BinRMWTruncExtPattern<
423 atomic_load_or_i8, atomic_load_or_i16, atomic_load_or_i32,
424 "ATOMIC_RMW8_U_OR_I32", "ATOMIC_RMW16_U_OR_I32",
425 "ATOMIC_RMW8_U_OR_I64", "ATOMIC_RMW16_U_OR_I64", "ATOMIC_RMW32_U_OR_I64">;
426 defm : BinRMWTruncExtPattern<
427 atomic_load_xor_i8, atomic_load_xor_i16, atomic_load_xor_i32,
428 "ATOMIC_RMW8_U_XOR_I32", "ATOMIC_RMW16_U_XOR_I32",
429 "ATOMIC_RMW8_U_XOR_I64", "ATOMIC_RMW16_U_XOR_I64", "ATOMIC_RMW32_U_XOR_I64">;
430 defm : BinRMWTruncExtPattern<
431 atomic_swap_i8, atomic_swap_i16, atomic_swap_i32,
432 "ATOMIC_RMW8_U_XCHG_I32", "ATOMIC_RMW16_U_XCHG_I32",
433 "ATOMIC_RMW8_U_XCHG_I64", "ATOMIC_RMW16_U_XCHG_I64",
434 "ATOMIC_RMW32_U_XCHG_I64">;
436 //===----------------------------------------------------------------------===//
437 // Atomic ternary read-modify-writes
438 //===----------------------------------------------------------------------===//
440 // TODO LLVM IR's cmpxchg instruction returns a pair of {loaded value, success
441 // flag}. When we use the success flag or both values, we can't make use of i64
442 // truncate/extend versions of instructions for now, which is suboptimal.
443 // Consider adding a pass after instruction selection that optimizes this case
444 // if it is frequent.
446 multiclass WebAssemblyTerRMW<WebAssemblyRegClass rc, string name,
449 ATOMIC_I<(outs rc:$dst),
450 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$exp,
452 (outs), (ins P2Align:$p2align, offset32_op:$off), [],
453 !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $exp, $new_"),
454 !strconcat(name, "\t${off}${p2align}"), atomic_op, false>;
456 ATOMIC_I<(outs rc:$dst),
457 (ins P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$exp,
459 (outs), (ins P2Align:$p2align, offset64_op:$off), [],
460 !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $exp, $new_"),
461 !strconcat(name, "\t${off}${p2align}"), atomic_op, true>;
464 defm ATOMIC_RMW_CMPXCHG_I32 :
465 WebAssemblyTerRMW<I32, "i32.atomic.rmw.cmpxchg", 0x48>;
466 defm ATOMIC_RMW_CMPXCHG_I64 :
467 WebAssemblyTerRMW<I64, "i64.atomic.rmw.cmpxchg", 0x49>;
468 defm ATOMIC_RMW8_U_CMPXCHG_I32 :
469 WebAssemblyTerRMW<I32, "i32.atomic.rmw8.cmpxchg_u", 0x4a>;
470 defm ATOMIC_RMW16_U_CMPXCHG_I32 :
471 WebAssemblyTerRMW<I32, "i32.atomic.rmw16.cmpxchg_u", 0x4b>;
472 defm ATOMIC_RMW8_U_CMPXCHG_I64 :
473 WebAssemblyTerRMW<I64, "i64.atomic.rmw8.cmpxchg_u", 0x4c>;
474 defm ATOMIC_RMW16_U_CMPXCHG_I64 :
475 WebAssemblyTerRMW<I64, "i64.atomic.rmw16.cmpxchg_u", 0x4d>;
476 defm ATOMIC_RMW32_U_CMPXCHG_I64 :
477 WebAssemblyTerRMW<I64, "i64.atomic.rmw32.cmpxchg_u", 0x4e>;
479 multiclass TerRMWPat<ValueType ty, PatFrag kind, string inst> {
480 def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$exp, ty:$new)),
481 (!cast<NI>(inst#_A32) 0, $offset, $addr, $exp, $new)>,
482 Requires<[HasAddr32, HasAtomics]>;
483 def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$exp, ty:$new)),
484 (!cast<NI>(inst#_A64) 0, $offset, $addr, $exp, $new)>,
485 Requires<[HasAddr64, HasAtomics]>;
488 defm : TerRMWPat<i32, atomic_cmp_swap_i32, "ATOMIC_RMW_CMPXCHG_I32">;
489 defm : TerRMWPat<i64, atomic_cmp_swap_i64, "ATOMIC_RMW_CMPXCHG_I64">;
491 // Truncating & zero-extending ternary RMW patterns.
492 // DAG legalization & optimization before instruction selection may introduce
493 // additional nodes such as anyext or assertzext depending on operand types.
494 class zext_ter_rmw_8_32<PatFrag kind> :
495 PatFrag<(ops node:$addr, node:$exp, node:$new),
496 (i32 (kind node:$addr, node:$exp, node:$new))>;
497 class zext_ter_rmw_16_32<PatFrag kind> : zext_ter_rmw_8_32<kind>;
498 class zext_ter_rmw_8_64<PatFrag kind> :
499 PatFrag<(ops node:$addr, node:$exp, node:$new),
500 (zext (i32 (assertzext (i32 (kind node:$addr,
501 (i32 (trunc (i64 node:$exp))),
502 (i32 (trunc (i64 node:$new))))))))>;
503 class zext_ter_rmw_16_64<PatFrag kind> : zext_ter_rmw_8_64<kind>;
504 class zext_ter_rmw_32_64<PatFrag kind> :
505 PatFrag<(ops node:$addr, node:$exp, node:$new),
506 (zext (i32 (kind node:$addr,
507 (i32 (trunc (i64 node:$exp))),
508 (i32 (trunc (i64 node:$new))))))>;
510 // Truncating & sign-extending ternary RMW patterns.
511 // We match subword RMWs (for 32-bit) and anyext RMWs (for 64-bit) and select a
512 // zext RMW; the next instruction will be sext_inreg which is selected by
514 class sext_ter_rmw_8_32<PatFrag kind> :
515 PatFrag<(ops node:$addr, node:$exp, node:$new),
516 (kind node:$addr, node:$exp, node:$new)>;
517 class sext_ter_rmw_16_32<PatFrag kind> : sext_ter_rmw_8_32<kind>;
518 class sext_ter_rmw_8_64<PatFrag kind> :
519 PatFrag<(ops node:$addr, node:$exp, node:$new),
520 (anyext (i32 (assertzext (i32
522 (i32 (trunc (i64 node:$exp))),
523 (i32 (trunc (i64 node:$new))))))))>;
524 class sext_ter_rmw_16_64<PatFrag kind> : sext_ter_rmw_8_64<kind>;
525 // 32->64 sext RMW gets selected as i32.atomic.rmw.***, i64.extend_i32_s
527 defm : TerRMWPat<i32, zext_ter_rmw_8_32<atomic_cmp_swap_i8>, "ATOMIC_RMW8_U_CMPXCHG_I32">;
528 defm : TerRMWPat<i32, zext_ter_rmw_16_32<atomic_cmp_swap_i16>, "ATOMIC_RMW16_U_CMPXCHG_I32">;
529 defm : TerRMWPat<i64, zext_ter_rmw_8_64<atomic_cmp_swap_i8>, "ATOMIC_RMW8_U_CMPXCHG_I64">;
530 defm : TerRMWPat<i64, zext_ter_rmw_16_64<atomic_cmp_swap_i16>, "ATOMIC_RMW16_U_CMPXCHG_I64">;
531 defm : TerRMWPat<i64, zext_ter_rmw_32_64<atomic_cmp_swap_i32>, "ATOMIC_RMW32_U_CMPXCHG_I64">;
533 defm : TerRMWPat<i32, sext_ter_rmw_8_32<atomic_cmp_swap_i8>, "ATOMIC_RMW8_U_CMPXCHG_I32">;
534 defm : TerRMWPat<i32, sext_ter_rmw_16_32<atomic_cmp_swap_i16>, "ATOMIC_RMW16_U_CMPXCHG_I32">;
535 defm : TerRMWPat<i64, sext_ter_rmw_8_64<atomic_cmp_swap_i8>, "ATOMIC_RMW8_U_CMPXCHG_I64">;
536 defm : TerRMWPat<i64, sext_ter_rmw_16_64<atomic_cmp_swap_i16>, "ATOMIC_RMW16_U_CMPXCHG_I64">;