xref: /freebsd/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
10b57cec5SDimitry Andric// WebAssemblyInstrAtomics.td-WebAssembly Atomic codegen support-*- tablegen -*-
20b57cec5SDimitry Andric//
30b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric//
70b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric///
90b57cec5SDimitry Andric/// \file
100b57cec5SDimitry Andric/// WebAssembly Atomic operand code-gen constructs.
110b57cec5SDimitry Andric///
120b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andriclet UseNamedOperandTable = 1 in
150b57cec5SDimitry Andricmulticlass ATOMIC_I<dag oops_r, dag iops_r, dag oops_s, dag iops_s,
16*5ffd83dbSDimitry Andric                    list<dag> pattern_r, string asmstr_r,
17*5ffd83dbSDimitry Andric                    string asmstr_s, bits<32> atomic_op,
18*5ffd83dbSDimitry Andric                    string is64 = "false"> {
190b57cec5SDimitry Andric  defm "" : I<oops_r, iops_r, oops_s, iops_s, pattern_r, asmstr_r, asmstr_s,
20*5ffd83dbSDimitry Andric              !or(0xfe00, !and(0xff, atomic_op)), is64>,
210b57cec5SDimitry Andric            Requires<[HasAtomics]>;
220b57cec5SDimitry Andric}
230b57cec5SDimitry Andric
240b57cec5SDimitry Andricmulticlass ATOMIC_NRI<dag oops, dag iops, list<dag> pattern, string asmstr = "",
250b57cec5SDimitry Andric                      bits<32> atomic_op = -1> {
260b57cec5SDimitry Andric  defm "" : NRI<oops, iops, pattern, asmstr,
270b57cec5SDimitry Andric                !or(0xfe00, !and(0xff, atomic_op))>,
280b57cec5SDimitry Andric            Requires<[HasAtomics]>;
290b57cec5SDimitry Andric}
300b57cec5SDimitry Andric
310b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
320b57cec5SDimitry Andric// Atomic wait / notify
330b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
340b57cec5SDimitry Andric
350b57cec5SDimitry Andriclet hasSideEffects = 1 in {
36*5ffd83dbSDimitry Andricdefm ATOMIC_NOTIFY_A32 :
370b57cec5SDimitry Andric  ATOMIC_I<(outs I32:$dst),
380b57cec5SDimitry Andric           (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$count),
390b57cec5SDimitry Andric           (outs), (ins P2Align:$p2align, offset32_op:$off), [],
400b57cec5SDimitry Andric           "atomic.notify \t$dst, ${off}(${addr})${p2align}, $count",
41*5ffd83dbSDimitry Andric           "atomic.notify \t${off}${p2align}", 0x00, "false">;
42*5ffd83dbSDimitry Andricdefm ATOMIC_NOTIFY_A64 :
43*5ffd83dbSDimitry Andric  ATOMIC_I<(outs I32:$dst),
44*5ffd83dbSDimitry Andric           (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$count),
45*5ffd83dbSDimitry Andric           (outs), (ins P2Align:$p2align, offset64_op:$off), [],
46*5ffd83dbSDimitry Andric           "atomic.notify \t$dst, ${off}(${addr})${p2align}, $count",
47*5ffd83dbSDimitry Andric           "atomic.notify \t${off}${p2align}", 0x00, "true">;
480b57cec5SDimitry Andriclet mayLoad = 1 in {
49*5ffd83dbSDimitry Andricdefm ATOMIC_WAIT_I32_A32 :
500b57cec5SDimitry Andric  ATOMIC_I<(outs I32:$dst),
510b57cec5SDimitry Andric           (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$exp,
520b57cec5SDimitry Andric                I64:$timeout),
530b57cec5SDimitry Andric           (outs), (ins P2Align:$p2align, offset32_op:$off), [],
540b57cec5SDimitry Andric           "i32.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
55*5ffd83dbSDimitry Andric           "i32.atomic.wait \t${off}${p2align}", 0x01, "false">;
56*5ffd83dbSDimitry Andricdefm ATOMIC_WAIT_I32_A64 :
57*5ffd83dbSDimitry Andric  ATOMIC_I<(outs I32:$dst),
58*5ffd83dbSDimitry Andric           (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I32:$exp,
59*5ffd83dbSDimitry Andric                I64:$timeout),
60*5ffd83dbSDimitry Andric           (outs), (ins P2Align:$p2align, offset64_op:$off), [],
61*5ffd83dbSDimitry Andric           "i32.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
62*5ffd83dbSDimitry Andric           "i32.atomic.wait \t${off}${p2align}", 0x01, "true">;
63*5ffd83dbSDimitry Andricdefm ATOMIC_WAIT_I64_A32 :
640b57cec5SDimitry Andric  ATOMIC_I<(outs I32:$dst),
650b57cec5SDimitry Andric           (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I64:$exp,
660b57cec5SDimitry Andric                I64:$timeout),
670b57cec5SDimitry Andric           (outs), (ins P2Align:$p2align, offset32_op:$off), [],
680b57cec5SDimitry Andric           "i64.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
69*5ffd83dbSDimitry Andric           "i64.atomic.wait \t${off}${p2align}", 0x02, "false">;
70*5ffd83dbSDimitry Andricdefm ATOMIC_WAIT_I64_A64 :
71*5ffd83dbSDimitry Andric  ATOMIC_I<(outs I32:$dst),
72*5ffd83dbSDimitry Andric           (ins P2Align:$p2align, offset64_op:$off, I64:$addr, I64:$exp,
73*5ffd83dbSDimitry Andric                I64:$timeout),
74*5ffd83dbSDimitry Andric           (outs), (ins P2Align:$p2align, offset64_op:$off), [],
75*5ffd83dbSDimitry Andric           "i64.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
76*5ffd83dbSDimitry Andric           "i64.atomic.wait \t${off}${p2align}", 0x02, "true">;
770b57cec5SDimitry Andric} // mayLoad = 1
780b57cec5SDimitry Andric} // hasSideEffects = 1
790b57cec5SDimitry Andric
800b57cec5SDimitry Andriclet Predicates = [HasAtomics] in {
810b57cec5SDimitry Andric// Select notifys with no constant offset.
82*5ffd83dbSDimitry Andricdef NotifyPatNoOffset_A32 :
830b57cec5SDimitry Andric  Pat<(i32 (int_wasm_atomic_notify I32:$addr, I32:$count)),
84*5ffd83dbSDimitry Andric      (ATOMIC_NOTIFY_A32 0, 0, I32:$addr, I32:$count)>,
85*5ffd83dbSDimitry Andric  Requires<[HasAddr32]>;
86*5ffd83dbSDimitry Andricdef NotifyPatNoOffset_A64 :
87*5ffd83dbSDimitry Andric  Pat<(i32 (int_wasm_atomic_notify I64:$addr, I32:$count)),
88*5ffd83dbSDimitry Andric      (ATOMIC_NOTIFY_A64 0, 0, I64:$addr, I32:$count)>,
89*5ffd83dbSDimitry Andric  Requires<[HasAddr64]>;
900b57cec5SDimitry Andric
910b57cec5SDimitry Andric// Select notifys with a constant offset.
920b57cec5SDimitry Andric
930b57cec5SDimitry Andric// Pattern with address + immediate offset
94*5ffd83dbSDimitry Andricmulticlass NotifyPatImmOff<PatFrag operand, string inst> {
95*5ffd83dbSDimitry Andric  def : Pat<(i32 (int_wasm_atomic_notify (operand I32:$addr, imm:$off),
96*5ffd83dbSDimitry Andric                  I32:$count)),
97*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, I32:$count)>,
98*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
99*5ffd83dbSDimitry Andric  def : Pat<(i32 (int_wasm_atomic_notify (operand I64:$addr, imm:$off),
100*5ffd83dbSDimitry Andric                  I32:$count)),
101*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, I32:$count)>,
102*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
103*5ffd83dbSDimitry Andric}
104*5ffd83dbSDimitry Andricdefm : NotifyPatImmOff<regPlusImm, "ATOMIC_NOTIFY">;
105*5ffd83dbSDimitry Andricdefm : NotifyPatImmOff<or_is_add, "ATOMIC_NOTIFY">;
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric// Select notifys with just a constant offset.
108*5ffd83dbSDimitry Andricdef NotifyPatOffsetOnly_A32 :
1090b57cec5SDimitry Andric  Pat<(i32 (int_wasm_atomic_notify imm:$off, I32:$count)),
110*5ffd83dbSDimitry Andric      (ATOMIC_NOTIFY_A32 0, imm:$off, (CONST_I32 0), I32:$count)>,
111*5ffd83dbSDimitry Andric  Requires<[HasAddr32]>;
112*5ffd83dbSDimitry Andricdef NotifyPatOffsetOnly_A64 :
113*5ffd83dbSDimitry Andric  Pat<(i32 (int_wasm_atomic_notify imm:$off, I32:$count)),
114*5ffd83dbSDimitry Andric      (ATOMIC_NOTIFY_A64 0, imm:$off, (CONST_I64 0), I32:$count)>,
115*5ffd83dbSDimitry Andric  Requires<[HasAddr64]>;
1160b57cec5SDimitry Andric
117*5ffd83dbSDimitry Andricdef NotifyPatGlobalAddrOffOnly_A32 :
1180b57cec5SDimitry Andric  Pat<(i32 (int_wasm_atomic_notify (WebAssemblywrapper tglobaladdr:$off),
1190b57cec5SDimitry Andric                                   I32:$count)),
120*5ffd83dbSDimitry Andric      (ATOMIC_NOTIFY_A32 0, tglobaladdr:$off, (CONST_I32 0), I32:$count)>,
121*5ffd83dbSDimitry Andric  Requires<[HasAddr32]>;
122*5ffd83dbSDimitry Andricdef NotifyPatGlobalAddrOffOnly_A64 :
123*5ffd83dbSDimitry Andric  Pat<(i32 (int_wasm_atomic_notify (WebAssemblywrapper tglobaladdr:$off),
124*5ffd83dbSDimitry Andric                                   I32:$count)),
125*5ffd83dbSDimitry Andric      (ATOMIC_NOTIFY_A64 0, tglobaladdr:$off, (CONST_I64 0), I32:$count)>,
126*5ffd83dbSDimitry Andric  Requires<[HasAddr64]>;
1270b57cec5SDimitry Andric
1280b57cec5SDimitry Andric// Select waits with no constant offset.
129*5ffd83dbSDimitry Andricmulticlass WaitPatNoOffset<ValueType ty, Intrinsic kind,
130*5ffd83dbSDimitry Andric                      string inst> {
131*5ffd83dbSDimitry Andric  def : Pat<(i32 (kind I32:$addr, ty:$exp, I64:$timeout)),
132*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, 0, I32:$addr, ty:$exp, I64:$timeout)>,
133*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
134*5ffd83dbSDimitry Andric  def : Pat<(i32 (kind I64:$addr, ty:$exp, I64:$timeout)),
135*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, 0, I64:$addr, ty:$exp, I64:$timeout)>,
136*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
137*5ffd83dbSDimitry Andric}
138*5ffd83dbSDimitry Andricdefm : WaitPatNoOffset<i32, int_wasm_atomic_wait_i32, "ATOMIC_WAIT_I32">;
139*5ffd83dbSDimitry Andricdefm : WaitPatNoOffset<i64, int_wasm_atomic_wait_i64, "ATOMIC_WAIT_I64">;
140*5ffd83dbSDimitry Andricdefm : WaitPatNoOffset<i32, int_wasm_atomic_wait_i32, "ATOMIC_WAIT_I32">;
141*5ffd83dbSDimitry Andricdefm : WaitPatNoOffset<i64, int_wasm_atomic_wait_i64, "ATOMIC_WAIT_I64">;
1420b57cec5SDimitry Andric
1430b57cec5SDimitry Andric// Select waits with a constant offset.
1440b57cec5SDimitry Andric
1450b57cec5SDimitry Andric// Pattern with address + immediate offset
146*5ffd83dbSDimitry Andricmulticlass WaitPatImmOff<ValueType ty, Intrinsic kind, PatFrag operand,
147*5ffd83dbSDimitry Andric                         string inst> {
148*5ffd83dbSDimitry Andric  def : Pat<(i32 (kind (operand I32:$addr, imm:$off), ty:$exp, I64:$timeout)),
149*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, ty:$exp,
150*5ffd83dbSDimitry Andric              I64:$timeout)>,
151*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
152*5ffd83dbSDimitry Andric  def : Pat<(i32 (kind (operand I64:$addr, imm:$off), ty:$exp, I64:$timeout)),
153*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, ty:$exp,
154*5ffd83dbSDimitry Andric              I64:$timeout)>,
155*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
156*5ffd83dbSDimitry Andric}
157*5ffd83dbSDimitry Andricdefm : WaitPatImmOff<i32, int_wasm_atomic_wait_i32, regPlusImm,
158*5ffd83dbSDimitry Andric                     "ATOMIC_WAIT_I32">;
159*5ffd83dbSDimitry Andricdefm : WaitPatImmOff<i32, int_wasm_atomic_wait_i32, or_is_add,
160*5ffd83dbSDimitry Andric                     "ATOMIC_WAIT_I32">;
161*5ffd83dbSDimitry Andricdefm : WaitPatImmOff<i64, int_wasm_atomic_wait_i64, regPlusImm,
162*5ffd83dbSDimitry Andric                     "ATOMIC_WAIT_I64">;
163*5ffd83dbSDimitry Andricdefm : WaitPatImmOff<i64, int_wasm_atomic_wait_i64, or_is_add,
164*5ffd83dbSDimitry Andric                     "ATOMIC_WAIT_I64">;
1650b57cec5SDimitry Andric
166*5ffd83dbSDimitry Andric// Select wait_i32, "ATOMIC_WAIT_I32s with just a constant offset.
167*5ffd83dbSDimitry Andricmulticlass WaitPatOffsetOnly<ValueType ty, Intrinsic kind, string inst> {
168*5ffd83dbSDimitry Andric  def : Pat<(i32 (kind imm:$off, ty:$exp, I64:$timeout)),
169*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, imm:$off, (CONST_I32 0), ty:$exp,
170*5ffd83dbSDimitry Andric               I64:$timeout)>,
171*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
172*5ffd83dbSDimitry Andric  def : Pat<(i32 (kind imm:$off, ty:$exp, I64:$timeout)),
173*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, imm:$off, (CONST_I64 0), ty:$exp,
174*5ffd83dbSDimitry Andric               I64:$timeout)>,
175*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
176*5ffd83dbSDimitry Andric}
177*5ffd83dbSDimitry Andricdefm : WaitPatOffsetOnly<i32, int_wasm_atomic_wait_i32, "ATOMIC_WAIT_I32">;
178*5ffd83dbSDimitry Andricdefm : WaitPatOffsetOnly<i64, int_wasm_atomic_wait_i64, "ATOMIC_WAIT_I64">;
1790b57cec5SDimitry Andric
180*5ffd83dbSDimitry Andricmulticlass WaitPatGlobalAddrOffOnly<ValueType ty, Intrinsic kind, string inst> {
181*5ffd83dbSDimitry Andric  def : Pat<(i32 (kind (WebAssemblywrapper tglobaladdr:$off), ty:$exp,
182*5ffd83dbSDimitry Andric                  I64:$timeout)),
183*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, tglobaladdr:$off, (CONST_I32 0), ty:$exp,
184*5ffd83dbSDimitry Andric               I64:$timeout)>,
185*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
186*5ffd83dbSDimitry Andric  def : Pat<(i32 (kind (WebAssemblywrapper tglobaladdr:$off), ty:$exp,
187*5ffd83dbSDimitry Andric                  I64:$timeout)),
188*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, tglobaladdr:$off, (CONST_I64 0), ty:$exp,
189*5ffd83dbSDimitry Andric               I64:$timeout)>,
190*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
191*5ffd83dbSDimitry Andric}
192*5ffd83dbSDimitry Andricdefm : WaitPatGlobalAddrOffOnly<i32, int_wasm_atomic_wait_i32,
193*5ffd83dbSDimitry Andric                                "ATOMIC_WAIT_I32">;
194*5ffd83dbSDimitry Andricdefm : WaitPatGlobalAddrOffOnly<i64, int_wasm_atomic_wait_i64,
195*5ffd83dbSDimitry Andric                                "ATOMIC_WAIT_I64">;
1960b57cec5SDimitry Andric} // Predicates = [HasAtomics]
1970b57cec5SDimitry Andric
1980b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
1998bcb0991SDimitry Andric// Atomic fences
2008bcb0991SDimitry Andric//===----------------------------------------------------------------------===//
2018bcb0991SDimitry Andric
2028bcb0991SDimitry Andric// A compiler fence instruction that prevents reordering of instructions.
2038bcb0991SDimitry Andriclet Defs = [ARGUMENTS] in {
2048bcb0991SDimitry Andriclet isPseudo = 1, hasSideEffects = 1 in
2058bcb0991SDimitry Andricdefm COMPILER_FENCE : ATOMIC_NRI<(outs), (ins), [], "compiler_fence">;
2068bcb0991SDimitry Andriclet hasSideEffects = 1 in
2078bcb0991SDimitry Andricdefm ATOMIC_FENCE : ATOMIC_NRI<(outs), (ins i8imm:$flags), [], "atomic.fence",
2088bcb0991SDimitry Andric                               0x03>;
2098bcb0991SDimitry Andric} // Defs = [ARGUMENTS]
2108bcb0991SDimitry Andric
2118bcb0991SDimitry Andric//===----------------------------------------------------------------------===//
2120b57cec5SDimitry Andric// Atomic loads
2130b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
2140b57cec5SDimitry Andric
2150b57cec5SDimitry Andricmulticlass AtomicLoad<WebAssemblyRegClass rc, string name, int atomic_op> {
216*5ffd83dbSDimitry Andric  defm "" : WebAssemblyLoad<rc, name, !or(0xfe00, !and(0xff, atomic_op)),
217*5ffd83dbSDimitry Andric                            [HasAtomics]>;
2180b57cec5SDimitry Andric}
2190b57cec5SDimitry Andric
2200b57cec5SDimitry Andricdefm ATOMIC_LOAD_I32 : AtomicLoad<I32, "i32.atomic.load", 0x10>;
2210b57cec5SDimitry Andricdefm ATOMIC_LOAD_I64 : AtomicLoad<I64, "i64.atomic.load", 0x11>;
2220b57cec5SDimitry Andric
2230b57cec5SDimitry Andric// Select loads with no constant offset.
2240b57cec5SDimitry Andriclet Predicates = [HasAtomics] in {
225*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i32, atomic_load_32, "ATOMIC_LOAD_I32">;
226*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i64, atomic_load_64, "ATOMIC_LOAD_I64">;
2270b57cec5SDimitry Andric
2280b57cec5SDimitry Andric// Select loads with a constant offset.
2290b57cec5SDimitry Andric
2300b57cec5SDimitry Andric// Pattern with address + immediate offset
231*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, atomic_load_32, regPlusImm, "ATOMIC_LOAD_I32">;
232*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, atomic_load_64, regPlusImm, "ATOMIC_LOAD_I64">;
233*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, atomic_load_32, or_is_add, "ATOMIC_LOAD_I32">;
234*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, atomic_load_64, or_is_add, "ATOMIC_LOAD_I64">;
2350b57cec5SDimitry Andric
2360b57cec5SDimitry Andric// Select loads with just a constant offset.
237*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i32, atomic_load_32, "ATOMIC_LOAD_I32">;
238*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i64, atomic_load_64, "ATOMIC_LOAD_I64">;
2390b57cec5SDimitry Andric
240*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i32, atomic_load_32, "ATOMIC_LOAD_I32">;
241*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i64, atomic_load_64, "ATOMIC_LOAD_I64">;
2420b57cec5SDimitry Andric
2430b57cec5SDimitry Andric} // Predicates = [HasAtomics]
2440b57cec5SDimitry Andric
2450b57cec5SDimitry Andric// Extending loads. Note that there are only zero-extending atomic loads, no
2460b57cec5SDimitry Andric// sign-extending loads.
2470b57cec5SDimitry Andricdefm ATOMIC_LOAD8_U_I32 : AtomicLoad<I32, "i32.atomic.load8_u", 0x12>;
2480b57cec5SDimitry Andricdefm ATOMIC_LOAD16_U_I32 : AtomicLoad<I32, "i32.atomic.load16_u", 0x13>;
2490b57cec5SDimitry Andricdefm ATOMIC_LOAD8_U_I64 : AtomicLoad<I64, "i64.atomic.load8_u", 0x14>;
2500b57cec5SDimitry Andricdefm ATOMIC_LOAD16_U_I64 : AtomicLoad<I64, "i64.atomic.load16_u", 0x15>;
2510b57cec5SDimitry Andricdefm ATOMIC_LOAD32_U_I64 : AtomicLoad<I64, "i64.atomic.load32_u", 0x16>;
2520b57cec5SDimitry Andric
2530b57cec5SDimitry Andric// Fragments for extending loads. These are different from regular loads because
2540b57cec5SDimitry Andric// the SDNodes are derived from AtomicSDNode rather than LoadSDNode and
2550b57cec5SDimitry Andric// therefore don't have the extension type field. So instead of matching that,
2560b57cec5SDimitry Andric// we match the patterns that the type legalizer expands them to.
2570b57cec5SDimitry Andric
2580b57cec5SDimitry Andric// We directly match zext patterns and select the zext atomic loads.
2590b57cec5SDimitry Andric// i32 (zext (i8 (atomic_load_8))) gets legalized to
2600b57cec5SDimitry Andric// i32 (and (i32 (atomic_load_8)), 255)
2610b57cec5SDimitry Andric// These can be selected to a single zero-extending atomic load instruction.
2620b57cec5SDimitry Andricdef zext_aload_8_32 :
2630b57cec5SDimitry Andric  PatFrag<(ops node:$addr), (and (i32 (atomic_load_8 node:$addr)), 255)>;
2640b57cec5SDimitry Andricdef zext_aload_16_32 :
2650b57cec5SDimitry Andric  PatFrag<(ops node:$addr), (and (i32 (atomic_load_16 node:$addr)), 65535)>;
2660b57cec5SDimitry Andric// Unlike regular loads, extension to i64 is handled differently than i32.
2670b57cec5SDimitry Andric// i64 (zext (i8 (atomic_load_8))) gets legalized to
2680b57cec5SDimitry Andric// i64 (and (i64 (anyext (i32 (atomic_load_8)))), 255)
2690b57cec5SDimitry Andricdef zext_aload_8_64 :
2700b57cec5SDimitry Andric  PatFrag<(ops node:$addr),
2710b57cec5SDimitry Andric          (and (i64 (anyext (i32 (atomic_load_8 node:$addr)))), 255)>;
2720b57cec5SDimitry Andricdef zext_aload_16_64 :
2730b57cec5SDimitry Andric  PatFrag<(ops node:$addr),
2740b57cec5SDimitry Andric          (and (i64 (anyext (i32 (atomic_load_16 node:$addr)))), 65535)>;
2750b57cec5SDimitry Andricdef zext_aload_32_64 :
2760b57cec5SDimitry Andric  PatFrag<(ops node:$addr),
2770b57cec5SDimitry Andric          (zext (i32 (atomic_load node:$addr)))>;
2780b57cec5SDimitry Andric
2790b57cec5SDimitry Andric// We don't have single sext atomic load instructions. So for sext loads, we
2800b57cec5SDimitry Andric// match bare subword loads (for 32-bit results) and anyext loads (for 64-bit
2810b57cec5SDimitry Andric// results) and select a zext load; the next instruction will be sext_inreg
2820b57cec5SDimitry Andric// which is selected by itself.
2830b57cec5SDimitry Andricdef sext_aload_8_64 :
2840b57cec5SDimitry Andric  PatFrag<(ops node:$addr), (anyext (i32 (atomic_load_8 node:$addr)))>;
2850b57cec5SDimitry Andricdef sext_aload_16_64 :
2860b57cec5SDimitry Andric  PatFrag<(ops node:$addr), (anyext (i32 (atomic_load_16 node:$addr)))>;
2870b57cec5SDimitry Andric
2880b57cec5SDimitry Andriclet Predicates = [HasAtomics] in {
2890b57cec5SDimitry Andric// Select zero-extending loads with no constant offset.
290*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i32, zext_aload_8_32, "ATOMIC_LOAD8_U_I32">;
291*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i32, zext_aload_16_32, "ATOMIC_LOAD16_U_I32">;
292*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i64, zext_aload_8_64, "ATOMIC_LOAD8_U_I64">;
293*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i64, zext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
294*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i64, zext_aload_32_64, "ATOMIC_LOAD32_U_I64">;
2950b57cec5SDimitry Andric
2960b57cec5SDimitry Andric// Select sign-extending loads with no constant offset
297*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i32, atomic_load_8, "ATOMIC_LOAD8_U_I32">;
298*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i32, atomic_load_16, "ATOMIC_LOAD16_U_I32">;
299*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i64, sext_aload_8_64, "ATOMIC_LOAD8_U_I64">;
300*5ffd83dbSDimitry Andricdefm : LoadPatNoOffset<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
3010b57cec5SDimitry Andric// 32->64 sext load gets selected as i32.atomic.load, i64.extend_i32_s
3020b57cec5SDimitry Andric
3030b57cec5SDimitry Andric// Zero-extending loads with constant offset
304*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, zext_aload_8_32, regPlusImm, "ATOMIC_LOAD8_U_I32">;
305*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, zext_aload_16_32, regPlusImm, "ATOMIC_LOAD16_U_I32">;
306*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, zext_aload_8_32, or_is_add, "ATOMIC_LOAD8_U_I32">;
307*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, zext_aload_16_32, or_is_add, "ATOMIC_LOAD16_U_I32">;
308*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, zext_aload_8_64, regPlusImm, "ATOMIC_LOAD8_U_I64">;
309*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, zext_aload_16_64, regPlusImm, "ATOMIC_LOAD16_U_I64">;
310*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, zext_aload_32_64, regPlusImm, "ATOMIC_LOAD32_U_I64">;
311*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, zext_aload_8_64, or_is_add, "ATOMIC_LOAD8_U_I64">;
312*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, zext_aload_16_64, or_is_add, "ATOMIC_LOAD16_U_I64">;
313*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, zext_aload_32_64, or_is_add, "ATOMIC_LOAD32_U_I64">;
3140b57cec5SDimitry Andric
3150b57cec5SDimitry Andric// Sign-extending loads with constant offset
316*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, atomic_load_8, regPlusImm, "ATOMIC_LOAD8_U_I32">;
317*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, atomic_load_16, regPlusImm, "ATOMIC_LOAD16_U_I32">;
318*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, atomic_load_8, or_is_add, "ATOMIC_LOAD8_U_I32">;
319*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i32, atomic_load_16, or_is_add, "ATOMIC_LOAD16_U_I32">;
320*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, sext_aload_8_64, regPlusImm, "ATOMIC_LOAD8_U_I64">;
321*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, sext_aload_16_64, regPlusImm, "ATOMIC_LOAD16_U_I64">;
322*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, sext_aload_8_64, or_is_add, "ATOMIC_LOAD8_U_I64">;
323*5ffd83dbSDimitry Andricdefm : LoadPatImmOff<i64, sext_aload_16_64, or_is_add, "ATOMIC_LOAD16_U_I64">;
3240b57cec5SDimitry Andric// No 32->64 patterns, just use i32.atomic.load and i64.extend_s/i64
3250b57cec5SDimitry Andric
3260b57cec5SDimitry Andric// Extending loads with just a constant offset
327*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i32, zext_aload_8_32, "ATOMIC_LOAD8_U_I32">;
328*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i32, zext_aload_16_32, "ATOMIC_LOAD16_U_I32">;
329*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i64, zext_aload_8_64, "ATOMIC_LOAD8_U_I64">;
330*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i64, zext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
331*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i64, zext_aload_32_64, "ATOMIC_LOAD32_U_I64">;
332*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i32, atomic_load_8, "ATOMIC_LOAD8_U_I32">;
333*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i32, atomic_load_16, "ATOMIC_LOAD16_U_I32">;
334*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i64, sext_aload_8_64, "ATOMIC_LOAD8_U_I64">;
335*5ffd83dbSDimitry Andricdefm : LoadPatOffsetOnly<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
3360b57cec5SDimitry Andric
337*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i32, zext_aload_8_32, "ATOMIC_LOAD8_U_I32">;
338*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i32, zext_aload_16_32, "ATOMIC_LOAD16_U_I32">;
339*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i64, zext_aload_8_64, "ATOMIC_LOAD8_U_I64">;
340*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i64, zext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
341*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i64, zext_aload_32_64, "ATOMIC_LOAD32_U_I64">;
342*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i32, atomic_load_8, "ATOMIC_LOAD8_U_I32">;
343*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i32, atomic_load_16, "ATOMIC_LOAD16_U_I32">;
344*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i64, sext_aload_8_64, "ATOMIC_LOAD8_U_I64">;
345*5ffd83dbSDimitry Andricdefm : LoadPatGlobalAddrOffOnly<i64, sext_aload_16_64, "ATOMIC_LOAD16_U_I64">;
3460b57cec5SDimitry Andric
3470b57cec5SDimitry Andric} // Predicates = [HasAtomics]
3480b57cec5SDimitry Andric
3490b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
3500b57cec5SDimitry Andric// Atomic stores
3510b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
3520b57cec5SDimitry Andric
3530b57cec5SDimitry Andricmulticlass AtomicStore<WebAssemblyRegClass rc, string name, int atomic_op> {
354*5ffd83dbSDimitry Andric  defm "" : WebAssemblyStore<rc, name, !or(0xfe00, !and(0xff, atomic_op)),
355*5ffd83dbSDimitry Andric                             [HasAtomics]>;
3560b57cec5SDimitry Andric}
3570b57cec5SDimitry Andric
3580b57cec5SDimitry Andricdefm ATOMIC_STORE_I32 : AtomicStore<I32, "i32.atomic.store", 0x17>;
3590b57cec5SDimitry Andricdefm ATOMIC_STORE_I64 : AtomicStore<I64, "i64.atomic.store", 0x18>;
3600b57cec5SDimitry Andric
3610b57cec5SDimitry Andric// We need an 'atomic' version of store patterns because store and atomic_store
3620b57cec5SDimitry Andric// nodes have different operand orders:
3630b57cec5SDimitry Andric// store: (store $val, $ptr)
3640b57cec5SDimitry Andric// atomic_store: (store $ptr, $val)
3650b57cec5SDimitry Andric
3660b57cec5SDimitry Andriclet Predicates = [HasAtomics] in {
3670b57cec5SDimitry Andric
3680b57cec5SDimitry Andric// Select stores with no constant offset.
369*5ffd83dbSDimitry Andricmulticlass AStorePatNoOffset<ValueType ty, PatFrag kind, string inst> {
370*5ffd83dbSDimitry Andric  def : Pat<(kind I32:$addr, ty:$val),
371*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, 0, I32:$addr, ty:$val)>,
372*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
373*5ffd83dbSDimitry Andric  def : Pat<(kind I64:$addr, ty:$val),
374*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, 0, I64:$addr, ty:$val)>,
375*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
376*5ffd83dbSDimitry Andric}
377*5ffd83dbSDimitry Andricdefm : AStorePatNoOffset<i32, atomic_store_32, "ATOMIC_STORE_I32">;
378*5ffd83dbSDimitry Andricdefm : AStorePatNoOffset<i64, atomic_store_64, "ATOMIC_STORE_I64">;
3790b57cec5SDimitry Andric
3800b57cec5SDimitry Andric// Select stores with a constant offset.
3810b57cec5SDimitry Andric
3820b57cec5SDimitry Andric// Pattern with address + immediate offset
383*5ffd83dbSDimitry Andricmulticlass AStorePatImmOff<ValueType ty, PatFrag kind, PatFrag operand,
384*5ffd83dbSDimitry Andric                           string inst> {
385*5ffd83dbSDimitry Andric  def : Pat<(kind (operand I32:$addr, imm:$off), ty:$val),
386*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, ty:$val)>,
387*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
388*5ffd83dbSDimitry Andric  def : Pat<(kind (operand I64:$addr, imm:$off), ty:$val),
389*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, ty:$val)>,
390*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
391*5ffd83dbSDimitry Andric}
392*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i32, atomic_store_32, regPlusImm, "ATOMIC_STORE_I32">;
393*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i64, atomic_store_64, regPlusImm, "ATOMIC_STORE_I64">;
3940b57cec5SDimitry Andric
3950b57cec5SDimitry Andric// Select stores with just a constant offset.
396*5ffd83dbSDimitry Andricmulticlass AStorePatOffsetOnly<ValueType ty, PatFrag kind, string inst> {
397*5ffd83dbSDimitry Andric  def : Pat<(kind imm:$off, ty:$val),
398*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, imm:$off, (CONST_I32 0), ty:$val)>,
399*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
400*5ffd83dbSDimitry Andric  def : Pat<(kind imm:$off, ty:$val),
401*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, imm:$off, (CONST_I64 0), ty:$val)>,
402*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
403*5ffd83dbSDimitry Andric}
404*5ffd83dbSDimitry Andricdefm : AStorePatOffsetOnly<i32, atomic_store_32, "ATOMIC_STORE_I32">;
405*5ffd83dbSDimitry Andricdefm : AStorePatOffsetOnly<i64, atomic_store_64, "ATOMIC_STORE_I64">;
4060b57cec5SDimitry Andric
407*5ffd83dbSDimitry Andricmulticlass AStorePatGlobalAddrOffOnly<ValueType ty, PatFrag kind, string inst> {
408*5ffd83dbSDimitry Andric  def : Pat<(kind (WebAssemblywrapper tglobaladdr:$off), ty:$val),
409*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>,
410*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
411*5ffd83dbSDimitry Andric  def : Pat<(kind (WebAssemblywrapper tglobaladdr:$off), ty:$val),
412*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, tglobaladdr:$off, (CONST_I64 0), ty:$val)>,
413*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
414*5ffd83dbSDimitry Andric}
415*5ffd83dbSDimitry Andricdefm : AStorePatGlobalAddrOffOnly<i32, atomic_store_32, "ATOMIC_STORE_I32">;
416*5ffd83dbSDimitry Andricdefm : AStorePatGlobalAddrOffOnly<i64, atomic_store_64, "ATOMIC_STORE_I64">;
4170b57cec5SDimitry Andric
4180b57cec5SDimitry Andric} // Predicates = [HasAtomics]
4190b57cec5SDimitry Andric
4200b57cec5SDimitry Andric// Truncating stores.
4210b57cec5SDimitry Andricdefm ATOMIC_STORE8_I32 : AtomicStore<I32, "i32.atomic.store8", 0x19>;
4220b57cec5SDimitry Andricdefm ATOMIC_STORE16_I32 : AtomicStore<I32, "i32.atomic.store16", 0x1a>;
4230b57cec5SDimitry Andricdefm ATOMIC_STORE8_I64 : AtomicStore<I64, "i64.atomic.store8", 0x1b>;
4240b57cec5SDimitry Andricdefm ATOMIC_STORE16_I64 : AtomicStore<I64, "i64.atomic.store16", 0x1c>;
4250b57cec5SDimitry Andricdefm ATOMIC_STORE32_I64 : AtomicStore<I64, "i64.atomic.store32", 0x1d>;
4260b57cec5SDimitry Andric
4270b57cec5SDimitry Andric// Fragments for truncating stores.
4280b57cec5SDimitry Andric
4290b57cec5SDimitry Andric// We don't have single truncating atomic store instructions. For 32-bit
4300b57cec5SDimitry Andric// instructions, we just need to match bare atomic stores. On the other hand,
4310b57cec5SDimitry Andric// truncating stores from i64 values are once truncated to i32 first.
4320b57cec5SDimitry Andricclass trunc_astore_64<PatFrag kind> :
4330b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val),
4340b57cec5SDimitry Andric          (kind node:$addr, (i32 (trunc (i64 node:$val))))>;
4350b57cec5SDimitry Andricdef trunc_astore_8_64 : trunc_astore_64<atomic_store_8>;
4360b57cec5SDimitry Andricdef trunc_astore_16_64 : trunc_astore_64<atomic_store_16>;
4370b57cec5SDimitry Andricdef trunc_astore_32_64 : trunc_astore_64<atomic_store_32>;
4380b57cec5SDimitry Andric
4390b57cec5SDimitry Andriclet Predicates = [HasAtomics] in {
4400b57cec5SDimitry Andric
4410b57cec5SDimitry Andric// Truncating stores with no constant offset
442*5ffd83dbSDimitry Andricdefm : AStorePatNoOffset<i32, atomic_store_8, "ATOMIC_STORE8_I32">;
443*5ffd83dbSDimitry Andricdefm : AStorePatNoOffset<i32, atomic_store_16, "ATOMIC_STORE16_I32">;
444*5ffd83dbSDimitry Andricdefm : AStorePatNoOffset<i64, trunc_astore_8_64, "ATOMIC_STORE8_I64">;
445*5ffd83dbSDimitry Andricdefm : AStorePatNoOffset<i64, trunc_astore_16_64, "ATOMIC_STORE16_I64">;
446*5ffd83dbSDimitry Andricdefm : AStorePatNoOffset<i64, trunc_astore_32_64, "ATOMIC_STORE32_I64">;
4470b57cec5SDimitry Andric
4480b57cec5SDimitry Andric// Truncating stores with a constant offset
449*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i32, atomic_store_8, regPlusImm, "ATOMIC_STORE8_I32">;
450*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i32, atomic_store_16, regPlusImm, "ATOMIC_STORE16_I32">;
451*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i64, trunc_astore_8_64, regPlusImm, "ATOMIC_STORE8_I64">;
452*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i64, trunc_astore_16_64, regPlusImm,
453*5ffd83dbSDimitry Andric                       "ATOMIC_STORE16_I64">;
454*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i64, trunc_astore_32_64, regPlusImm,
455*5ffd83dbSDimitry Andric                       "ATOMIC_STORE32_I64">;
456*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i32, atomic_store_8, or_is_add, "ATOMIC_STORE8_I32">;
457*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i32, atomic_store_16, or_is_add, "ATOMIC_STORE16_I32">;
458*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i64, trunc_astore_8_64, or_is_add, "ATOMIC_STORE8_I64">;
459*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i64, trunc_astore_16_64, or_is_add,
460*5ffd83dbSDimitry Andric                       "ATOMIC_STORE16_I64">;
461*5ffd83dbSDimitry Andricdefm : AStorePatImmOff<i64, trunc_astore_32_64, or_is_add,
462*5ffd83dbSDimitry Andric                       "ATOMIC_STORE32_I64">;
4630b57cec5SDimitry Andric
4640b57cec5SDimitry Andric// Truncating stores with just a constant offset
465*5ffd83dbSDimitry Andricdefm : AStorePatOffsetOnly<i32, atomic_store_8, "ATOMIC_STORE8_I32">;
466*5ffd83dbSDimitry Andricdefm : AStorePatOffsetOnly<i32, atomic_store_16, "ATOMIC_STORE16_I32">;
467*5ffd83dbSDimitry Andricdefm : AStorePatOffsetOnly<i64, trunc_astore_8_64, "ATOMIC_STORE8_I64">;
468*5ffd83dbSDimitry Andricdefm : AStorePatOffsetOnly<i64, trunc_astore_16_64, "ATOMIC_STORE16_I64">;
469*5ffd83dbSDimitry Andricdefm : AStorePatOffsetOnly<i64, trunc_astore_32_64, "ATOMIC_STORE32_I64">;
4700b57cec5SDimitry Andric
471*5ffd83dbSDimitry Andricdefm : AStorePatGlobalAddrOffOnly<i32, atomic_store_8, "ATOMIC_STORE8_I32">;
472*5ffd83dbSDimitry Andricdefm : AStorePatGlobalAddrOffOnly<i32, atomic_store_16, "ATOMIC_STORE16_I32">;
473*5ffd83dbSDimitry Andricdefm : AStorePatGlobalAddrOffOnly<i64, trunc_astore_8_64, "ATOMIC_STORE8_I64">;
474*5ffd83dbSDimitry Andricdefm : AStorePatGlobalAddrOffOnly<i64, trunc_astore_16_64, "ATOMIC_STORE16_I64">;
475*5ffd83dbSDimitry Andricdefm : AStorePatGlobalAddrOffOnly<i64, trunc_astore_32_64, "ATOMIC_STORE32_I64">;
4760b57cec5SDimitry Andric
4770b57cec5SDimitry Andric} // Predicates = [HasAtomics]
4780b57cec5SDimitry Andric
4790b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
4800b57cec5SDimitry Andric// Atomic binary read-modify-writes
4810b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
4820b57cec5SDimitry Andric
4830b57cec5SDimitry Andricmulticlass WebAssemblyBinRMW<WebAssemblyRegClass rc, string name,
4840b57cec5SDimitry Andric                             int atomic_op> {
485*5ffd83dbSDimitry Andric  defm "_A32" :
4860b57cec5SDimitry Andric    ATOMIC_I<(outs rc:$dst),
4870b57cec5SDimitry Andric             (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
4880b57cec5SDimitry Andric             (outs), (ins P2Align:$p2align, offset32_op:$off), [],
4890b57cec5SDimitry Andric             !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $val"),
490*5ffd83dbSDimitry Andric             !strconcat(name, "\t${off}${p2align}"), atomic_op, "false">;
491*5ffd83dbSDimitry Andric  defm "_A64" :
492*5ffd83dbSDimitry Andric    ATOMIC_I<(outs rc:$dst),
493*5ffd83dbSDimitry Andric             (ins P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$val),
494*5ffd83dbSDimitry Andric             (outs), (ins P2Align:$p2align, offset64_op:$off), [],
495*5ffd83dbSDimitry Andric             !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $val"),
496*5ffd83dbSDimitry Andric             !strconcat(name, "\t${off}${p2align}"), atomic_op, "true">;
4970b57cec5SDimitry Andric}
4980b57cec5SDimitry Andric
4990b57cec5SDimitry Andricdefm ATOMIC_RMW_ADD_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.add", 0x1e>;
5000b57cec5SDimitry Andricdefm ATOMIC_RMW_ADD_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.add", 0x1f>;
5010b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_ADD_I32 :
5020b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw8.add_u", 0x20>;
5030b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_ADD_I32 :
5040b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw16.add_u", 0x21>;
5050b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_ADD_I64 :
5060b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw8.add_u", 0x22>;
5070b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_ADD_I64 :
5080b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw16.add_u", 0x23>;
5090b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_ADD_I64 :
5100b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw32.add_u", 0x24>;
5110b57cec5SDimitry Andric
5120b57cec5SDimitry Andricdefm ATOMIC_RMW_SUB_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.sub", 0x25>;
5130b57cec5SDimitry Andricdefm ATOMIC_RMW_SUB_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.sub", 0x26>;
5140b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_SUB_I32 :
5150b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw8.sub_u", 0x27>;
5160b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_SUB_I32 :
5170b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw16.sub_u", 0x28>;
5180b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_SUB_I64 :
5190b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw8.sub_u", 0x29>;
5200b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_SUB_I64 :
5210b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw16.sub_u", 0x2a>;
5220b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_SUB_I64 :
5230b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw32.sub_u", 0x2b>;
5240b57cec5SDimitry Andric
5250b57cec5SDimitry Andricdefm ATOMIC_RMW_AND_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.and", 0x2c>;
5260b57cec5SDimitry Andricdefm ATOMIC_RMW_AND_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.and", 0x2d>;
5270b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_AND_I32 :
5280b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw8.and_u", 0x2e>;
5290b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_AND_I32 :
5300b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw16.and_u", 0x2f>;
5310b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_AND_I64 :
5320b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw8.and_u", 0x30>;
5330b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_AND_I64 :
5340b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw16.and_u", 0x31>;
5350b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_AND_I64 :
5360b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw32.and_u", 0x32>;
5370b57cec5SDimitry Andric
5380b57cec5SDimitry Andricdefm ATOMIC_RMW_OR_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.or", 0x33>;
5390b57cec5SDimitry Andricdefm ATOMIC_RMW_OR_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.or", 0x34>;
5400b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_OR_I32 :
5410b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw8.or_u", 0x35>;
5420b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_OR_I32 :
5430b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw16.or_u", 0x36>;
5440b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_OR_I64 :
5450b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw8.or_u", 0x37>;
5460b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_OR_I64 :
5470b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw16.or_u", 0x38>;
5480b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_OR_I64 :
5490b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw32.or_u", 0x39>;
5500b57cec5SDimitry Andric
5510b57cec5SDimitry Andricdefm ATOMIC_RMW_XOR_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.xor", 0x3a>;
5520b57cec5SDimitry Andricdefm ATOMIC_RMW_XOR_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.xor", 0x3b>;
5530b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_XOR_I32 :
5540b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw8.xor_u", 0x3c>;
5550b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_XOR_I32 :
5560b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw16.xor_u", 0x3d>;
5570b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_XOR_I64 :
5580b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw8.xor_u", 0x3e>;
5590b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_XOR_I64 :
5600b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw16.xor_u", 0x3f>;
5610b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_XOR_I64 :
5620b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw32.xor_u", 0x40>;
5630b57cec5SDimitry Andric
5640b57cec5SDimitry Andricdefm ATOMIC_RMW_XCHG_I32 :
5650b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw.xchg", 0x41>;
5660b57cec5SDimitry Andricdefm ATOMIC_RMW_XCHG_I64 :
5670b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw.xchg", 0x42>;
5680b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_XCHG_I32 :
5690b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw8.xchg_u", 0x43>;
5700b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_XCHG_I32 :
5710b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw16.xchg_u", 0x44>;
5720b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_XCHG_I64 :
5730b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw8.xchg_u", 0x45>;
5740b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_XCHG_I64 :
5750b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw16.xchg_u", 0x46>;
5760b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_XCHG_I64 :
5770b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw32.xchg_u", 0x47>;
5780b57cec5SDimitry Andric
5790b57cec5SDimitry Andric// Select binary RMWs with no constant offset.
580*5ffd83dbSDimitry Andricmulticlass BinRMWPatNoOffset<ValueType ty, PatFrag kind, string inst> {
581*5ffd83dbSDimitry Andric  def : Pat<(ty (kind I32:$addr, ty:$val)),
582*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, 0, I32:$addr, ty:$val)>,
583*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
584*5ffd83dbSDimitry Andric  def : Pat<(ty (kind I64:$addr, ty:$val)),
585*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, 0, I64:$addr, ty:$val)>,
586*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
587*5ffd83dbSDimitry Andric}
5880b57cec5SDimitry Andric
5890b57cec5SDimitry Andric// Select binary RMWs with a constant offset.
5900b57cec5SDimitry Andric
5910b57cec5SDimitry Andric// Pattern with address + immediate offset
592*5ffd83dbSDimitry Andricmulticlass BinRMWPatImmOff<ValueType ty, PatFrag kind, PatFrag operand,
593*5ffd83dbSDimitry Andric                           string inst> {
594*5ffd83dbSDimitry Andric  def : Pat<(ty (kind (operand I32:$addr, imm:$off), ty:$val)),
595*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, ty:$val)>,
596*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
597*5ffd83dbSDimitry Andric  def : Pat<(ty (kind (operand I64:$addr, imm:$off), ty:$val)),
598*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, ty:$val)>,
599*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
600*5ffd83dbSDimitry Andric}
6010b57cec5SDimitry Andric
6020b57cec5SDimitry Andric// Select binary RMWs with just a constant offset.
603*5ffd83dbSDimitry Andricmulticlass BinRMWPatOffsetOnly<ValueType ty, PatFrag kind, string inst> {
604*5ffd83dbSDimitry Andric  def : Pat<(ty (kind imm:$off, ty:$val)),
605*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, imm:$off, (CONST_I32 0), ty:$val)>,
606*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
607*5ffd83dbSDimitry Andric  def : Pat<(ty (kind imm:$off, ty:$val)),
608*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, imm:$off, (CONST_I64 0), ty:$val)>,
609*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
610*5ffd83dbSDimitry Andric}
6110b57cec5SDimitry Andric
612*5ffd83dbSDimitry Andricmulticlass BinRMWPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> {
613*5ffd83dbSDimitry Andric  def : Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off), ty:$val)),
614*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>,
615*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
616*5ffd83dbSDimitry Andric  def : Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off), ty:$val)),
617*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, tglobaladdr:$off, (CONST_I64 0), ty:$val)>,
618*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
619*5ffd83dbSDimitry Andric}
6200b57cec5SDimitry Andric
6210b57cec5SDimitry Andric// Patterns for various addressing modes.
622*5ffd83dbSDimitry Andricmulticlass BinRMWPattern<PatFrag rmw_32, PatFrag rmw_64, string inst_32,
623*5ffd83dbSDimitry Andric                         string inst_64> {
624*5ffd83dbSDimitry Andric  defm : BinRMWPatNoOffset<i32, rmw_32, inst_32>;
625*5ffd83dbSDimitry Andric  defm : BinRMWPatNoOffset<i64, rmw_64, inst_64>;
6260b57cec5SDimitry Andric
627*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i32, rmw_32, regPlusImm, inst_32>;
628*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i64, rmw_64, regPlusImm, inst_64>;
629*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i32, rmw_32, or_is_add, inst_32>;
630*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i64, rmw_64, or_is_add, inst_64>;
6310b57cec5SDimitry Andric
632*5ffd83dbSDimitry Andric  defm : BinRMWPatOffsetOnly<i32, rmw_32, inst_32>;
633*5ffd83dbSDimitry Andric  defm : BinRMWPatOffsetOnly<i64, rmw_64, inst_64>;
6340b57cec5SDimitry Andric
635*5ffd83dbSDimitry Andric  defm : BinRMWPatGlobalAddrOffOnly<i32, rmw_32, inst_32>;
636*5ffd83dbSDimitry Andric  defm : BinRMWPatGlobalAddrOffOnly<i64, rmw_64, inst_64>;
6370b57cec5SDimitry Andric}
6380b57cec5SDimitry Andric
6390b57cec5SDimitry Andriclet Predicates = [HasAtomics] in {
640*5ffd83dbSDimitry Andricdefm : BinRMWPattern<atomic_load_add_32, atomic_load_add_64,
641*5ffd83dbSDimitry Andric                     "ATOMIC_RMW_ADD_I32", "ATOMIC_RMW_ADD_I64">;
642*5ffd83dbSDimitry Andricdefm : BinRMWPattern<atomic_load_sub_32, atomic_load_sub_64,
643*5ffd83dbSDimitry Andric                     "ATOMIC_RMW_SUB_I32", "ATOMIC_RMW_SUB_I64">;
644*5ffd83dbSDimitry Andricdefm : BinRMWPattern<atomic_load_and_32, atomic_load_and_64,
645*5ffd83dbSDimitry Andric                     "ATOMIC_RMW_AND_I32", "ATOMIC_RMW_AND_I64">;
646*5ffd83dbSDimitry Andricdefm : BinRMWPattern<atomic_load_or_32, atomic_load_or_64,
647*5ffd83dbSDimitry Andric                     "ATOMIC_RMW_OR_I32", "ATOMIC_RMW_OR_I64">;
648*5ffd83dbSDimitry Andricdefm : BinRMWPattern<atomic_load_xor_32, atomic_load_xor_64,
649*5ffd83dbSDimitry Andric                     "ATOMIC_RMW_XOR_I32", "ATOMIC_RMW_XOR_I64">;
650*5ffd83dbSDimitry Andricdefm : BinRMWPattern<atomic_swap_32, atomic_swap_64,
651*5ffd83dbSDimitry Andric                     "ATOMIC_RMW_XCHG_I32", "ATOMIC_RMW_XCHG_I64">;
6520b57cec5SDimitry Andric} // Predicates = [HasAtomics]
6530b57cec5SDimitry Andric
6540b57cec5SDimitry Andric// Truncating & zero-extending binary RMW patterns.
6550b57cec5SDimitry Andric// These are combined patterns of truncating store patterns and zero-extending
6560b57cec5SDimitry Andric// load patterns above.
6570b57cec5SDimitry Andricclass zext_bin_rmw_8_32<PatFrag kind> :
6580b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val),
6590b57cec5SDimitry Andric          (and (i32 (kind node:$addr, node:$val)), 255)>;
6600b57cec5SDimitry Andricclass zext_bin_rmw_16_32<PatFrag kind> :
6610b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val),
6620b57cec5SDimitry Andric          (and (i32 (kind node:$addr, node:$val)), 65535)>;
6630b57cec5SDimitry Andricclass zext_bin_rmw_8_64<PatFrag kind> :
6640b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val),
6650b57cec5SDimitry Andric    (and (i64 (anyext (i32 (kind node:$addr,
6660b57cec5SDimitry Andric                                 (i32 (trunc (i64 node:$val))))))), 255)>;
6670b57cec5SDimitry Andricclass zext_bin_rmw_16_64<PatFrag kind> :
6680b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val),
6690b57cec5SDimitry Andric    (and (i64 (anyext (i32 (kind node:$addr,
6700b57cec5SDimitry Andric                                 (i32 (trunc (i64 node:$val))))))), 65535)>;
6710b57cec5SDimitry Andricclass zext_bin_rmw_32_64<PatFrag kind> :
6720b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val),
6730b57cec5SDimitry Andric          (zext (i32 (kind node:$addr, (i32 (trunc (i64 node:$val))))))>;
6740b57cec5SDimitry Andric
6750b57cec5SDimitry Andric// Truncating & sign-extending binary RMW patterns.
6760b57cec5SDimitry Andric// These are combined patterns of truncating store patterns and sign-extending
6770b57cec5SDimitry Andric// load patterns above. We match subword RMWs (for 32-bit) and anyext RMWs (for
6780b57cec5SDimitry Andric// 64-bit) and select a zext RMW; the next instruction will be sext_inreg which
6790b57cec5SDimitry Andric// is selected by itself.
6800b57cec5SDimitry Andricclass sext_bin_rmw_8_32<PatFrag kind> :
6810b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val), (kind node:$addr, node:$val)>;
6820b57cec5SDimitry Andricclass sext_bin_rmw_16_32<PatFrag kind> : sext_bin_rmw_8_32<kind>;
6830b57cec5SDimitry Andricclass sext_bin_rmw_8_64<PatFrag kind> :
6840b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val),
6850b57cec5SDimitry Andric          (anyext (i32 (kind node:$addr, (i32 (trunc (i64 node:$val))))))>;
6860b57cec5SDimitry Andricclass sext_bin_rmw_16_64<PatFrag kind> : sext_bin_rmw_8_64<kind>;
6870b57cec5SDimitry Andric// 32->64 sext RMW gets selected as i32.atomic.rmw.***, i64.extend_i32_s
6880b57cec5SDimitry Andric
6890b57cec5SDimitry Andric// Patterns for various addressing modes for truncating-extending binary RMWs.
6900b57cec5SDimitry Andricmulticlass BinRMWTruncExtPattern<
6910b57cec5SDimitry Andric  PatFrag rmw_8, PatFrag rmw_16, PatFrag rmw_32, PatFrag rmw_64,
6920b57cec5SDimitry Andric  NI inst8_32, NI inst16_32, NI inst8_64, NI inst16_64, NI inst32_64> {
6930b57cec5SDimitry Andric  // Truncating-extending binary RMWs with no constant offset
694*5ffd83dbSDimitry Andric  defm : BinRMWPatNoOffset<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
695*5ffd83dbSDimitry Andric  defm : BinRMWPatNoOffset<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
696*5ffd83dbSDimitry Andric  defm : BinRMWPatNoOffset<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
697*5ffd83dbSDimitry Andric  defm : BinRMWPatNoOffset<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
698*5ffd83dbSDimitry Andric  defm : BinRMWPatNoOffset<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
6990b57cec5SDimitry Andric
700*5ffd83dbSDimitry Andric  defm : BinRMWPatNoOffset<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
701*5ffd83dbSDimitry Andric  defm : BinRMWPatNoOffset<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
702*5ffd83dbSDimitry Andric  defm : BinRMWPatNoOffset<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
703*5ffd83dbSDimitry Andric  defm : BinRMWPatNoOffset<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
7040b57cec5SDimitry Andric
7050b57cec5SDimitry Andric  // Truncating-extending binary RMWs with a constant offset
706*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i32, zext_bin_rmw_8_32<rmw_8>, regPlusImm, inst8_32>;
707*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i32, zext_bin_rmw_16_32<rmw_16>, regPlusImm,
708*5ffd83dbSDimitry Andric                         inst16_32>;
709*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i64, zext_bin_rmw_8_64<rmw_8>, regPlusImm, inst8_64>;
710*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i64, zext_bin_rmw_16_64<rmw_16>, regPlusImm,
711*5ffd83dbSDimitry Andric                         inst16_64>;
712*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i64, zext_bin_rmw_32_64<rmw_32>, regPlusImm,
713*5ffd83dbSDimitry Andric                         inst32_64>;
714*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i32, zext_bin_rmw_8_32<rmw_8>, or_is_add, inst8_32>;
715*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i32, zext_bin_rmw_16_32<rmw_16>, or_is_add, inst16_32>;
716*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i64, zext_bin_rmw_8_64<rmw_8>, or_is_add, inst8_64>;
717*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i64, zext_bin_rmw_16_64<rmw_16>, or_is_add, inst16_64>;
718*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i64, zext_bin_rmw_32_64<rmw_32>, or_is_add, inst32_64>;
7190b57cec5SDimitry Andric
720*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i32, sext_bin_rmw_8_32<rmw_8>, regPlusImm, inst8_32>;
721*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i32, sext_bin_rmw_16_32<rmw_16>, regPlusImm,
722*5ffd83dbSDimitry Andric                         inst16_32>;
723*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i64, sext_bin_rmw_8_64<rmw_8>, regPlusImm, inst8_64>;
724*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i64, sext_bin_rmw_16_64<rmw_16>, regPlusImm,
725*5ffd83dbSDimitry Andric                         inst16_64>;
726*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i32, sext_bin_rmw_8_32<rmw_8>, or_is_add, inst8_32>;
727*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i32, sext_bin_rmw_16_32<rmw_16>, or_is_add, inst16_32>;
728*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i64, sext_bin_rmw_8_64<rmw_8>, or_is_add, inst8_64>;
729*5ffd83dbSDimitry Andric  defm : BinRMWPatImmOff<i64, sext_bin_rmw_16_64<rmw_16>, or_is_add, inst16_64>;
7300b57cec5SDimitry Andric
7310b57cec5SDimitry Andric  // Truncating-extending binary RMWs with just a constant offset
732*5ffd83dbSDimitry Andric  defm : BinRMWPatOffsetOnly<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
733*5ffd83dbSDimitry Andric  defm : BinRMWPatOffsetOnly<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
734*5ffd83dbSDimitry Andric  defm : BinRMWPatOffsetOnly<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
735*5ffd83dbSDimitry Andric  defm : BinRMWPatOffsetOnly<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
736*5ffd83dbSDimitry Andric  defm : BinRMWPatOffsetOnly<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
7370b57cec5SDimitry Andric
738*5ffd83dbSDimitry Andric  defm : BinRMWPatOffsetOnly<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
739*5ffd83dbSDimitry Andric  defm : BinRMWPatOffsetOnly<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
740*5ffd83dbSDimitry Andric  defm : BinRMWPatOffsetOnly<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
741*5ffd83dbSDimitry Andric  defm : BinRMWPatOffsetOnly<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
7420b57cec5SDimitry Andric
743*5ffd83dbSDimitry Andric  defm : BinRMWPatGlobalAddrOffOnly<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
744*5ffd83dbSDimitry Andric  defm : BinRMWPatGlobalAddrOffOnly<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
745*5ffd83dbSDimitry Andric  defm : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
746*5ffd83dbSDimitry Andric  defm : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
747*5ffd83dbSDimitry Andric  defm : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
7480b57cec5SDimitry Andric
749*5ffd83dbSDimitry Andric  defm : BinRMWPatGlobalAddrOffOnly<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
750*5ffd83dbSDimitry Andric  defm : BinRMWPatGlobalAddrOffOnly<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
751*5ffd83dbSDimitry Andric  defm : BinRMWPatGlobalAddrOffOnly<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
752*5ffd83dbSDimitry Andric  defm : BinRMWPatGlobalAddrOffOnly<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
7530b57cec5SDimitry Andric}
7540b57cec5SDimitry Andric
7550b57cec5SDimitry Andriclet Predicates = [HasAtomics] in {
7560b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern<
7570b57cec5SDimitry Andric  atomic_load_add_8, atomic_load_add_16, atomic_load_add_32, atomic_load_add_64,
758*5ffd83dbSDimitry Andric  "ATOMIC_RMW8_U_ADD_I32", "ATOMIC_RMW16_U_ADD_I32",
759*5ffd83dbSDimitry Andric  "ATOMIC_RMW8_U_ADD_I64", "ATOMIC_RMW16_U_ADD_I64", "ATOMIC_RMW32_U_ADD_I64">;
7600b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern<
7610b57cec5SDimitry Andric  atomic_load_sub_8, atomic_load_sub_16, atomic_load_sub_32, atomic_load_sub_64,
762*5ffd83dbSDimitry Andric  "ATOMIC_RMW8_U_SUB_I32", "ATOMIC_RMW16_U_SUB_I32",
763*5ffd83dbSDimitry Andric  "ATOMIC_RMW8_U_SUB_I64", "ATOMIC_RMW16_U_SUB_I64", "ATOMIC_RMW32_U_SUB_I64">;
7640b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern<
7650b57cec5SDimitry Andric  atomic_load_and_8, atomic_load_and_16, atomic_load_and_32, atomic_load_and_64,
766*5ffd83dbSDimitry Andric  "ATOMIC_RMW8_U_AND_I32", "ATOMIC_RMW16_U_AND_I32",
767*5ffd83dbSDimitry Andric  "ATOMIC_RMW8_U_AND_I64", "ATOMIC_RMW16_U_AND_I64", "ATOMIC_RMW32_U_AND_I64">;
7680b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern<
7690b57cec5SDimitry Andric  atomic_load_or_8, atomic_load_or_16, atomic_load_or_32, atomic_load_or_64,
770*5ffd83dbSDimitry Andric  "ATOMIC_RMW8_U_OR_I32", "ATOMIC_RMW16_U_OR_I32",
771*5ffd83dbSDimitry Andric  "ATOMIC_RMW8_U_OR_I64", "ATOMIC_RMW16_U_OR_I64", "ATOMIC_RMW32_U_OR_I64">;
7720b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern<
7730b57cec5SDimitry Andric  atomic_load_xor_8, atomic_load_xor_16, atomic_load_xor_32, atomic_load_xor_64,
774*5ffd83dbSDimitry Andric  "ATOMIC_RMW8_U_XOR_I32", "ATOMIC_RMW16_U_XOR_I32",
775*5ffd83dbSDimitry Andric  "ATOMIC_RMW8_U_XOR_I64", "ATOMIC_RMW16_U_XOR_I64", "ATOMIC_RMW32_U_XOR_I64">;
7760b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern<
7770b57cec5SDimitry Andric  atomic_swap_8, atomic_swap_16, atomic_swap_32, atomic_swap_64,
778*5ffd83dbSDimitry Andric  "ATOMIC_RMW8_U_XCHG_I32", "ATOMIC_RMW16_U_XCHG_I32",
779*5ffd83dbSDimitry Andric  "ATOMIC_RMW8_U_XCHG_I64", "ATOMIC_RMW16_U_XCHG_I64",
780*5ffd83dbSDimitry Andric  "ATOMIC_RMW32_U_XCHG_I64">;
7810b57cec5SDimitry Andric} // Predicates = [HasAtomics]
7820b57cec5SDimitry Andric
7830b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
7840b57cec5SDimitry Andric// Atomic ternary read-modify-writes
7850b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
7860b57cec5SDimitry Andric
7870b57cec5SDimitry Andric// TODO LLVM IR's cmpxchg instruction returns a pair of {loaded value, success
7880b57cec5SDimitry Andric// flag}. When we use the success flag or both values, we can't make use of i64
7890b57cec5SDimitry Andric// truncate/extend versions of instructions for now, which is suboptimal.
7900b57cec5SDimitry Andric// Consider adding a pass after instruction selection that optimizes this case
7910b57cec5SDimitry Andric// if it is frequent.
7920b57cec5SDimitry Andric
7930b57cec5SDimitry Andricmulticlass WebAssemblyTerRMW<WebAssemblyRegClass rc, string name,
7940b57cec5SDimitry Andric                             int atomic_op> {
795*5ffd83dbSDimitry Andric  defm "_A32" :
7960b57cec5SDimitry Andric    ATOMIC_I<(outs rc:$dst),
7970b57cec5SDimitry Andric             (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$exp,
7980b57cec5SDimitry Andric                  rc:$new_),
7990b57cec5SDimitry Andric             (outs), (ins P2Align:$p2align, offset32_op:$off), [],
8000b57cec5SDimitry Andric             !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $exp, $new_"),
801*5ffd83dbSDimitry Andric             !strconcat(name, "\t${off}${p2align}"), atomic_op, "false">;
802*5ffd83dbSDimitry Andric  defm "_A64" :
803*5ffd83dbSDimitry Andric    ATOMIC_I<(outs rc:$dst),
804*5ffd83dbSDimitry Andric             (ins P2Align:$p2align, offset64_op:$off, I64:$addr, rc:$exp,
805*5ffd83dbSDimitry Andric                  rc:$new_),
806*5ffd83dbSDimitry Andric             (outs), (ins P2Align:$p2align, offset64_op:$off), [],
807*5ffd83dbSDimitry Andric             !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $exp, $new_"),
808*5ffd83dbSDimitry Andric             !strconcat(name, "\t${off}${p2align}"), atomic_op, "true">;
8090b57cec5SDimitry Andric}
8100b57cec5SDimitry Andric
8110b57cec5SDimitry Andricdefm ATOMIC_RMW_CMPXCHG_I32 :
8120b57cec5SDimitry Andric  WebAssemblyTerRMW<I32, "i32.atomic.rmw.cmpxchg", 0x48>;
8130b57cec5SDimitry Andricdefm ATOMIC_RMW_CMPXCHG_I64 :
8140b57cec5SDimitry Andric  WebAssemblyTerRMW<I64, "i64.atomic.rmw.cmpxchg", 0x49>;
8150b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_CMPXCHG_I32 :
8160b57cec5SDimitry Andric  WebAssemblyTerRMW<I32, "i32.atomic.rmw8.cmpxchg_u", 0x4a>;
8170b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_CMPXCHG_I32 :
8180b57cec5SDimitry Andric  WebAssemblyTerRMW<I32, "i32.atomic.rmw16.cmpxchg_u", 0x4b>;
8190b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_CMPXCHG_I64 :
8200b57cec5SDimitry Andric  WebAssemblyTerRMW<I64, "i64.atomic.rmw8.cmpxchg_u", 0x4c>;
8210b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_CMPXCHG_I64 :
8220b57cec5SDimitry Andric  WebAssemblyTerRMW<I64, "i64.atomic.rmw16.cmpxchg_u", 0x4d>;
8230b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_CMPXCHG_I64 :
8240b57cec5SDimitry Andric  WebAssemblyTerRMW<I64, "i64.atomic.rmw32.cmpxchg_u", 0x4e>;
8250b57cec5SDimitry Andric
8260b57cec5SDimitry Andric// Select ternary RMWs with no constant offset.
827*5ffd83dbSDimitry Andricmulticlass TerRMWPatNoOffset<ValueType ty, PatFrag kind, string inst> {
828*5ffd83dbSDimitry Andric  def : Pat<(ty (kind I32:$addr, ty:$exp, ty:$new)),
829*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, 0, I32:$addr, ty:$exp, ty:$new)>,
830*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
831*5ffd83dbSDimitry Andric  def : Pat<(ty (kind I64:$addr, ty:$exp, ty:$new)),
832*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, 0, I64:$addr, ty:$exp, ty:$new)>,
833*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
834*5ffd83dbSDimitry Andric}
8350b57cec5SDimitry Andric
8360b57cec5SDimitry Andric// Select ternary RMWs with a constant offset.
8370b57cec5SDimitry Andric
8380b57cec5SDimitry Andric// Pattern with address + immediate offset
839*5ffd83dbSDimitry Andricmulticlass TerRMWPatImmOff<ValueType ty, PatFrag kind, PatFrag operand,
840*5ffd83dbSDimitry Andric                           string inst> {
841*5ffd83dbSDimitry Andric  def : Pat<(ty (kind (operand I32:$addr, imm:$off), ty:$exp, ty:$new)),
842*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, imm:$off, I32:$addr, ty:$exp, ty:$new)>,
843*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
844*5ffd83dbSDimitry Andric  def : Pat<(ty (kind (operand I64:$addr, imm:$off), ty:$exp, ty:$new)),
845*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, imm:$off, I64:$addr, ty:$exp, ty:$new)>,
846*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
847*5ffd83dbSDimitry Andric}
8480b57cec5SDimitry Andric
8490b57cec5SDimitry Andric// Select ternary RMWs with just a constant offset.
850*5ffd83dbSDimitry Andricmulticlass TerRMWPatOffsetOnly<ValueType ty, PatFrag kind, string inst> {
851*5ffd83dbSDimitry Andric  def : Pat<(ty (kind imm:$off, ty:$exp, ty:$new)),
852*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, imm:$off, (CONST_I32 0), ty:$exp,
853*5ffd83dbSDimitry Andric              ty:$new)>;
854*5ffd83dbSDimitry Andric  def : Pat<(ty (kind imm:$off, ty:$exp, ty:$new)),
855*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, imm:$off, (CONST_I64 0), ty:$exp,
856*5ffd83dbSDimitry Andric              ty:$new)>;
857*5ffd83dbSDimitry Andric}
8580b57cec5SDimitry Andric
859*5ffd83dbSDimitry Andricmulticlass TerRMWPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, string inst> {
860*5ffd83dbSDimitry Andric  def : Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off), ty:$exp, ty:$new)),
861*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A32) 0, tglobaladdr:$off, (CONST_I32 0), ty:$exp,
862*5ffd83dbSDimitry Andric              ty:$new)>,
863*5ffd83dbSDimitry Andric        Requires<[HasAddr32]>;
864*5ffd83dbSDimitry Andric  def : Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off), ty:$exp, ty:$new)),
865*5ffd83dbSDimitry Andric            (!cast<NI>(inst#_A64) 0, tglobaladdr:$off, (CONST_I64 0), ty:$exp,
866*5ffd83dbSDimitry Andric              ty:$new)>,
867*5ffd83dbSDimitry Andric        Requires<[HasAddr64]>;
868*5ffd83dbSDimitry Andric}
8690b57cec5SDimitry Andric
8700b57cec5SDimitry Andric// Patterns for various addressing modes.
871*5ffd83dbSDimitry Andricmulticlass TerRMWPattern<PatFrag rmw_32, PatFrag rmw_64, string inst_32,
872*5ffd83dbSDimitry Andric                         string inst_64> {
873*5ffd83dbSDimitry Andric  defm : TerRMWPatNoOffset<i32, rmw_32, inst_32>;
874*5ffd83dbSDimitry Andric  defm : TerRMWPatNoOffset<i64, rmw_64, inst_64>;
8750b57cec5SDimitry Andric
876*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i32, rmw_32, regPlusImm, inst_32>;
877*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i64, rmw_64, regPlusImm, inst_64>;
878*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i32, rmw_32, or_is_add, inst_32>;
879*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i64, rmw_64, or_is_add, inst_64>;
8800b57cec5SDimitry Andric
881*5ffd83dbSDimitry Andric  defm : TerRMWPatOffsetOnly<i32, rmw_32, inst_32>;
882*5ffd83dbSDimitry Andric  defm : TerRMWPatOffsetOnly<i64, rmw_64, inst_64>;
8830b57cec5SDimitry Andric
884*5ffd83dbSDimitry Andric  defm : TerRMWPatGlobalAddrOffOnly<i32, rmw_32, inst_32>;
885*5ffd83dbSDimitry Andric  defm : TerRMWPatGlobalAddrOffOnly<i64, rmw_64, inst_64>;
8860b57cec5SDimitry Andric}
8870b57cec5SDimitry Andric
8880b57cec5SDimitry Andriclet Predicates = [HasAtomics] in
8890b57cec5SDimitry Andricdefm : TerRMWPattern<atomic_cmp_swap_32, atomic_cmp_swap_64,
890*5ffd83dbSDimitry Andric                     "ATOMIC_RMW_CMPXCHG_I32", "ATOMIC_RMW_CMPXCHG_I64">;
8910b57cec5SDimitry Andric
8920b57cec5SDimitry Andric// Truncating & zero-extending ternary RMW patterns.
8930b57cec5SDimitry Andric// DAG legalization & optimization before instruction selection may introduce
8940b57cec5SDimitry Andric// additional nodes such as anyext or assertzext depending on operand types.
8950b57cec5SDimitry Andricclass zext_ter_rmw_8_32<PatFrag kind> :
8960b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$exp, node:$new),
8970b57cec5SDimitry Andric          (and (i32 (kind node:$addr, node:$exp, node:$new)), 255)>;
8980b57cec5SDimitry Andricclass zext_ter_rmw_16_32<PatFrag kind> :
8990b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$exp, node:$new),
9000b57cec5SDimitry Andric          (and (i32 (kind node:$addr, node:$exp, node:$new)), 65535)>;
9010b57cec5SDimitry Andricclass zext_ter_rmw_8_64<PatFrag kind> :
9020b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$exp, node:$new),
9030b57cec5SDimitry Andric          (zext (i32 (assertzext (i32 (kind node:$addr,
9040b57cec5SDimitry Andric                                            (i32 (trunc (i64 node:$exp))),
9050b57cec5SDimitry Andric                                            (i32 (trunc (i64 node:$new))))))))>;
9060b57cec5SDimitry Andricclass zext_ter_rmw_16_64<PatFrag kind> : zext_ter_rmw_8_64<kind>;
9070b57cec5SDimitry Andricclass zext_ter_rmw_32_64<PatFrag kind> :
9080b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$exp, node:$new),
9090b57cec5SDimitry Andric          (zext (i32 (kind node:$addr,
9100b57cec5SDimitry Andric                           (i32 (trunc (i64 node:$exp))),
9110b57cec5SDimitry Andric                           (i32 (trunc (i64 node:$new))))))>;
9120b57cec5SDimitry Andric
9130b57cec5SDimitry Andric// Truncating & sign-extending ternary RMW patterns.
9140b57cec5SDimitry Andric// We match subword RMWs (for 32-bit) and anyext RMWs (for 64-bit) and select a
9150b57cec5SDimitry Andric// zext RMW; the next instruction will be sext_inreg which is selected by
9160b57cec5SDimitry Andric// itself.
9170b57cec5SDimitry Andricclass sext_ter_rmw_8_32<PatFrag kind> :
9180b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$exp, node:$new),
9190b57cec5SDimitry Andric          (kind node:$addr, node:$exp, node:$new)>;
9200b57cec5SDimitry Andricclass sext_ter_rmw_16_32<PatFrag kind> : sext_ter_rmw_8_32<kind>;
9210b57cec5SDimitry Andricclass sext_ter_rmw_8_64<PatFrag kind> :
9220b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$exp, node:$new),
9230b57cec5SDimitry Andric          (anyext (i32 (assertzext (i32
9240b57cec5SDimitry Andric            (kind node:$addr,
9250b57cec5SDimitry Andric                  (i32 (trunc (i64 node:$exp))),
9260b57cec5SDimitry Andric                  (i32 (trunc (i64 node:$new))))))))>;
9270b57cec5SDimitry Andricclass sext_ter_rmw_16_64<PatFrag kind> : sext_ter_rmw_8_64<kind>;
9280b57cec5SDimitry Andric// 32->64 sext RMW gets selected as i32.atomic.rmw.***, i64.extend_i32_s
9290b57cec5SDimitry Andric
9300b57cec5SDimitry Andric// Patterns for various addressing modes for truncating-extending ternary RMWs.
9310b57cec5SDimitry Andricmulticlass TerRMWTruncExtPattern<
9320b57cec5SDimitry Andric  PatFrag rmw_8, PatFrag rmw_16, PatFrag rmw_32, PatFrag rmw_64,
933*5ffd83dbSDimitry Andric  string inst8_32, string inst16_32, string inst8_64, string inst16_64,
934*5ffd83dbSDimitry Andric  string inst32_64> {
9350b57cec5SDimitry Andric  // Truncating-extending ternary RMWs with no constant offset
936*5ffd83dbSDimitry Andric  defm : TerRMWPatNoOffset<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>;
937*5ffd83dbSDimitry Andric  defm : TerRMWPatNoOffset<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>;
938*5ffd83dbSDimitry Andric  defm : TerRMWPatNoOffset<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>;
939*5ffd83dbSDimitry Andric  defm : TerRMWPatNoOffset<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>;
940*5ffd83dbSDimitry Andric  defm : TerRMWPatNoOffset<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>;
9410b57cec5SDimitry Andric
942*5ffd83dbSDimitry Andric  defm : TerRMWPatNoOffset<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>;
943*5ffd83dbSDimitry Andric  defm : TerRMWPatNoOffset<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>;
944*5ffd83dbSDimitry Andric  defm : TerRMWPatNoOffset<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>;
945*5ffd83dbSDimitry Andric  defm : TerRMWPatNoOffset<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>;
9460b57cec5SDimitry Andric
9470b57cec5SDimitry Andric  // Truncating-extending ternary RMWs with a constant offset
948*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i32, zext_ter_rmw_8_32<rmw_8>, regPlusImm, inst8_32>;
949*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i32, zext_ter_rmw_16_32<rmw_16>, regPlusImm,
950*5ffd83dbSDimitry Andric                         inst16_32>;
951*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i64, zext_ter_rmw_8_64<rmw_8>, regPlusImm, inst8_64>;
952*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i64, zext_ter_rmw_16_64<rmw_16>, regPlusImm,
953*5ffd83dbSDimitry Andric                         inst16_64>;
954*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i64, zext_ter_rmw_32_64<rmw_32>, regPlusImm,
955*5ffd83dbSDimitry Andric                         inst32_64>;
956*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i32, zext_ter_rmw_8_32<rmw_8>, or_is_add, inst8_32>;
957*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i32, zext_ter_rmw_16_32<rmw_16>, or_is_add, inst16_32>;
958*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i64, zext_ter_rmw_8_64<rmw_8>, or_is_add, inst8_64>;
959*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i64, zext_ter_rmw_16_64<rmw_16>, or_is_add, inst16_64>;
960*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i64, zext_ter_rmw_32_64<rmw_32>, or_is_add, inst32_64>;
9610b57cec5SDimitry Andric
962*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i32, sext_ter_rmw_8_32<rmw_8>, regPlusImm, inst8_32>;
963*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i32, sext_ter_rmw_16_32<rmw_16>, regPlusImm,
964*5ffd83dbSDimitry Andric                         inst16_32>;
965*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i64, sext_ter_rmw_8_64<rmw_8>, regPlusImm, inst8_64>;
966*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i64, sext_ter_rmw_16_64<rmw_16>, regPlusImm,
967*5ffd83dbSDimitry Andric                         inst16_64>;
968*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i32, sext_ter_rmw_8_32<rmw_8>, or_is_add, inst8_32>;
969*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i32, sext_ter_rmw_16_32<rmw_16>, or_is_add, inst16_32>;
970*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i64, sext_ter_rmw_8_64<rmw_8>, or_is_add, inst8_64>;
971*5ffd83dbSDimitry Andric  defm : TerRMWPatImmOff<i64, sext_ter_rmw_16_64<rmw_16>, or_is_add, inst16_64>;
9720b57cec5SDimitry Andric
9730b57cec5SDimitry Andric  // Truncating-extending ternary RMWs with just a constant offset
974*5ffd83dbSDimitry Andric  defm : TerRMWPatOffsetOnly<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>;
975*5ffd83dbSDimitry Andric  defm : TerRMWPatOffsetOnly<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>;
976*5ffd83dbSDimitry Andric  defm : TerRMWPatOffsetOnly<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>;
977*5ffd83dbSDimitry Andric  defm : TerRMWPatOffsetOnly<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>;
978*5ffd83dbSDimitry Andric  defm : TerRMWPatOffsetOnly<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>;
9790b57cec5SDimitry Andric
980*5ffd83dbSDimitry Andric  defm : TerRMWPatOffsetOnly<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>;
981*5ffd83dbSDimitry Andric  defm : TerRMWPatOffsetOnly<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>;
982*5ffd83dbSDimitry Andric  defm : TerRMWPatOffsetOnly<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>;
983*5ffd83dbSDimitry Andric  defm : TerRMWPatOffsetOnly<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>;
9840b57cec5SDimitry Andric
985*5ffd83dbSDimitry Andric  defm : TerRMWPatGlobalAddrOffOnly<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>;
986*5ffd83dbSDimitry Andric  defm : TerRMWPatGlobalAddrOffOnly<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>;
987*5ffd83dbSDimitry Andric  defm : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>;
988*5ffd83dbSDimitry Andric  defm : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>;
989*5ffd83dbSDimitry Andric  defm : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>;
9900b57cec5SDimitry Andric
991*5ffd83dbSDimitry Andric  defm : TerRMWPatGlobalAddrOffOnly<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>;
992*5ffd83dbSDimitry Andric  defm : TerRMWPatGlobalAddrOffOnly<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>;
993*5ffd83dbSDimitry Andric  defm : TerRMWPatGlobalAddrOffOnly<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>;
994*5ffd83dbSDimitry Andric  defm : TerRMWPatGlobalAddrOffOnly<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>;
9950b57cec5SDimitry Andric}
9960b57cec5SDimitry Andric
9970b57cec5SDimitry Andriclet Predicates = [HasAtomics] in
9980b57cec5SDimitry Andricdefm : TerRMWTruncExtPattern<
9990b57cec5SDimitry Andric  atomic_cmp_swap_8, atomic_cmp_swap_16, atomic_cmp_swap_32, atomic_cmp_swap_64,
1000*5ffd83dbSDimitry Andric  "ATOMIC_RMW8_U_CMPXCHG_I32", "ATOMIC_RMW16_U_CMPXCHG_I32",
1001*5ffd83dbSDimitry Andric  "ATOMIC_RMW8_U_CMPXCHG_I64", "ATOMIC_RMW16_U_CMPXCHG_I64",
1002*5ffd83dbSDimitry Andric  "ATOMIC_RMW32_U_CMPXCHG_I64">;
1003