xref: /freebsd/contrib/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric// WebAssemblyInstrAtomics.td-WebAssembly Atomic codegen support-*- tablegen -*-
2*0b57cec5SDimitry Andric//
3*0b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric//
7*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric///
9*0b57cec5SDimitry Andric/// \file
10*0b57cec5SDimitry Andric/// WebAssembly Atomic operand code-gen constructs.
11*0b57cec5SDimitry Andric///
12*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
13*0b57cec5SDimitry Andric
14*0b57cec5SDimitry Andriclet UseNamedOperandTable = 1 in
15*0b57cec5SDimitry Andricmulticlass ATOMIC_I<dag oops_r, dag iops_r, dag oops_s, dag iops_s,
16*0b57cec5SDimitry Andric                    list<dag> pattern_r, string asmstr_r = "",
17*0b57cec5SDimitry Andric                    string asmstr_s = "", bits<32> atomic_op = -1> {
18*0b57cec5SDimitry Andric  defm "" : I<oops_r, iops_r, oops_s, iops_s, pattern_r, asmstr_r, asmstr_s,
19*0b57cec5SDimitry Andric              !or(0xfe00, !and(0xff, atomic_op))>,
20*0b57cec5SDimitry Andric            Requires<[HasAtomics]>;
21*0b57cec5SDimitry Andric}
22*0b57cec5SDimitry Andric
23*0b57cec5SDimitry Andricmulticlass ATOMIC_NRI<dag oops, dag iops, list<dag> pattern, string asmstr = "",
24*0b57cec5SDimitry Andric                      bits<32> atomic_op = -1> {
25*0b57cec5SDimitry Andric  defm "" : NRI<oops, iops, pattern, asmstr,
26*0b57cec5SDimitry Andric                !or(0xfe00, !and(0xff, atomic_op))>,
27*0b57cec5SDimitry Andric            Requires<[HasAtomics]>;
28*0b57cec5SDimitry Andric}
29*0b57cec5SDimitry Andric
30*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
31*0b57cec5SDimitry Andric// Atomic wait / notify
32*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
33*0b57cec5SDimitry Andric
34*0b57cec5SDimitry Andriclet hasSideEffects = 1 in {
35*0b57cec5SDimitry Andricdefm ATOMIC_NOTIFY :
36*0b57cec5SDimitry Andric  ATOMIC_I<(outs I32:$dst),
37*0b57cec5SDimitry Andric           (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$count),
38*0b57cec5SDimitry Andric           (outs), (ins P2Align:$p2align, offset32_op:$off), [],
39*0b57cec5SDimitry Andric           "atomic.notify \t$dst, ${off}(${addr})${p2align}, $count",
40*0b57cec5SDimitry Andric           "atomic.notify \t${off}${p2align}", 0x00>;
41*0b57cec5SDimitry Andriclet mayLoad = 1 in {
42*0b57cec5SDimitry Andricdefm ATOMIC_WAIT_I32 :
43*0b57cec5SDimitry Andric  ATOMIC_I<(outs I32:$dst),
44*0b57cec5SDimitry Andric           (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$exp,
45*0b57cec5SDimitry Andric                I64:$timeout),
46*0b57cec5SDimitry Andric           (outs), (ins P2Align:$p2align, offset32_op:$off), [],
47*0b57cec5SDimitry Andric           "i32.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
48*0b57cec5SDimitry Andric           "i32.atomic.wait \t${off}${p2align}", 0x01>;
49*0b57cec5SDimitry Andricdefm ATOMIC_WAIT_I64 :
50*0b57cec5SDimitry Andric  ATOMIC_I<(outs I32:$dst),
51*0b57cec5SDimitry Andric           (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I64:$exp,
52*0b57cec5SDimitry Andric                I64:$timeout),
53*0b57cec5SDimitry Andric           (outs), (ins P2Align:$p2align, offset32_op:$off), [],
54*0b57cec5SDimitry Andric           "i64.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
55*0b57cec5SDimitry Andric           "i64.atomic.wait \t${off}${p2align}", 0x02>;
56*0b57cec5SDimitry Andric} // mayLoad = 1
57*0b57cec5SDimitry Andric} // hasSideEffects = 1
58*0b57cec5SDimitry Andric
59*0b57cec5SDimitry Andriclet Predicates = [HasAtomics] in {
60*0b57cec5SDimitry Andric// Select notifys with no constant offset.
61*0b57cec5SDimitry Andricdef NotifyPatNoOffset :
62*0b57cec5SDimitry Andric  Pat<(i32 (int_wasm_atomic_notify I32:$addr, I32:$count)),
63*0b57cec5SDimitry Andric      (ATOMIC_NOTIFY 0, 0, I32:$addr, I32:$count)>;
64*0b57cec5SDimitry Andric
65*0b57cec5SDimitry Andric// Select notifys with a constant offset.
66*0b57cec5SDimitry Andric
67*0b57cec5SDimitry Andric// Pattern with address + immediate offset
68*0b57cec5SDimitry Andricclass NotifyPatImmOff<PatFrag operand> :
69*0b57cec5SDimitry Andric  Pat<(i32 (int_wasm_atomic_notify (operand I32:$addr, imm:$off), I32:$count)),
70*0b57cec5SDimitry Andric      (ATOMIC_NOTIFY 0, imm:$off, I32:$addr, I32:$count)>;
71*0b57cec5SDimitry Andricdef : NotifyPatImmOff<regPlusImm>;
72*0b57cec5SDimitry Andricdef : NotifyPatImmOff<or_is_add>;
73*0b57cec5SDimitry Andric
74*0b57cec5SDimitry Andricdef NotifyPatGlobalAddr :
75*0b57cec5SDimitry Andric  Pat<(i32 (int_wasm_atomic_notify (regPlusGA I32:$addr,
76*0b57cec5SDimitry Andric                                    (WebAssemblywrapper tglobaladdr:$off)),
77*0b57cec5SDimitry Andric                                   I32:$count)),
78*0b57cec5SDimitry Andric      (ATOMIC_NOTIFY 0, tglobaladdr:$off, I32:$addr, I32:$count)>;
79*0b57cec5SDimitry Andric
80*0b57cec5SDimitry Andric// Select notifys with just a constant offset.
81*0b57cec5SDimitry Andricdef NotifyPatOffsetOnly :
82*0b57cec5SDimitry Andric  Pat<(i32 (int_wasm_atomic_notify imm:$off, I32:$count)),
83*0b57cec5SDimitry Andric      (ATOMIC_NOTIFY 0, imm:$off, (CONST_I32 0), I32:$count)>;
84*0b57cec5SDimitry Andric
85*0b57cec5SDimitry Andricdef NotifyPatGlobalAddrOffOnly :
86*0b57cec5SDimitry Andric  Pat<(i32 (int_wasm_atomic_notify (WebAssemblywrapper tglobaladdr:$off),
87*0b57cec5SDimitry Andric                                   I32:$count)),
88*0b57cec5SDimitry Andric      (ATOMIC_NOTIFY 0, tglobaladdr:$off, (CONST_I32 0), I32:$count)>;
89*0b57cec5SDimitry Andric
90*0b57cec5SDimitry Andric// Select waits with no constant offset.
91*0b57cec5SDimitry Andricclass WaitPatNoOffset<ValueType ty, Intrinsic kind, NI inst> :
92*0b57cec5SDimitry Andric  Pat<(i32 (kind I32:$addr, ty:$exp, I64:$timeout)),
93*0b57cec5SDimitry Andric      (inst 0, 0, I32:$addr, ty:$exp, I64:$timeout)>;
94*0b57cec5SDimitry Andricdef : WaitPatNoOffset<i32, int_wasm_atomic_wait_i32, ATOMIC_WAIT_I32>;
95*0b57cec5SDimitry Andricdef : WaitPatNoOffset<i64, int_wasm_atomic_wait_i64, ATOMIC_WAIT_I64>;
96*0b57cec5SDimitry Andric
97*0b57cec5SDimitry Andric// Select waits with a constant offset.
98*0b57cec5SDimitry Andric
99*0b57cec5SDimitry Andric// Pattern with address + immediate offset
100*0b57cec5SDimitry Andricclass WaitPatImmOff<ValueType ty, Intrinsic kind, PatFrag operand, NI inst> :
101*0b57cec5SDimitry Andric  Pat<(i32 (kind (operand I32:$addr, imm:$off), ty:$exp, I64:$timeout)),
102*0b57cec5SDimitry Andric      (inst 0, imm:$off, I32:$addr, ty:$exp, I64:$timeout)>;
103*0b57cec5SDimitry Andricdef : WaitPatImmOff<i32, int_wasm_atomic_wait_i32, regPlusImm, ATOMIC_WAIT_I32>;
104*0b57cec5SDimitry Andricdef : WaitPatImmOff<i32, int_wasm_atomic_wait_i32, or_is_add, ATOMIC_WAIT_I32>;
105*0b57cec5SDimitry Andricdef : WaitPatImmOff<i64, int_wasm_atomic_wait_i64, regPlusImm, ATOMIC_WAIT_I64>;
106*0b57cec5SDimitry Andricdef : WaitPatImmOff<i64, int_wasm_atomic_wait_i64, or_is_add, ATOMIC_WAIT_I64>;
107*0b57cec5SDimitry Andric
108*0b57cec5SDimitry Andricclass WaitPatGlobalAddr<ValueType ty, Intrinsic kind, NI inst> :
109*0b57cec5SDimitry Andric  Pat<(i32 (kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)),
110*0b57cec5SDimitry Andric                 ty:$exp, I64:$timeout)),
111*0b57cec5SDimitry Andric      (inst 0, tglobaladdr:$off, I32:$addr, ty:$exp, I64:$timeout)>;
112*0b57cec5SDimitry Andricdef : WaitPatGlobalAddr<i32, int_wasm_atomic_wait_i32, ATOMIC_WAIT_I32>;
113*0b57cec5SDimitry Andricdef : WaitPatGlobalAddr<i64, int_wasm_atomic_wait_i64, ATOMIC_WAIT_I64>;
114*0b57cec5SDimitry Andric
115*0b57cec5SDimitry Andric// Select wait_i32, ATOMIC_WAIT_I32s with just a constant offset.
116*0b57cec5SDimitry Andricclass WaitPatOffsetOnly<ValueType ty, Intrinsic kind, NI inst> :
117*0b57cec5SDimitry Andric  Pat<(i32 (kind imm:$off, ty:$exp, I64:$timeout)),
118*0b57cec5SDimitry Andric      (inst 0, imm:$off, (CONST_I32 0), ty:$exp, I64:$timeout)>;
119*0b57cec5SDimitry Andricdef : WaitPatOffsetOnly<i32, int_wasm_atomic_wait_i32, ATOMIC_WAIT_I32>;
120*0b57cec5SDimitry Andricdef : WaitPatOffsetOnly<i64, int_wasm_atomic_wait_i64, ATOMIC_WAIT_I64>;
121*0b57cec5SDimitry Andric
122*0b57cec5SDimitry Andricclass WaitPatGlobalAddrOffOnly<ValueType ty, Intrinsic kind, NI inst> :
123*0b57cec5SDimitry Andric  Pat<(i32 (kind (WebAssemblywrapper tglobaladdr:$off), ty:$exp, I64:$timeout)),
124*0b57cec5SDimitry Andric      (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$exp, I64:$timeout)>;
125*0b57cec5SDimitry Andricdef : WaitPatGlobalAddrOffOnly<i32, int_wasm_atomic_wait_i32, ATOMIC_WAIT_I32>;
126*0b57cec5SDimitry Andricdef : WaitPatGlobalAddrOffOnly<i64, int_wasm_atomic_wait_i64, ATOMIC_WAIT_I64>;
127*0b57cec5SDimitry Andric} // Predicates = [HasAtomics]
128*0b57cec5SDimitry Andric
129*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
130*0b57cec5SDimitry Andric// Atomic loads
131*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
132*0b57cec5SDimitry Andric
133*0b57cec5SDimitry Andricmulticlass AtomicLoad<WebAssemblyRegClass rc, string name, int atomic_op> {
134*0b57cec5SDimitry Andric  defm "" : WebAssemblyLoad<rc, name, !or(0xfe00, !and(0xff, atomic_op))>,
135*0b57cec5SDimitry Andric            Requires<[HasAtomics]>;
136*0b57cec5SDimitry Andric}
137*0b57cec5SDimitry Andric
138*0b57cec5SDimitry Andricdefm ATOMIC_LOAD_I32 : AtomicLoad<I32, "i32.atomic.load", 0x10>;
139*0b57cec5SDimitry Andricdefm ATOMIC_LOAD_I64 : AtomicLoad<I64, "i64.atomic.load", 0x11>;
140*0b57cec5SDimitry Andric
141*0b57cec5SDimitry Andric// Select loads with no constant offset.
142*0b57cec5SDimitry Andriclet Predicates = [HasAtomics] in {
143*0b57cec5SDimitry Andricdef : LoadPatNoOffset<i32, atomic_load_32, ATOMIC_LOAD_I32>;
144*0b57cec5SDimitry Andricdef : LoadPatNoOffset<i64, atomic_load_64, ATOMIC_LOAD_I64>;
145*0b57cec5SDimitry Andric
146*0b57cec5SDimitry Andric// Select loads with a constant offset.
147*0b57cec5SDimitry Andric
148*0b57cec5SDimitry Andric// Pattern with address + immediate offset
149*0b57cec5SDimitry Andricdef : LoadPatImmOff<i32, atomic_load_32, regPlusImm, ATOMIC_LOAD_I32>;
150*0b57cec5SDimitry Andricdef : LoadPatImmOff<i64, atomic_load_64, regPlusImm, ATOMIC_LOAD_I64>;
151*0b57cec5SDimitry Andricdef : LoadPatImmOff<i32, atomic_load_32, or_is_add, ATOMIC_LOAD_I32>;
152*0b57cec5SDimitry Andricdef : LoadPatImmOff<i64, atomic_load_64, or_is_add, ATOMIC_LOAD_I64>;
153*0b57cec5SDimitry Andric
154*0b57cec5SDimitry Andricdef : LoadPatGlobalAddr<i32, atomic_load_32, ATOMIC_LOAD_I32>;
155*0b57cec5SDimitry Andricdef : LoadPatGlobalAddr<i64, atomic_load_64, ATOMIC_LOAD_I64>;
156*0b57cec5SDimitry Andric
157*0b57cec5SDimitry Andric// Select loads with just a constant offset.
158*0b57cec5SDimitry Andricdef : LoadPatOffsetOnly<i32, atomic_load_32, ATOMIC_LOAD_I32>;
159*0b57cec5SDimitry Andricdef : LoadPatOffsetOnly<i64, atomic_load_64, ATOMIC_LOAD_I64>;
160*0b57cec5SDimitry Andric
161*0b57cec5SDimitry Andricdef : LoadPatGlobalAddrOffOnly<i32, atomic_load_32, ATOMIC_LOAD_I32>;
162*0b57cec5SDimitry Andricdef : LoadPatGlobalAddrOffOnly<i64, atomic_load_64, ATOMIC_LOAD_I64>;
163*0b57cec5SDimitry Andric
164*0b57cec5SDimitry Andric} // Predicates = [HasAtomics]
165*0b57cec5SDimitry Andric
166*0b57cec5SDimitry Andric// Extending loads. Note that there are only zero-extending atomic loads, no
167*0b57cec5SDimitry Andric// sign-extending loads.
168*0b57cec5SDimitry Andricdefm ATOMIC_LOAD8_U_I32 : AtomicLoad<I32, "i32.atomic.load8_u", 0x12>;
169*0b57cec5SDimitry Andricdefm ATOMIC_LOAD16_U_I32 : AtomicLoad<I32, "i32.atomic.load16_u", 0x13>;
170*0b57cec5SDimitry Andricdefm ATOMIC_LOAD8_U_I64 : AtomicLoad<I64, "i64.atomic.load8_u", 0x14>;
171*0b57cec5SDimitry Andricdefm ATOMIC_LOAD16_U_I64 : AtomicLoad<I64, "i64.atomic.load16_u", 0x15>;
172*0b57cec5SDimitry Andricdefm ATOMIC_LOAD32_U_I64 : AtomicLoad<I64, "i64.atomic.load32_u", 0x16>;
173*0b57cec5SDimitry Andric
174*0b57cec5SDimitry Andric// Fragments for extending loads. These are different from regular loads because
175*0b57cec5SDimitry Andric// the SDNodes are derived from AtomicSDNode rather than LoadSDNode and
176*0b57cec5SDimitry Andric// therefore don't have the extension type field. So instead of matching that,
177*0b57cec5SDimitry Andric// we match the patterns that the type legalizer expands them to.
178*0b57cec5SDimitry Andric
179*0b57cec5SDimitry Andric// We directly match zext patterns and select the zext atomic loads.
180*0b57cec5SDimitry Andric// i32 (zext (i8 (atomic_load_8))) gets legalized to
181*0b57cec5SDimitry Andric// i32 (and (i32 (atomic_load_8)), 255)
182*0b57cec5SDimitry Andric// These can be selected to a single zero-extending atomic load instruction.
183*0b57cec5SDimitry Andricdef zext_aload_8_32 :
184*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr), (and (i32 (atomic_load_8 node:$addr)), 255)>;
185*0b57cec5SDimitry Andricdef zext_aload_16_32 :
186*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr), (and (i32 (atomic_load_16 node:$addr)), 65535)>;
187*0b57cec5SDimitry Andric// Unlike regular loads, extension to i64 is handled differently than i32.
188*0b57cec5SDimitry Andric// i64 (zext (i8 (atomic_load_8))) gets legalized to
189*0b57cec5SDimitry Andric// i64 (and (i64 (anyext (i32 (atomic_load_8)))), 255)
190*0b57cec5SDimitry Andricdef zext_aload_8_64 :
191*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr),
192*0b57cec5SDimitry Andric          (and (i64 (anyext (i32 (atomic_load_8 node:$addr)))), 255)>;
193*0b57cec5SDimitry Andricdef zext_aload_16_64 :
194*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr),
195*0b57cec5SDimitry Andric          (and (i64 (anyext (i32 (atomic_load_16 node:$addr)))), 65535)>;
196*0b57cec5SDimitry Andricdef zext_aload_32_64 :
197*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr),
198*0b57cec5SDimitry Andric          (zext (i32 (atomic_load node:$addr)))>;
199*0b57cec5SDimitry Andric
200*0b57cec5SDimitry Andric// We don't have single sext atomic load instructions. So for sext loads, we
201*0b57cec5SDimitry Andric// match bare subword loads (for 32-bit results) and anyext loads (for 64-bit
202*0b57cec5SDimitry Andric// results) and select a zext load; the next instruction will be sext_inreg
203*0b57cec5SDimitry Andric// which is selected by itself.
204*0b57cec5SDimitry Andricdef sext_aload_8_64 :
205*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr), (anyext (i32 (atomic_load_8 node:$addr)))>;
206*0b57cec5SDimitry Andricdef sext_aload_16_64 :
207*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr), (anyext (i32 (atomic_load_16 node:$addr)))>;
208*0b57cec5SDimitry Andric
209*0b57cec5SDimitry Andriclet Predicates = [HasAtomics] in {
210*0b57cec5SDimitry Andric// Select zero-extending loads with no constant offset.
211*0b57cec5SDimitry Andricdef : LoadPatNoOffset<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
212*0b57cec5SDimitry Andricdef : LoadPatNoOffset<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
213*0b57cec5SDimitry Andricdef : LoadPatNoOffset<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
214*0b57cec5SDimitry Andricdef : LoadPatNoOffset<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
215*0b57cec5SDimitry Andricdef : LoadPatNoOffset<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
216*0b57cec5SDimitry Andric
217*0b57cec5SDimitry Andric// Select sign-extending loads with no constant offset
218*0b57cec5SDimitry Andricdef : LoadPatNoOffset<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
219*0b57cec5SDimitry Andricdef : LoadPatNoOffset<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
220*0b57cec5SDimitry Andricdef : LoadPatNoOffset<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
221*0b57cec5SDimitry Andricdef : LoadPatNoOffset<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
222*0b57cec5SDimitry Andric// 32->64 sext load gets selected as i32.atomic.load, i64.extend_i32_s
223*0b57cec5SDimitry Andric
224*0b57cec5SDimitry Andric// Zero-extending loads with constant offset
225*0b57cec5SDimitry Andricdef : LoadPatImmOff<i32, zext_aload_8_32, regPlusImm, ATOMIC_LOAD8_U_I32>;
226*0b57cec5SDimitry Andricdef : LoadPatImmOff<i32, zext_aload_16_32, regPlusImm, ATOMIC_LOAD16_U_I32>;
227*0b57cec5SDimitry Andricdef : LoadPatImmOff<i32, zext_aload_8_32, or_is_add, ATOMIC_LOAD8_U_I32>;
228*0b57cec5SDimitry Andricdef : LoadPatImmOff<i32, zext_aload_16_32, or_is_add, ATOMIC_LOAD16_U_I32>;
229*0b57cec5SDimitry Andricdef : LoadPatImmOff<i64, zext_aload_8_64, regPlusImm, ATOMIC_LOAD8_U_I64>;
230*0b57cec5SDimitry Andricdef : LoadPatImmOff<i64, zext_aload_16_64, regPlusImm, ATOMIC_LOAD16_U_I64>;
231*0b57cec5SDimitry Andricdef : LoadPatImmOff<i64, zext_aload_32_64, regPlusImm, ATOMIC_LOAD32_U_I64>;
232*0b57cec5SDimitry Andricdef : LoadPatImmOff<i64, zext_aload_8_64, or_is_add, ATOMIC_LOAD8_U_I64>;
233*0b57cec5SDimitry Andricdef : LoadPatImmOff<i64, zext_aload_16_64, or_is_add, ATOMIC_LOAD16_U_I64>;
234*0b57cec5SDimitry Andricdef : LoadPatImmOff<i64, zext_aload_32_64, or_is_add, ATOMIC_LOAD32_U_I64>;
235*0b57cec5SDimitry Andric
236*0b57cec5SDimitry Andric// Sign-extending loads with constant offset
237*0b57cec5SDimitry Andricdef : LoadPatImmOff<i32, atomic_load_8, regPlusImm, ATOMIC_LOAD8_U_I32>;
238*0b57cec5SDimitry Andricdef : LoadPatImmOff<i32, atomic_load_16, regPlusImm, ATOMIC_LOAD16_U_I32>;
239*0b57cec5SDimitry Andricdef : LoadPatImmOff<i32, atomic_load_8, or_is_add, ATOMIC_LOAD8_U_I32>;
240*0b57cec5SDimitry Andricdef : LoadPatImmOff<i32, atomic_load_16, or_is_add, ATOMIC_LOAD16_U_I32>;
241*0b57cec5SDimitry Andricdef : LoadPatImmOff<i64, sext_aload_8_64, regPlusImm, ATOMIC_LOAD8_U_I64>;
242*0b57cec5SDimitry Andricdef : LoadPatImmOff<i64, sext_aload_16_64, regPlusImm, ATOMIC_LOAD16_U_I64>;
243*0b57cec5SDimitry Andricdef : LoadPatImmOff<i64, sext_aload_8_64, or_is_add, ATOMIC_LOAD8_U_I64>;
244*0b57cec5SDimitry Andricdef : LoadPatImmOff<i64, sext_aload_16_64, or_is_add, ATOMIC_LOAD16_U_I64>;
245*0b57cec5SDimitry Andric// No 32->64 patterns, just use i32.atomic.load and i64.extend_s/i64
246*0b57cec5SDimitry Andric
247*0b57cec5SDimitry Andricdef : LoadPatGlobalAddr<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
248*0b57cec5SDimitry Andricdef : LoadPatGlobalAddr<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
249*0b57cec5SDimitry Andricdef : LoadPatGlobalAddr<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
250*0b57cec5SDimitry Andricdef : LoadPatGlobalAddr<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
251*0b57cec5SDimitry Andricdef : LoadPatGlobalAddr<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
252*0b57cec5SDimitry Andricdef : LoadPatGlobalAddr<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
253*0b57cec5SDimitry Andricdef : LoadPatGlobalAddr<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
254*0b57cec5SDimitry Andricdef : LoadPatGlobalAddr<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
255*0b57cec5SDimitry Andricdef : LoadPatGlobalAddr<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
256*0b57cec5SDimitry Andric
257*0b57cec5SDimitry Andric// Extending loads with just a constant offset
258*0b57cec5SDimitry Andricdef : LoadPatOffsetOnly<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
259*0b57cec5SDimitry Andricdef : LoadPatOffsetOnly<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
260*0b57cec5SDimitry Andricdef : LoadPatOffsetOnly<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
261*0b57cec5SDimitry Andricdef : LoadPatOffsetOnly<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
262*0b57cec5SDimitry Andricdef : LoadPatOffsetOnly<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
263*0b57cec5SDimitry Andricdef : LoadPatOffsetOnly<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
264*0b57cec5SDimitry Andricdef : LoadPatOffsetOnly<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
265*0b57cec5SDimitry Andricdef : LoadPatOffsetOnly<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
266*0b57cec5SDimitry Andricdef : LoadPatOffsetOnly<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
267*0b57cec5SDimitry Andric
268*0b57cec5SDimitry Andricdef : LoadPatGlobalAddrOffOnly<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
269*0b57cec5SDimitry Andricdef : LoadPatGlobalAddrOffOnly<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
270*0b57cec5SDimitry Andricdef : LoadPatGlobalAddrOffOnly<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
271*0b57cec5SDimitry Andricdef : LoadPatGlobalAddrOffOnly<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
272*0b57cec5SDimitry Andricdef : LoadPatGlobalAddrOffOnly<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
273*0b57cec5SDimitry Andricdef : LoadPatGlobalAddrOffOnly<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
274*0b57cec5SDimitry Andricdef : LoadPatGlobalAddrOffOnly<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
275*0b57cec5SDimitry Andricdef : LoadPatGlobalAddrOffOnly<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
276*0b57cec5SDimitry Andricdef : LoadPatGlobalAddrOffOnly<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
277*0b57cec5SDimitry Andric
278*0b57cec5SDimitry Andric} // Predicates = [HasAtomics]
279*0b57cec5SDimitry Andric
280*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
281*0b57cec5SDimitry Andric// Atomic stores
282*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
283*0b57cec5SDimitry Andric
284*0b57cec5SDimitry Andricmulticlass AtomicStore<WebAssemblyRegClass rc, string name, int atomic_op> {
285*0b57cec5SDimitry Andric  defm "" : WebAssemblyStore<rc, name, !or(0xfe00, !and(0xff, atomic_op))>,
286*0b57cec5SDimitry Andric            Requires<[HasAtomics]>;
287*0b57cec5SDimitry Andric}
288*0b57cec5SDimitry Andric
289*0b57cec5SDimitry Andricdefm ATOMIC_STORE_I32 : AtomicStore<I32, "i32.atomic.store", 0x17>;
290*0b57cec5SDimitry Andricdefm ATOMIC_STORE_I64 : AtomicStore<I64, "i64.atomic.store", 0x18>;
291*0b57cec5SDimitry Andric
292*0b57cec5SDimitry Andric// We need an 'atomic' version of store patterns because store and atomic_store
293*0b57cec5SDimitry Andric// nodes have different operand orders:
294*0b57cec5SDimitry Andric// store: (store $val, $ptr)
295*0b57cec5SDimitry Andric// atomic_store: (store $ptr, $val)
296*0b57cec5SDimitry Andric
297*0b57cec5SDimitry Andriclet Predicates = [HasAtomics] in {
298*0b57cec5SDimitry Andric
299*0b57cec5SDimitry Andric// Select stores with no constant offset.
300*0b57cec5SDimitry Andricclass AStorePatNoOffset<ValueType ty, PatFrag kind, NI inst> :
301*0b57cec5SDimitry Andric  Pat<(kind I32:$addr, ty:$val), (inst 0, 0, I32:$addr, ty:$val)>;
302*0b57cec5SDimitry Andricdef : AStorePatNoOffset<i32, atomic_store_32, ATOMIC_STORE_I32>;
303*0b57cec5SDimitry Andricdef : AStorePatNoOffset<i64, atomic_store_64, ATOMIC_STORE_I64>;
304*0b57cec5SDimitry Andric
305*0b57cec5SDimitry Andric// Select stores with a constant offset.
306*0b57cec5SDimitry Andric
307*0b57cec5SDimitry Andric// Pattern with address + immediate offset
308*0b57cec5SDimitry Andricclass AStorePatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
309*0b57cec5SDimitry Andric  Pat<(kind (operand I32:$addr, imm:$off), ty:$val),
310*0b57cec5SDimitry Andric      (inst 0, imm:$off, I32:$addr, ty:$val)>;
311*0b57cec5SDimitry Andricdef : AStorePatImmOff<i32, atomic_store_32, regPlusImm, ATOMIC_STORE_I32>;
312*0b57cec5SDimitry Andricdef : AStorePatImmOff<i64, atomic_store_64, regPlusImm, ATOMIC_STORE_I64>;
313*0b57cec5SDimitry Andricdef : AStorePatImmOff<i32, atomic_store_32, or_is_add, ATOMIC_STORE_I32>;
314*0b57cec5SDimitry Andricdef : AStorePatImmOff<i64, atomic_store_64, or_is_add, ATOMIC_STORE_I64>;
315*0b57cec5SDimitry Andric
316*0b57cec5SDimitry Andricclass AStorePatGlobalAddr<ValueType ty, PatFrag kind, NI inst> :
317*0b57cec5SDimitry Andric  Pat<(kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)),
318*0b57cec5SDimitry Andric            ty:$val),
319*0b57cec5SDimitry Andric      (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>;
320*0b57cec5SDimitry Andricdef : AStorePatGlobalAddr<i32, atomic_store_32, ATOMIC_STORE_I32>;
321*0b57cec5SDimitry Andricdef : AStorePatGlobalAddr<i64, atomic_store_64, ATOMIC_STORE_I64>;
322*0b57cec5SDimitry Andric
323*0b57cec5SDimitry Andric// Select stores with just a constant offset.
324*0b57cec5SDimitry Andricclass AStorePatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
325*0b57cec5SDimitry Andric  Pat<(kind imm:$off, ty:$val), (inst 0, imm:$off, (CONST_I32 0), ty:$val)>;
326*0b57cec5SDimitry Andricdef : AStorePatOffsetOnly<i32, atomic_store_32, ATOMIC_STORE_I32>;
327*0b57cec5SDimitry Andricdef : AStorePatOffsetOnly<i64, atomic_store_64, ATOMIC_STORE_I64>;
328*0b57cec5SDimitry Andric
329*0b57cec5SDimitry Andricclass AStorePatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
330*0b57cec5SDimitry Andric  Pat<(kind (WebAssemblywrapper tglobaladdr:$off), ty:$val),
331*0b57cec5SDimitry Andric      (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>;
332*0b57cec5SDimitry Andricdef : AStorePatGlobalAddrOffOnly<i32, atomic_store_32, ATOMIC_STORE_I32>;
333*0b57cec5SDimitry Andricdef : AStorePatGlobalAddrOffOnly<i64, atomic_store_64, ATOMIC_STORE_I64>;
334*0b57cec5SDimitry Andric
335*0b57cec5SDimitry Andric} // Predicates = [HasAtomics]
336*0b57cec5SDimitry Andric
337*0b57cec5SDimitry Andric// Truncating stores.
338*0b57cec5SDimitry Andricdefm ATOMIC_STORE8_I32 : AtomicStore<I32, "i32.atomic.store8", 0x19>;
339*0b57cec5SDimitry Andricdefm ATOMIC_STORE16_I32 : AtomicStore<I32, "i32.atomic.store16", 0x1a>;
340*0b57cec5SDimitry Andricdefm ATOMIC_STORE8_I64 : AtomicStore<I64, "i64.atomic.store8", 0x1b>;
341*0b57cec5SDimitry Andricdefm ATOMIC_STORE16_I64 : AtomicStore<I64, "i64.atomic.store16", 0x1c>;
342*0b57cec5SDimitry Andricdefm ATOMIC_STORE32_I64 : AtomicStore<I64, "i64.atomic.store32", 0x1d>;
343*0b57cec5SDimitry Andric
344*0b57cec5SDimitry Andric// Fragments for truncating stores.
345*0b57cec5SDimitry Andric
346*0b57cec5SDimitry Andric// We don't have single truncating atomic store instructions. For 32-bit
347*0b57cec5SDimitry Andric// instructions, we just need to match bare atomic stores. On the other hand,
348*0b57cec5SDimitry Andric// truncating stores from i64 values are once truncated to i32 first.
349*0b57cec5SDimitry Andricclass trunc_astore_64<PatFrag kind> :
350*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val),
351*0b57cec5SDimitry Andric          (kind node:$addr, (i32 (trunc (i64 node:$val))))>;
352*0b57cec5SDimitry Andricdef trunc_astore_8_64 : trunc_astore_64<atomic_store_8>;
353*0b57cec5SDimitry Andricdef trunc_astore_16_64 : trunc_astore_64<atomic_store_16>;
354*0b57cec5SDimitry Andricdef trunc_astore_32_64 : trunc_astore_64<atomic_store_32>;
355*0b57cec5SDimitry Andric
356*0b57cec5SDimitry Andriclet Predicates = [HasAtomics] in {
357*0b57cec5SDimitry Andric
358*0b57cec5SDimitry Andric// Truncating stores with no constant offset
359*0b57cec5SDimitry Andricdef : AStorePatNoOffset<i32, atomic_store_8, ATOMIC_STORE8_I32>;
360*0b57cec5SDimitry Andricdef : AStorePatNoOffset<i32, atomic_store_16, ATOMIC_STORE16_I32>;
361*0b57cec5SDimitry Andricdef : AStorePatNoOffset<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
362*0b57cec5SDimitry Andricdef : AStorePatNoOffset<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
363*0b57cec5SDimitry Andricdef : AStorePatNoOffset<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
364*0b57cec5SDimitry Andric
365*0b57cec5SDimitry Andric// Truncating stores with a constant offset
366*0b57cec5SDimitry Andricdef : AStorePatImmOff<i32, atomic_store_8, regPlusImm, ATOMIC_STORE8_I32>;
367*0b57cec5SDimitry Andricdef : AStorePatImmOff<i32, atomic_store_16, regPlusImm, ATOMIC_STORE16_I32>;
368*0b57cec5SDimitry Andricdef : AStorePatImmOff<i64, trunc_astore_8_64, regPlusImm, ATOMIC_STORE8_I64>;
369*0b57cec5SDimitry Andricdef : AStorePatImmOff<i64, trunc_astore_16_64, regPlusImm, ATOMIC_STORE16_I64>;
370*0b57cec5SDimitry Andricdef : AStorePatImmOff<i64, trunc_astore_32_64, regPlusImm, ATOMIC_STORE32_I64>;
371*0b57cec5SDimitry Andricdef : AStorePatImmOff<i32, atomic_store_8, or_is_add, ATOMIC_STORE8_I32>;
372*0b57cec5SDimitry Andricdef : AStorePatImmOff<i32, atomic_store_16, or_is_add, ATOMIC_STORE16_I32>;
373*0b57cec5SDimitry Andricdef : AStorePatImmOff<i64, trunc_astore_8_64, or_is_add, ATOMIC_STORE8_I64>;
374*0b57cec5SDimitry Andricdef : AStorePatImmOff<i64, trunc_astore_16_64, or_is_add, ATOMIC_STORE16_I64>;
375*0b57cec5SDimitry Andricdef : AStorePatImmOff<i64, trunc_astore_32_64, or_is_add, ATOMIC_STORE32_I64>;
376*0b57cec5SDimitry Andric
377*0b57cec5SDimitry Andricdef : AStorePatGlobalAddr<i32, atomic_store_8, ATOMIC_STORE8_I32>;
378*0b57cec5SDimitry Andricdef : AStorePatGlobalAddr<i32, atomic_store_16, ATOMIC_STORE16_I32>;
379*0b57cec5SDimitry Andricdef : AStorePatGlobalAddr<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
380*0b57cec5SDimitry Andricdef : AStorePatGlobalAddr<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
381*0b57cec5SDimitry Andricdef : AStorePatGlobalAddr<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
382*0b57cec5SDimitry Andric
383*0b57cec5SDimitry Andric// Truncating stores with just a constant offset
384*0b57cec5SDimitry Andricdef : AStorePatOffsetOnly<i32, atomic_store_8, ATOMIC_STORE8_I32>;
385*0b57cec5SDimitry Andricdef : AStorePatOffsetOnly<i32, atomic_store_16, ATOMIC_STORE16_I32>;
386*0b57cec5SDimitry Andricdef : AStorePatOffsetOnly<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
387*0b57cec5SDimitry Andricdef : AStorePatOffsetOnly<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
388*0b57cec5SDimitry Andricdef : AStorePatOffsetOnly<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
389*0b57cec5SDimitry Andric
390*0b57cec5SDimitry Andricdef : AStorePatGlobalAddrOffOnly<i32, atomic_store_8, ATOMIC_STORE8_I32>;
391*0b57cec5SDimitry Andricdef : AStorePatGlobalAddrOffOnly<i32, atomic_store_16, ATOMIC_STORE16_I32>;
392*0b57cec5SDimitry Andricdef : AStorePatGlobalAddrOffOnly<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
393*0b57cec5SDimitry Andricdef : AStorePatGlobalAddrOffOnly<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
394*0b57cec5SDimitry Andricdef : AStorePatGlobalAddrOffOnly<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
395*0b57cec5SDimitry Andric
396*0b57cec5SDimitry Andric} // Predicates = [HasAtomics]
397*0b57cec5SDimitry Andric
398*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
399*0b57cec5SDimitry Andric// Atomic binary read-modify-writes
400*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
401*0b57cec5SDimitry Andric
402*0b57cec5SDimitry Andricmulticlass WebAssemblyBinRMW<WebAssemblyRegClass rc, string name,
403*0b57cec5SDimitry Andric                             int atomic_op> {
404*0b57cec5SDimitry Andric  defm "" :
405*0b57cec5SDimitry Andric    ATOMIC_I<(outs rc:$dst),
406*0b57cec5SDimitry Andric             (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
407*0b57cec5SDimitry Andric             (outs), (ins P2Align:$p2align, offset32_op:$off), [],
408*0b57cec5SDimitry Andric             !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $val"),
409*0b57cec5SDimitry Andric             !strconcat(name, "\t${off}${p2align}"), atomic_op>;
410*0b57cec5SDimitry Andric}
411*0b57cec5SDimitry Andric
412*0b57cec5SDimitry Andricdefm ATOMIC_RMW_ADD_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.add", 0x1e>;
413*0b57cec5SDimitry Andricdefm ATOMIC_RMW_ADD_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.add", 0x1f>;
414*0b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_ADD_I32 :
415*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw8.add_u", 0x20>;
416*0b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_ADD_I32 :
417*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw16.add_u", 0x21>;
418*0b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_ADD_I64 :
419*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw8.add_u", 0x22>;
420*0b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_ADD_I64 :
421*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw16.add_u", 0x23>;
422*0b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_ADD_I64 :
423*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw32.add_u", 0x24>;
424*0b57cec5SDimitry Andric
425*0b57cec5SDimitry Andricdefm ATOMIC_RMW_SUB_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.sub", 0x25>;
426*0b57cec5SDimitry Andricdefm ATOMIC_RMW_SUB_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.sub", 0x26>;
427*0b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_SUB_I32 :
428*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw8.sub_u", 0x27>;
429*0b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_SUB_I32 :
430*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw16.sub_u", 0x28>;
431*0b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_SUB_I64 :
432*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw8.sub_u", 0x29>;
433*0b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_SUB_I64 :
434*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw16.sub_u", 0x2a>;
435*0b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_SUB_I64 :
436*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw32.sub_u", 0x2b>;
437*0b57cec5SDimitry Andric
438*0b57cec5SDimitry Andricdefm ATOMIC_RMW_AND_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.and", 0x2c>;
439*0b57cec5SDimitry Andricdefm ATOMIC_RMW_AND_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.and", 0x2d>;
440*0b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_AND_I32 :
441*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw8.and_u", 0x2e>;
442*0b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_AND_I32 :
443*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw16.and_u", 0x2f>;
444*0b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_AND_I64 :
445*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw8.and_u", 0x30>;
446*0b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_AND_I64 :
447*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw16.and_u", 0x31>;
448*0b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_AND_I64 :
449*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw32.and_u", 0x32>;
450*0b57cec5SDimitry Andric
451*0b57cec5SDimitry Andricdefm ATOMIC_RMW_OR_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.or", 0x33>;
452*0b57cec5SDimitry Andricdefm ATOMIC_RMW_OR_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.or", 0x34>;
453*0b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_OR_I32 :
454*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw8.or_u", 0x35>;
455*0b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_OR_I32 :
456*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw16.or_u", 0x36>;
457*0b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_OR_I64 :
458*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw8.or_u", 0x37>;
459*0b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_OR_I64 :
460*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw16.or_u", 0x38>;
461*0b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_OR_I64 :
462*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw32.or_u", 0x39>;
463*0b57cec5SDimitry Andric
464*0b57cec5SDimitry Andricdefm ATOMIC_RMW_XOR_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.xor", 0x3a>;
465*0b57cec5SDimitry Andricdefm ATOMIC_RMW_XOR_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.xor", 0x3b>;
466*0b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_XOR_I32 :
467*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw8.xor_u", 0x3c>;
468*0b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_XOR_I32 :
469*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw16.xor_u", 0x3d>;
470*0b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_XOR_I64 :
471*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw8.xor_u", 0x3e>;
472*0b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_XOR_I64 :
473*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw16.xor_u", 0x3f>;
474*0b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_XOR_I64 :
475*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw32.xor_u", 0x40>;
476*0b57cec5SDimitry Andric
477*0b57cec5SDimitry Andricdefm ATOMIC_RMW_XCHG_I32 :
478*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw.xchg", 0x41>;
479*0b57cec5SDimitry Andricdefm ATOMIC_RMW_XCHG_I64 :
480*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw.xchg", 0x42>;
481*0b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_XCHG_I32 :
482*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw8.xchg_u", 0x43>;
483*0b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_XCHG_I32 :
484*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I32, "i32.atomic.rmw16.xchg_u", 0x44>;
485*0b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_XCHG_I64 :
486*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw8.xchg_u", 0x45>;
487*0b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_XCHG_I64 :
488*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw16.xchg_u", 0x46>;
489*0b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_XCHG_I64 :
490*0b57cec5SDimitry Andric  WebAssemblyBinRMW<I64, "i64.atomic.rmw32.xchg_u", 0x47>;
491*0b57cec5SDimitry Andric
492*0b57cec5SDimitry Andric// Select binary RMWs with no constant offset.
493*0b57cec5SDimitry Andricclass BinRMWPatNoOffset<ValueType ty, PatFrag kind, NI inst> :
494*0b57cec5SDimitry Andric  Pat<(ty (kind I32:$addr, ty:$val)), (inst 0, 0, I32:$addr, ty:$val)>;
495*0b57cec5SDimitry Andric
496*0b57cec5SDimitry Andric// Select binary RMWs with a constant offset.
497*0b57cec5SDimitry Andric
498*0b57cec5SDimitry Andric// Pattern with address + immediate offset
499*0b57cec5SDimitry Andricclass BinRMWPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
500*0b57cec5SDimitry Andric  Pat<(ty (kind (operand I32:$addr, imm:$off), ty:$val)),
501*0b57cec5SDimitry Andric      (inst 0, imm:$off, I32:$addr, ty:$val)>;
502*0b57cec5SDimitry Andric
503*0b57cec5SDimitry Andricclass BinRMWPatGlobalAddr<ValueType ty, PatFrag kind, NI inst> :
504*0b57cec5SDimitry Andric  Pat<(ty (kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)),
505*0b57cec5SDimitry Andric                ty:$val)),
506*0b57cec5SDimitry Andric      (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>;
507*0b57cec5SDimitry Andric
508*0b57cec5SDimitry Andric// Select binary RMWs with just a constant offset.
509*0b57cec5SDimitry Andricclass BinRMWPatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
510*0b57cec5SDimitry Andric  Pat<(ty (kind imm:$off, ty:$val)),
511*0b57cec5SDimitry Andric      (inst 0, imm:$off, (CONST_I32 0), ty:$val)>;
512*0b57cec5SDimitry Andric
513*0b57cec5SDimitry Andricclass BinRMWPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
514*0b57cec5SDimitry Andric  Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off), ty:$val)),
515*0b57cec5SDimitry Andric      (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>;
516*0b57cec5SDimitry Andric
517*0b57cec5SDimitry Andric// Patterns for various addressing modes.
518*0b57cec5SDimitry Andricmulticlass BinRMWPattern<PatFrag rmw_32, PatFrag rmw_64, NI inst_32,
519*0b57cec5SDimitry Andric                         NI inst_64> {
520*0b57cec5SDimitry Andric  def : BinRMWPatNoOffset<i32, rmw_32, inst_32>;
521*0b57cec5SDimitry Andric  def : BinRMWPatNoOffset<i64, rmw_64, inst_64>;
522*0b57cec5SDimitry Andric
523*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i32, rmw_32, regPlusImm, inst_32>;
524*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i64, rmw_64, regPlusImm, inst_64>;
525*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i32, rmw_32, or_is_add, inst_32>;
526*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i64, rmw_64, or_is_add, inst_64>;
527*0b57cec5SDimitry Andric
528*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddr<i32, rmw_32, inst_32>;
529*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddr<i64, rmw_64, inst_64>;
530*0b57cec5SDimitry Andric
531*0b57cec5SDimitry Andric  def : BinRMWPatOffsetOnly<i32, rmw_32, inst_32>;
532*0b57cec5SDimitry Andric  def : BinRMWPatOffsetOnly<i64, rmw_64, inst_64>;
533*0b57cec5SDimitry Andric
534*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddrOffOnly<i32, rmw_32, inst_32>;
535*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddrOffOnly<i64, rmw_64, inst_64>;
536*0b57cec5SDimitry Andric}
537*0b57cec5SDimitry Andric
538*0b57cec5SDimitry Andriclet Predicates = [HasAtomics] in {
539*0b57cec5SDimitry Andricdefm : BinRMWPattern<atomic_load_add_32, atomic_load_add_64, ATOMIC_RMW_ADD_I32,
540*0b57cec5SDimitry Andric                     ATOMIC_RMW_ADD_I64>;
541*0b57cec5SDimitry Andricdefm : BinRMWPattern<atomic_load_sub_32, atomic_load_sub_64, ATOMIC_RMW_SUB_I32,
542*0b57cec5SDimitry Andric                     ATOMIC_RMW_SUB_I64>;
543*0b57cec5SDimitry Andricdefm : BinRMWPattern<atomic_load_and_32, atomic_load_and_64, ATOMIC_RMW_AND_I32,
544*0b57cec5SDimitry Andric                     ATOMIC_RMW_AND_I64>;
545*0b57cec5SDimitry Andricdefm : BinRMWPattern<atomic_load_or_32, atomic_load_or_64, ATOMIC_RMW_OR_I32,
546*0b57cec5SDimitry Andric                     ATOMIC_RMW_OR_I64>;
547*0b57cec5SDimitry Andricdefm : BinRMWPattern<atomic_load_xor_32, atomic_load_xor_64, ATOMIC_RMW_XOR_I32,
548*0b57cec5SDimitry Andric                     ATOMIC_RMW_XOR_I64>;
549*0b57cec5SDimitry Andricdefm : BinRMWPattern<atomic_swap_32, atomic_swap_64, ATOMIC_RMW_XCHG_I32,
550*0b57cec5SDimitry Andric                     ATOMIC_RMW_XCHG_I64>;
551*0b57cec5SDimitry Andric} // Predicates = [HasAtomics]
552*0b57cec5SDimitry Andric
553*0b57cec5SDimitry Andric// Truncating & zero-extending binary RMW patterns.
554*0b57cec5SDimitry Andric// These are combined patterns of truncating store patterns and zero-extending
555*0b57cec5SDimitry Andric// load patterns above.
556*0b57cec5SDimitry Andricclass zext_bin_rmw_8_32<PatFrag kind> :
557*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val),
558*0b57cec5SDimitry Andric          (and (i32 (kind node:$addr, node:$val)), 255)>;
559*0b57cec5SDimitry Andricclass zext_bin_rmw_16_32<PatFrag kind> :
560*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val),
561*0b57cec5SDimitry Andric          (and (i32 (kind node:$addr, node:$val)), 65535)>;
562*0b57cec5SDimitry Andricclass zext_bin_rmw_8_64<PatFrag kind> :
563*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val),
564*0b57cec5SDimitry Andric    (and (i64 (anyext (i32 (kind node:$addr,
565*0b57cec5SDimitry Andric                                 (i32 (trunc (i64 node:$val))))))), 255)>;
566*0b57cec5SDimitry Andricclass zext_bin_rmw_16_64<PatFrag kind> :
567*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val),
568*0b57cec5SDimitry Andric    (and (i64 (anyext (i32 (kind node:$addr,
569*0b57cec5SDimitry Andric                                 (i32 (trunc (i64 node:$val))))))), 65535)>;
570*0b57cec5SDimitry Andricclass zext_bin_rmw_32_64<PatFrag kind> :
571*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val),
572*0b57cec5SDimitry Andric          (zext (i32 (kind node:$addr, (i32 (trunc (i64 node:$val))))))>;
573*0b57cec5SDimitry Andric
574*0b57cec5SDimitry Andric// Truncating & sign-extending binary RMW patterns.
575*0b57cec5SDimitry Andric// These are combined patterns of truncating store patterns and sign-extending
576*0b57cec5SDimitry Andric// load patterns above. We match subword RMWs (for 32-bit) and anyext RMWs (for
577*0b57cec5SDimitry Andric// 64-bit) and select a zext RMW; the next instruction will be sext_inreg which
578*0b57cec5SDimitry Andric// is selected by itself.
579*0b57cec5SDimitry Andricclass sext_bin_rmw_8_32<PatFrag kind> :
580*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val), (kind node:$addr, node:$val)>;
581*0b57cec5SDimitry Andricclass sext_bin_rmw_16_32<PatFrag kind> : sext_bin_rmw_8_32<kind>;
582*0b57cec5SDimitry Andricclass sext_bin_rmw_8_64<PatFrag kind> :
583*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$val),
584*0b57cec5SDimitry Andric          (anyext (i32 (kind node:$addr, (i32 (trunc (i64 node:$val))))))>;
585*0b57cec5SDimitry Andricclass sext_bin_rmw_16_64<PatFrag kind> : sext_bin_rmw_8_64<kind>;
586*0b57cec5SDimitry Andric// 32->64 sext RMW gets selected as i32.atomic.rmw.***, i64.extend_i32_s
587*0b57cec5SDimitry Andric
588*0b57cec5SDimitry Andric// Patterns for various addressing modes for truncating-extending binary RMWs.
589*0b57cec5SDimitry Andricmulticlass BinRMWTruncExtPattern<
590*0b57cec5SDimitry Andric  PatFrag rmw_8, PatFrag rmw_16, PatFrag rmw_32, PatFrag rmw_64,
591*0b57cec5SDimitry Andric  NI inst8_32, NI inst16_32, NI inst8_64, NI inst16_64, NI inst32_64> {
592*0b57cec5SDimitry Andric  // Truncating-extending binary RMWs with no constant offset
593*0b57cec5SDimitry Andric  def : BinRMWPatNoOffset<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
594*0b57cec5SDimitry Andric  def : BinRMWPatNoOffset<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
595*0b57cec5SDimitry Andric  def : BinRMWPatNoOffset<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
596*0b57cec5SDimitry Andric  def : BinRMWPatNoOffset<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
597*0b57cec5SDimitry Andric  def : BinRMWPatNoOffset<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
598*0b57cec5SDimitry Andric
599*0b57cec5SDimitry Andric  def : BinRMWPatNoOffset<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
600*0b57cec5SDimitry Andric  def : BinRMWPatNoOffset<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
601*0b57cec5SDimitry Andric  def : BinRMWPatNoOffset<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
602*0b57cec5SDimitry Andric  def : BinRMWPatNoOffset<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
603*0b57cec5SDimitry Andric
604*0b57cec5SDimitry Andric  // Truncating-extending binary RMWs with a constant offset
605*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i32, zext_bin_rmw_8_32<rmw_8>, regPlusImm, inst8_32>;
606*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i32, zext_bin_rmw_16_32<rmw_16>, regPlusImm, inst16_32>;
607*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i64, zext_bin_rmw_8_64<rmw_8>, regPlusImm, inst8_64>;
608*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i64, zext_bin_rmw_16_64<rmw_16>, regPlusImm, inst16_64>;
609*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i64, zext_bin_rmw_32_64<rmw_32>, regPlusImm, inst32_64>;
610*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i32, zext_bin_rmw_8_32<rmw_8>, or_is_add, inst8_32>;
611*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i32, zext_bin_rmw_16_32<rmw_16>, or_is_add, inst16_32>;
612*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i64, zext_bin_rmw_8_64<rmw_8>, or_is_add, inst8_64>;
613*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i64, zext_bin_rmw_16_64<rmw_16>, or_is_add, inst16_64>;
614*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i64, zext_bin_rmw_32_64<rmw_32>, or_is_add, inst32_64>;
615*0b57cec5SDimitry Andric
616*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i32, sext_bin_rmw_8_32<rmw_8>, regPlusImm, inst8_32>;
617*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i32, sext_bin_rmw_16_32<rmw_16>, regPlusImm, inst16_32>;
618*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i64, sext_bin_rmw_8_64<rmw_8>, regPlusImm, inst8_64>;
619*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i64, sext_bin_rmw_16_64<rmw_16>, regPlusImm, inst16_64>;
620*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i32, sext_bin_rmw_8_32<rmw_8>, or_is_add, inst8_32>;
621*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i32, sext_bin_rmw_16_32<rmw_16>, or_is_add, inst16_32>;
622*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i64, sext_bin_rmw_8_64<rmw_8>, or_is_add, inst8_64>;
623*0b57cec5SDimitry Andric  def : BinRMWPatImmOff<i64, sext_bin_rmw_16_64<rmw_16>, or_is_add, inst16_64>;
624*0b57cec5SDimitry Andric
625*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddr<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
626*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddr<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
627*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddr<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
628*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddr<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
629*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddr<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
630*0b57cec5SDimitry Andric
631*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddr<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
632*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddr<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
633*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddr<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
634*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddr<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
635*0b57cec5SDimitry Andric
636*0b57cec5SDimitry Andric  // Truncating-extending binary RMWs with just a constant offset
637*0b57cec5SDimitry Andric  def : BinRMWPatOffsetOnly<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
638*0b57cec5SDimitry Andric  def : BinRMWPatOffsetOnly<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
639*0b57cec5SDimitry Andric  def : BinRMWPatOffsetOnly<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
640*0b57cec5SDimitry Andric  def : BinRMWPatOffsetOnly<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
641*0b57cec5SDimitry Andric  def : BinRMWPatOffsetOnly<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
642*0b57cec5SDimitry Andric
643*0b57cec5SDimitry Andric  def : BinRMWPatOffsetOnly<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
644*0b57cec5SDimitry Andric  def : BinRMWPatOffsetOnly<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
645*0b57cec5SDimitry Andric  def : BinRMWPatOffsetOnly<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
646*0b57cec5SDimitry Andric  def : BinRMWPatOffsetOnly<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
647*0b57cec5SDimitry Andric
648*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddrOffOnly<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
649*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddrOffOnly<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
650*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
651*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
652*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
653*0b57cec5SDimitry Andric
654*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddrOffOnly<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
655*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddrOffOnly<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
656*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddrOffOnly<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
657*0b57cec5SDimitry Andric  def : BinRMWPatGlobalAddrOffOnly<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
658*0b57cec5SDimitry Andric}
659*0b57cec5SDimitry Andric
660*0b57cec5SDimitry Andriclet Predicates = [HasAtomics] in {
661*0b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern<
662*0b57cec5SDimitry Andric  atomic_load_add_8, atomic_load_add_16, atomic_load_add_32, atomic_load_add_64,
663*0b57cec5SDimitry Andric  ATOMIC_RMW8_U_ADD_I32, ATOMIC_RMW16_U_ADD_I32,
664*0b57cec5SDimitry Andric  ATOMIC_RMW8_U_ADD_I64, ATOMIC_RMW16_U_ADD_I64, ATOMIC_RMW32_U_ADD_I64>;
665*0b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern<
666*0b57cec5SDimitry Andric  atomic_load_sub_8, atomic_load_sub_16, atomic_load_sub_32, atomic_load_sub_64,
667*0b57cec5SDimitry Andric  ATOMIC_RMW8_U_SUB_I32, ATOMIC_RMW16_U_SUB_I32,
668*0b57cec5SDimitry Andric  ATOMIC_RMW8_U_SUB_I64, ATOMIC_RMW16_U_SUB_I64, ATOMIC_RMW32_U_SUB_I64>;
669*0b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern<
670*0b57cec5SDimitry Andric  atomic_load_and_8, atomic_load_and_16, atomic_load_and_32, atomic_load_and_64,
671*0b57cec5SDimitry Andric  ATOMIC_RMW8_U_AND_I32, ATOMIC_RMW16_U_AND_I32,
672*0b57cec5SDimitry Andric  ATOMIC_RMW8_U_AND_I64, ATOMIC_RMW16_U_AND_I64, ATOMIC_RMW32_U_AND_I64>;
673*0b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern<
674*0b57cec5SDimitry Andric  atomic_load_or_8, atomic_load_or_16, atomic_load_or_32, atomic_load_or_64,
675*0b57cec5SDimitry Andric  ATOMIC_RMW8_U_OR_I32, ATOMIC_RMW16_U_OR_I32,
676*0b57cec5SDimitry Andric  ATOMIC_RMW8_U_OR_I64, ATOMIC_RMW16_U_OR_I64, ATOMIC_RMW32_U_OR_I64>;
677*0b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern<
678*0b57cec5SDimitry Andric  atomic_load_xor_8, atomic_load_xor_16, atomic_load_xor_32, atomic_load_xor_64,
679*0b57cec5SDimitry Andric  ATOMIC_RMW8_U_XOR_I32, ATOMIC_RMW16_U_XOR_I32,
680*0b57cec5SDimitry Andric  ATOMIC_RMW8_U_XOR_I64, ATOMIC_RMW16_U_XOR_I64, ATOMIC_RMW32_U_XOR_I64>;
681*0b57cec5SDimitry Andricdefm : BinRMWTruncExtPattern<
682*0b57cec5SDimitry Andric  atomic_swap_8, atomic_swap_16, atomic_swap_32, atomic_swap_64,
683*0b57cec5SDimitry Andric  ATOMIC_RMW8_U_XCHG_I32, ATOMIC_RMW16_U_XCHG_I32,
684*0b57cec5SDimitry Andric  ATOMIC_RMW8_U_XCHG_I64, ATOMIC_RMW16_U_XCHG_I64, ATOMIC_RMW32_U_XCHG_I64>;
685*0b57cec5SDimitry Andric} // Predicates = [HasAtomics]
686*0b57cec5SDimitry Andric
687*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
688*0b57cec5SDimitry Andric// Atomic ternary read-modify-writes
689*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
690*0b57cec5SDimitry Andric
691*0b57cec5SDimitry Andric// TODO LLVM IR's cmpxchg instruction returns a pair of {loaded value, success
692*0b57cec5SDimitry Andric// flag}. When we use the success flag or both values, we can't make use of i64
693*0b57cec5SDimitry Andric// truncate/extend versions of instructions for now, which is suboptimal.
694*0b57cec5SDimitry Andric// Consider adding a pass after instruction selection that optimizes this case
695*0b57cec5SDimitry Andric// if it is frequent.
696*0b57cec5SDimitry Andric
697*0b57cec5SDimitry Andricmulticlass WebAssemblyTerRMW<WebAssemblyRegClass rc, string name,
698*0b57cec5SDimitry Andric                             int atomic_op> {
699*0b57cec5SDimitry Andric  defm "" :
700*0b57cec5SDimitry Andric    ATOMIC_I<(outs rc:$dst),
701*0b57cec5SDimitry Andric             (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$exp,
702*0b57cec5SDimitry Andric                  rc:$new_),
703*0b57cec5SDimitry Andric             (outs), (ins P2Align:$p2align, offset32_op:$off), [],
704*0b57cec5SDimitry Andric             !strconcat(name, "\t$dst, ${off}(${addr})${p2align}, $exp, $new_"),
705*0b57cec5SDimitry Andric             !strconcat(name, "\t${off}${p2align}"), atomic_op>;
706*0b57cec5SDimitry Andric}
707*0b57cec5SDimitry Andric
708*0b57cec5SDimitry Andricdefm ATOMIC_RMW_CMPXCHG_I32 :
709*0b57cec5SDimitry Andric  WebAssemblyTerRMW<I32, "i32.atomic.rmw.cmpxchg", 0x48>;
710*0b57cec5SDimitry Andricdefm ATOMIC_RMW_CMPXCHG_I64 :
711*0b57cec5SDimitry Andric  WebAssemblyTerRMW<I64, "i64.atomic.rmw.cmpxchg", 0x49>;
712*0b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_CMPXCHG_I32 :
713*0b57cec5SDimitry Andric  WebAssemblyTerRMW<I32, "i32.atomic.rmw8.cmpxchg_u", 0x4a>;
714*0b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_CMPXCHG_I32 :
715*0b57cec5SDimitry Andric  WebAssemblyTerRMW<I32, "i32.atomic.rmw16.cmpxchg_u", 0x4b>;
716*0b57cec5SDimitry Andricdefm ATOMIC_RMW8_U_CMPXCHG_I64 :
717*0b57cec5SDimitry Andric  WebAssemblyTerRMW<I64, "i64.atomic.rmw8.cmpxchg_u", 0x4c>;
718*0b57cec5SDimitry Andricdefm ATOMIC_RMW16_U_CMPXCHG_I64 :
719*0b57cec5SDimitry Andric  WebAssemblyTerRMW<I64, "i64.atomic.rmw16.cmpxchg_u", 0x4d>;
720*0b57cec5SDimitry Andricdefm ATOMIC_RMW32_U_CMPXCHG_I64 :
721*0b57cec5SDimitry Andric  WebAssemblyTerRMW<I64, "i64.atomic.rmw32.cmpxchg_u", 0x4e>;
722*0b57cec5SDimitry Andric
723*0b57cec5SDimitry Andric// Select ternary RMWs with no constant offset.
724*0b57cec5SDimitry Andricclass TerRMWPatNoOffset<ValueType ty, PatFrag kind, NI inst> :
725*0b57cec5SDimitry Andric  Pat<(ty (kind I32:$addr, ty:$exp, ty:$new)),
726*0b57cec5SDimitry Andric      (inst 0, 0, I32:$addr, ty:$exp, ty:$new)>;
727*0b57cec5SDimitry Andric
728*0b57cec5SDimitry Andric// Select ternary RMWs with a constant offset.
729*0b57cec5SDimitry Andric
730*0b57cec5SDimitry Andric// Pattern with address + immediate offset
731*0b57cec5SDimitry Andricclass TerRMWPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
732*0b57cec5SDimitry Andric  Pat<(ty (kind (operand I32:$addr, imm:$off), ty:$exp, ty:$new)),
733*0b57cec5SDimitry Andric      (inst 0, imm:$off, I32:$addr, ty:$exp, ty:$new)>;
734*0b57cec5SDimitry Andric
735*0b57cec5SDimitry Andricclass TerRMWPatGlobalAddr<ValueType ty, PatFrag kind, NI inst> :
736*0b57cec5SDimitry Andric  Pat<(ty (kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)),
737*0b57cec5SDimitry Andric                ty:$exp, ty:$new)),
738*0b57cec5SDimitry Andric      (inst 0, tglobaladdr:$off, I32:$addr, ty:$exp, ty:$new)>;
739*0b57cec5SDimitry Andric
740*0b57cec5SDimitry Andric// Select ternary RMWs with just a constant offset.
741*0b57cec5SDimitry Andricclass TerRMWPatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
742*0b57cec5SDimitry Andric  Pat<(ty (kind imm:$off, ty:$exp, ty:$new)),
743*0b57cec5SDimitry Andric      (inst 0, imm:$off, (CONST_I32 0), ty:$exp, ty:$new)>;
744*0b57cec5SDimitry Andric
745*0b57cec5SDimitry Andricclass TerRMWPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
746*0b57cec5SDimitry Andric  Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off), ty:$exp, ty:$new)),
747*0b57cec5SDimitry Andric      (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$exp, ty:$new)>;
748*0b57cec5SDimitry Andric
749*0b57cec5SDimitry Andric// Patterns for various addressing modes.
750*0b57cec5SDimitry Andricmulticlass TerRMWPattern<PatFrag rmw_32, PatFrag rmw_64, NI inst_32,
751*0b57cec5SDimitry Andric                         NI inst_64> {
752*0b57cec5SDimitry Andric  def : TerRMWPatNoOffset<i32, rmw_32, inst_32>;
753*0b57cec5SDimitry Andric  def : TerRMWPatNoOffset<i64, rmw_64, inst_64>;
754*0b57cec5SDimitry Andric
755*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i32, rmw_32, regPlusImm, inst_32>;
756*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i64, rmw_64, regPlusImm, inst_64>;
757*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i32, rmw_32, or_is_add, inst_32>;
758*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i64, rmw_64, or_is_add, inst_64>;
759*0b57cec5SDimitry Andric
760*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddr<i32, rmw_32, inst_32>;
761*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddr<i64, rmw_64, inst_64>;
762*0b57cec5SDimitry Andric
763*0b57cec5SDimitry Andric  def : TerRMWPatOffsetOnly<i32, rmw_32, inst_32>;
764*0b57cec5SDimitry Andric  def : TerRMWPatOffsetOnly<i64, rmw_64, inst_64>;
765*0b57cec5SDimitry Andric
766*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddrOffOnly<i32, rmw_32, inst_32>;
767*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddrOffOnly<i64, rmw_64, inst_64>;
768*0b57cec5SDimitry Andric}
769*0b57cec5SDimitry Andric
770*0b57cec5SDimitry Andriclet Predicates = [HasAtomics] in
771*0b57cec5SDimitry Andricdefm : TerRMWPattern<atomic_cmp_swap_32, atomic_cmp_swap_64,
772*0b57cec5SDimitry Andric                     ATOMIC_RMW_CMPXCHG_I32, ATOMIC_RMW_CMPXCHG_I64>;
773*0b57cec5SDimitry Andric
774*0b57cec5SDimitry Andric// Truncating & zero-extending ternary RMW patterns.
775*0b57cec5SDimitry Andric// DAG legalization & optimization before instruction selection may introduce
776*0b57cec5SDimitry Andric// additional nodes such as anyext or assertzext depending on operand types.
777*0b57cec5SDimitry Andricclass zext_ter_rmw_8_32<PatFrag kind> :
778*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$exp, node:$new),
779*0b57cec5SDimitry Andric          (and (i32 (kind node:$addr, node:$exp, node:$new)), 255)>;
780*0b57cec5SDimitry Andricclass zext_ter_rmw_16_32<PatFrag kind> :
781*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$exp, node:$new),
782*0b57cec5SDimitry Andric          (and (i32 (kind node:$addr, node:$exp, node:$new)), 65535)>;
783*0b57cec5SDimitry Andricclass zext_ter_rmw_8_64<PatFrag kind> :
784*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$exp, node:$new),
785*0b57cec5SDimitry Andric          (zext (i32 (assertzext (i32 (kind node:$addr,
786*0b57cec5SDimitry Andric                                            (i32 (trunc (i64 node:$exp))),
787*0b57cec5SDimitry Andric                                            (i32 (trunc (i64 node:$new))))))))>;
788*0b57cec5SDimitry Andricclass zext_ter_rmw_16_64<PatFrag kind> : zext_ter_rmw_8_64<kind>;
789*0b57cec5SDimitry Andricclass zext_ter_rmw_32_64<PatFrag kind> :
790*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$exp, node:$new),
791*0b57cec5SDimitry Andric          (zext (i32 (kind node:$addr,
792*0b57cec5SDimitry Andric                           (i32 (trunc (i64 node:$exp))),
793*0b57cec5SDimitry Andric                           (i32 (trunc (i64 node:$new))))))>;
794*0b57cec5SDimitry Andric
795*0b57cec5SDimitry Andric// Truncating & sign-extending ternary RMW patterns.
796*0b57cec5SDimitry Andric// We match subword RMWs (for 32-bit) and anyext RMWs (for 64-bit) and select a
797*0b57cec5SDimitry Andric// zext RMW; the next instruction will be sext_inreg which is selected by
798*0b57cec5SDimitry Andric// itself.
799*0b57cec5SDimitry Andricclass sext_ter_rmw_8_32<PatFrag kind> :
800*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$exp, node:$new),
801*0b57cec5SDimitry Andric          (kind node:$addr, node:$exp, node:$new)>;
802*0b57cec5SDimitry Andricclass sext_ter_rmw_16_32<PatFrag kind> : sext_ter_rmw_8_32<kind>;
803*0b57cec5SDimitry Andricclass sext_ter_rmw_8_64<PatFrag kind> :
804*0b57cec5SDimitry Andric  PatFrag<(ops node:$addr, node:$exp, node:$new),
805*0b57cec5SDimitry Andric          (anyext (i32 (assertzext (i32
806*0b57cec5SDimitry Andric            (kind node:$addr,
807*0b57cec5SDimitry Andric                  (i32 (trunc (i64 node:$exp))),
808*0b57cec5SDimitry Andric                  (i32 (trunc (i64 node:$new))))))))>;
809*0b57cec5SDimitry Andricclass sext_ter_rmw_16_64<PatFrag kind> : sext_ter_rmw_8_64<kind>;
810*0b57cec5SDimitry Andric// 32->64 sext RMW gets selected as i32.atomic.rmw.***, i64.extend_i32_s
811*0b57cec5SDimitry Andric
812*0b57cec5SDimitry Andric// Patterns for various addressing modes for truncating-extending ternary RMWs.
813*0b57cec5SDimitry Andricmulticlass TerRMWTruncExtPattern<
814*0b57cec5SDimitry Andric  PatFrag rmw_8, PatFrag rmw_16, PatFrag rmw_32, PatFrag rmw_64,
815*0b57cec5SDimitry Andric  NI inst8_32, NI inst16_32, NI inst8_64, NI inst16_64, NI inst32_64> {
816*0b57cec5SDimitry Andric  // Truncating-extending ternary RMWs with no constant offset
817*0b57cec5SDimitry Andric  def : TerRMWPatNoOffset<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>;
818*0b57cec5SDimitry Andric  def : TerRMWPatNoOffset<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>;
819*0b57cec5SDimitry Andric  def : TerRMWPatNoOffset<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>;
820*0b57cec5SDimitry Andric  def : TerRMWPatNoOffset<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>;
821*0b57cec5SDimitry Andric  def : TerRMWPatNoOffset<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>;
822*0b57cec5SDimitry Andric
823*0b57cec5SDimitry Andric  def : TerRMWPatNoOffset<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>;
824*0b57cec5SDimitry Andric  def : TerRMWPatNoOffset<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>;
825*0b57cec5SDimitry Andric  def : TerRMWPatNoOffset<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>;
826*0b57cec5SDimitry Andric  def : TerRMWPatNoOffset<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>;
827*0b57cec5SDimitry Andric
828*0b57cec5SDimitry Andric  // Truncating-extending ternary RMWs with a constant offset
829*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i32, zext_ter_rmw_8_32<rmw_8>, regPlusImm, inst8_32>;
830*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i32, zext_ter_rmw_16_32<rmw_16>, regPlusImm, inst16_32>;
831*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i64, zext_ter_rmw_8_64<rmw_8>, regPlusImm, inst8_64>;
832*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i64, zext_ter_rmw_16_64<rmw_16>, regPlusImm, inst16_64>;
833*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i64, zext_ter_rmw_32_64<rmw_32>, regPlusImm, inst32_64>;
834*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i32, zext_ter_rmw_8_32<rmw_8>, or_is_add, inst8_32>;
835*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i32, zext_ter_rmw_16_32<rmw_16>, or_is_add, inst16_32>;
836*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i64, zext_ter_rmw_8_64<rmw_8>, or_is_add, inst8_64>;
837*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i64, zext_ter_rmw_16_64<rmw_16>, or_is_add, inst16_64>;
838*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i64, zext_ter_rmw_32_64<rmw_32>, or_is_add, inst32_64>;
839*0b57cec5SDimitry Andric
840*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i32, sext_ter_rmw_8_32<rmw_8>, regPlusImm, inst8_32>;
841*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i32, sext_ter_rmw_16_32<rmw_16>, regPlusImm, inst16_32>;
842*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i64, sext_ter_rmw_8_64<rmw_8>, regPlusImm, inst8_64>;
843*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i64, sext_ter_rmw_16_64<rmw_16>, regPlusImm, inst16_64>;
844*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i32, sext_ter_rmw_8_32<rmw_8>, or_is_add, inst8_32>;
845*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i32, sext_ter_rmw_16_32<rmw_16>, or_is_add, inst16_32>;
846*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i64, sext_ter_rmw_8_64<rmw_8>, or_is_add, inst8_64>;
847*0b57cec5SDimitry Andric  def : TerRMWPatImmOff<i64, sext_ter_rmw_16_64<rmw_16>, or_is_add, inst16_64>;
848*0b57cec5SDimitry Andric
849*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddr<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>;
850*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddr<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>;
851*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddr<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>;
852*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddr<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>;
853*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddr<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>;
854*0b57cec5SDimitry Andric
855*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddr<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>;
856*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddr<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>;
857*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddr<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>;
858*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddr<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>;
859*0b57cec5SDimitry Andric
860*0b57cec5SDimitry Andric  // Truncating-extending ternary RMWs with just a constant offset
861*0b57cec5SDimitry Andric  def : TerRMWPatOffsetOnly<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>;
862*0b57cec5SDimitry Andric  def : TerRMWPatOffsetOnly<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>;
863*0b57cec5SDimitry Andric  def : TerRMWPatOffsetOnly<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>;
864*0b57cec5SDimitry Andric  def : TerRMWPatOffsetOnly<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>;
865*0b57cec5SDimitry Andric  def : TerRMWPatOffsetOnly<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>;
866*0b57cec5SDimitry Andric
867*0b57cec5SDimitry Andric  def : TerRMWPatOffsetOnly<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>;
868*0b57cec5SDimitry Andric  def : TerRMWPatOffsetOnly<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>;
869*0b57cec5SDimitry Andric  def : TerRMWPatOffsetOnly<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>;
870*0b57cec5SDimitry Andric  def : TerRMWPatOffsetOnly<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>;
871*0b57cec5SDimitry Andric
872*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddrOffOnly<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>;
873*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddrOffOnly<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>;
874*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>;
875*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>;
876*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>;
877*0b57cec5SDimitry Andric
878*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddrOffOnly<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>;
879*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddrOffOnly<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>;
880*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddrOffOnly<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>;
881*0b57cec5SDimitry Andric  def : TerRMWPatGlobalAddrOffOnly<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>;
882*0b57cec5SDimitry Andric}
883*0b57cec5SDimitry Andric
884*0b57cec5SDimitry Andriclet Predicates = [HasAtomics] in
885*0b57cec5SDimitry Andricdefm : TerRMWTruncExtPattern<
886*0b57cec5SDimitry Andric  atomic_cmp_swap_8, atomic_cmp_swap_16, atomic_cmp_swap_32, atomic_cmp_swap_64,
887*0b57cec5SDimitry Andric  ATOMIC_RMW8_U_CMPXCHG_I32, ATOMIC_RMW16_U_CMPXCHG_I32,
888*0b57cec5SDimitry Andric  ATOMIC_RMW8_U_CMPXCHG_I64, ATOMIC_RMW16_U_CMPXCHG_I64,
889*0b57cec5SDimitry Andric  ATOMIC_RMW32_U_CMPXCHG_I64>;
890*0b57cec5SDimitry Andric
891*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
892*0b57cec5SDimitry Andric// Atomic fences
893*0b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
894*0b57cec5SDimitry Andric
895*0b57cec5SDimitry Andric// A compiler fence instruction that prevents reordering of instructions.
896*0b57cec5SDimitry Andriclet Defs = [ARGUMENTS] in {
897*0b57cec5SDimitry Andriclet isPseudo = 1, hasSideEffects = 1 in
898*0b57cec5SDimitry Andricdefm COMPILER_FENCE : ATOMIC_NRI<(outs), (ins), [], "compiler_fence">;
899*0b57cec5SDimitry Andric} // Defs = [ARGUMENTS]
900