blob: 9eff2cfde0ad2fce8e82bfedf946e62d2f5f67b8 [file] [log] [blame]
Dan Gohman10e730a2015-06-29 23:51:55 +00001// WebAssemblyInstrAtomics.td-WebAssembly Atomic codegen support-*- tablegen -*-
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
JF Bastien5ca0bac2015-07-10 18:23:10 +00009///
10/// \file
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000011/// WebAssembly Atomic operand code-gen constructs.
JF Bastien5ca0bac2015-07-10 18:23:10 +000012///
Dan Gohman10e730a2015-06-29 23:51:55 +000013//===----------------------------------------------------------------------===//
14
Dan Gohman10e730a2015-06-29 23:51:55 +000015//===----------------------------------------------------------------------===//
16// Atomic loads
17//===----------------------------------------------------------------------===//
18
Thomas Lively914f0f22018-08-23 00:36:43 +000019multiclass ATOMIC_I<dag oops_r, dag iops_r, dag oops_s, dag iops_s,
20 list<dag> pattern_r, string asmstr_r = "",
21 string asmstr_s = "", bits<32> inst = -1> {
22 defm "" : I<oops_r, iops_r, oops_s, iops_s, pattern_r, asmstr_r, asmstr_s,
23 inst>,
24 Requires<[HasAtomics]>;
25}
26
Derek Schuff18ba1922017-08-30 18:07:45 +000027let Defs = [ARGUMENTS] in {
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +000028defm ATOMIC_LOAD_I32 : WebAssemblyLoad<I32, "i32.atomic.load", 0xfe10>;
29defm ATOMIC_LOAD_I64 : WebAssemblyLoad<I64, "i64.atomic.load", 0xfe11>;
Derek Schuff18ba1922017-08-30 18:07:45 +000030} // Defs = [ARGUMENTS]
31
32// Select loads with no constant offset.
33let Predicates = [HasAtomics] in {
Derek Schuff885dc592017-10-05 21:18:42 +000034def : LoadPatNoOffset<i32, atomic_load_32, ATOMIC_LOAD_I32>;
35def : LoadPatNoOffset<i64, atomic_load_64, ATOMIC_LOAD_I64>;
Derek Schuff0f3bc0f2017-08-31 21:51:48 +000036
Derek Schuff885dc592017-10-05 21:18:42 +000037// Select loads with a constant offset.
38
39// Pattern with address + immediate offset
40def : LoadPatImmOff<i32, atomic_load_32, regPlusImm, ATOMIC_LOAD_I32>;
41def : LoadPatImmOff<i64, atomic_load_64, regPlusImm, ATOMIC_LOAD_I64>;
42def : LoadPatImmOff<i32, atomic_load_32, or_is_add, ATOMIC_LOAD_I32>;
43def : LoadPatImmOff<i64, atomic_load_64, or_is_add, ATOMIC_LOAD_I64>;
44
45def : LoadPatGlobalAddr<i32, atomic_load_32, ATOMIC_LOAD_I32>;
46def : LoadPatGlobalAddr<i64, atomic_load_64, ATOMIC_LOAD_I64>;
47
48def : LoadPatExternalSym<i32, atomic_load_32, ATOMIC_LOAD_I32>;
49def : LoadPatExternalSym<i64, atomic_load_64, ATOMIC_LOAD_I64>;
50
Derek Schuff885dc592017-10-05 21:18:42 +000051// Select loads with just a constant offset.
52def : LoadPatOffsetOnly<i32, atomic_load_32, ATOMIC_LOAD_I32>;
53def : LoadPatOffsetOnly<i64, atomic_load_64, ATOMIC_LOAD_I64>;
54
55def : LoadPatGlobalAddrOffOnly<i32, atomic_load_32, ATOMIC_LOAD_I32>;
56def : LoadPatGlobalAddrOffOnly<i64, atomic_load_64, ATOMIC_LOAD_I64>;
57
58def : LoadPatExternSymOffOnly<i32, atomic_load_32, ATOMIC_LOAD_I32>;
59def : LoadPatExternSymOffOnly<i64, atomic_load_64, ATOMIC_LOAD_I64>;
60
61} // Predicates = [HasAtomics]
62
63// Extending loads. Note that there are only zero-extending atomic loads, no
64// sign-extending loads.
65let Defs = [ARGUMENTS] in {
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +000066defm ATOMIC_LOAD8_U_I32 : WebAssemblyLoad<I32, "i32.atomic.load8_u", 0xfe12>;
67defm ATOMIC_LOAD16_U_I32 : WebAssemblyLoad<I32, "i32.atomic.load16_u", 0xfe13>;
68defm ATOMIC_LOAD8_U_I64 : WebAssemblyLoad<I64, "i64.atomic.load8_u", 0xfe14>;
69defm ATOMIC_LOAD16_U_I64 : WebAssemblyLoad<I64, "i64.atomic.load16_u", 0xfe15>;
70defm ATOMIC_LOAD32_U_I64 : WebAssemblyLoad<I64, "i64.atomic.load32_u", 0xfe16>;
Derek Schuff885dc592017-10-05 21:18:42 +000071} // Defs = [ARGUMENTS]
72
Heejin Ahnd31bc982018-07-09 20:18:21 +000073// Fragments for extending loads. These are different from regular loads because
Derek Schuff885dc592017-10-05 21:18:42 +000074// the SDNodes are derived from AtomicSDNode rather than LoadSDNode and
75// therefore don't have the extension type field. So instead of matching that,
76// we match the patterns that the type legalizer expands them to.
77
78// We directly match zext patterns and select the zext atomic loads.
79// i32 (zext (i8 (atomic_load_8))) gets legalized to
80// i32 (and (i32 (atomic_load_8)), 255)
81// These can be selected to a single zero-extending atomic load instruction.
Heejin Ahnd31bc982018-07-09 20:18:21 +000082def zext_aload_8_32 :
83 PatFrag<(ops node:$addr), (and (i32 (atomic_load_8 node:$addr)), 255)>;
84def zext_aload_16_32 :
85 PatFrag<(ops node:$addr), (and (i32 (atomic_load_16 node:$addr)), 65535)>;
Derek Schuff885dc592017-10-05 21:18:42 +000086// Unlike regular loads, extension to i64 is handled differently than i32.
87// i64 (zext (i8 (atomic_load_8))) gets legalized to
88// i64 (and (i64 (anyext (i32 (atomic_load_8)))), 255)
89def zext_aload_8_64 :
90 PatFrag<(ops node:$addr),
91 (and (i64 (anyext (i32 (atomic_load_8 node:$addr)))), 255)>;
92def zext_aload_16_64 :
93 PatFrag<(ops node:$addr),
94 (and (i64 (anyext (i32 (atomic_load_16 node:$addr)))), 65535)>;
95def zext_aload_32_64 :
96 PatFrag<(ops node:$addr),
97 (zext (i32 (atomic_load node:$addr)))>;
98
99// We don't have single sext atomic load instructions. So for sext loads, we
100// match bare subword loads (for 32-bit results) and anyext loads (for 64-bit
101// results) and select a zext load; the next instruction will be sext_inreg
102// which is selected by itself.
Heejin Ahnd31bc982018-07-09 20:18:21 +0000103def sext_aload_8_64 :
Derek Schuff885dc592017-10-05 21:18:42 +0000104 PatFrag<(ops node:$addr), (anyext (i32 (atomic_load_8 node:$addr)))>;
Heejin Ahnd31bc982018-07-09 20:18:21 +0000105def sext_aload_16_64 :
Derek Schuff885dc592017-10-05 21:18:42 +0000106 PatFrag<(ops node:$addr), (anyext (i32 (atomic_load_16 node:$addr)))>;
107
108let Predicates = [HasAtomics] in {
109// Select zero-extending loads with no constant offset.
Heejin Ahnd31bc982018-07-09 20:18:21 +0000110def : LoadPatNoOffset<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
111def : LoadPatNoOffset<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
Derek Schuff885dc592017-10-05 21:18:42 +0000112def : LoadPatNoOffset<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
113def : LoadPatNoOffset<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
114def : LoadPatNoOffset<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
115
116// Select sign-extending loads with no constant offset
117def : LoadPatNoOffset<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
118def : LoadPatNoOffset<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
Heejin Ahnd31bc982018-07-09 20:18:21 +0000119def : LoadPatNoOffset<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
120def : LoadPatNoOffset<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
121// 32->64 sext load gets selected as i32.atomic.load, i64.extend_s/i32
Derek Schuff885dc592017-10-05 21:18:42 +0000122
123// Zero-extending loads with constant offset
Heejin Ahnd31bc982018-07-09 20:18:21 +0000124def : LoadPatImmOff<i32, zext_aload_8_32, regPlusImm, ATOMIC_LOAD8_U_I32>;
125def : LoadPatImmOff<i32, zext_aload_16_32, regPlusImm, ATOMIC_LOAD16_U_I32>;
126def : LoadPatImmOff<i32, zext_aload_8_32, or_is_add, ATOMIC_LOAD8_U_I32>;
127def : LoadPatImmOff<i32, zext_aload_16_32, or_is_add, ATOMIC_LOAD16_U_I32>;
Derek Schuff885dc592017-10-05 21:18:42 +0000128def : LoadPatImmOff<i64, zext_aload_8_64, regPlusImm, ATOMIC_LOAD8_U_I64>;
129def : LoadPatImmOff<i64, zext_aload_16_64, regPlusImm, ATOMIC_LOAD16_U_I64>;
130def : LoadPatImmOff<i64, zext_aload_32_64, regPlusImm, ATOMIC_LOAD32_U_I64>;
131def : LoadPatImmOff<i64, zext_aload_8_64, or_is_add, ATOMIC_LOAD8_U_I64>;
132def : LoadPatImmOff<i64, zext_aload_16_64, or_is_add, ATOMIC_LOAD16_U_I64>;
133def : LoadPatImmOff<i64, zext_aload_32_64, or_is_add, ATOMIC_LOAD32_U_I64>;
134
135// Sign-extending loads with constant offset
136def : LoadPatImmOff<i32, atomic_load_8, regPlusImm, ATOMIC_LOAD8_U_I32>;
137def : LoadPatImmOff<i32, atomic_load_16, regPlusImm, ATOMIC_LOAD16_U_I32>;
138def : LoadPatImmOff<i32, atomic_load_8, or_is_add, ATOMIC_LOAD8_U_I32>;
139def : LoadPatImmOff<i32, atomic_load_16, or_is_add, ATOMIC_LOAD16_U_I32>;
Heejin Ahnd31bc982018-07-09 20:18:21 +0000140def : LoadPatImmOff<i64, sext_aload_8_64, regPlusImm, ATOMIC_LOAD8_U_I64>;
141def : LoadPatImmOff<i64, sext_aload_16_64, regPlusImm, ATOMIC_LOAD16_U_I64>;
142def : LoadPatImmOff<i64, sext_aload_8_64, or_is_add, ATOMIC_LOAD8_U_I64>;
143def : LoadPatImmOff<i64, sext_aload_16_64, or_is_add, ATOMIC_LOAD16_U_I64>;
Derek Schuff885dc592017-10-05 21:18:42 +0000144// No 32->64 patterns, just use i32.atomic.load and i64.extend_s/i64
145
Heejin Ahnd31bc982018-07-09 20:18:21 +0000146def : LoadPatGlobalAddr<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
147def : LoadPatGlobalAddr<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
Derek Schuff885dc592017-10-05 21:18:42 +0000148def : LoadPatGlobalAddr<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
149def : LoadPatGlobalAddr<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
150def : LoadPatGlobalAddr<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
151def : LoadPatGlobalAddr<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
152def : LoadPatGlobalAddr<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
Heejin Ahnd31bc982018-07-09 20:18:21 +0000153def : LoadPatGlobalAddr<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
154def : LoadPatGlobalAddr<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
Derek Schuff885dc592017-10-05 21:18:42 +0000155
Heejin Ahnd31bc982018-07-09 20:18:21 +0000156def : LoadPatExternalSym<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
157def : LoadPatExternalSym<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
Derek Schuff885dc592017-10-05 21:18:42 +0000158def : LoadPatExternalSym<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
159def : LoadPatExternalSym<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
160def : LoadPatExternalSym<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
161def : LoadPatExternalSym<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
162def : LoadPatExternalSym<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
Heejin Ahnd31bc982018-07-09 20:18:21 +0000163def : LoadPatExternalSym<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
164def : LoadPatExternalSym<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
Derek Schuff885dc592017-10-05 21:18:42 +0000165
166// Extending loads with just a constant offset
Heejin Ahnd31bc982018-07-09 20:18:21 +0000167def : LoadPatOffsetOnly<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
168def : LoadPatOffsetOnly<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
Derek Schuff885dc592017-10-05 21:18:42 +0000169def : LoadPatOffsetOnly<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
170def : LoadPatOffsetOnly<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
171def : LoadPatOffsetOnly<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
172def : LoadPatOffsetOnly<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
173def : LoadPatOffsetOnly<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
Heejin Ahnd31bc982018-07-09 20:18:21 +0000174def : LoadPatOffsetOnly<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
175def : LoadPatOffsetOnly<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
Derek Schuff885dc592017-10-05 21:18:42 +0000176
Heejin Ahnd31bc982018-07-09 20:18:21 +0000177def : LoadPatGlobalAddrOffOnly<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
178def : LoadPatGlobalAddrOffOnly<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
Derek Schuff885dc592017-10-05 21:18:42 +0000179def : LoadPatGlobalAddrOffOnly<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
180def : LoadPatGlobalAddrOffOnly<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
181def : LoadPatGlobalAddrOffOnly<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
182def : LoadPatGlobalAddrOffOnly<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
183def : LoadPatGlobalAddrOffOnly<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
Heejin Ahnd31bc982018-07-09 20:18:21 +0000184def : LoadPatGlobalAddrOffOnly<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
185def : LoadPatGlobalAddrOffOnly<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
Derek Schuff885dc592017-10-05 21:18:42 +0000186
Heejin Ahnd31bc982018-07-09 20:18:21 +0000187def : LoadPatExternSymOffOnly<i32, zext_aload_8_32, ATOMIC_LOAD8_U_I32>;
188def : LoadPatExternSymOffOnly<i32, zext_aload_16_32, ATOMIC_LOAD16_U_I32>;
Derek Schuff885dc592017-10-05 21:18:42 +0000189def : LoadPatExternSymOffOnly<i64, zext_aload_8_64, ATOMIC_LOAD8_U_I64>;
190def : LoadPatExternSymOffOnly<i64, zext_aload_16_64, ATOMIC_LOAD16_U_I64>;
191def : LoadPatExternSymOffOnly<i64, zext_aload_32_64, ATOMIC_LOAD32_U_I64>;
192def : LoadPatExternSymOffOnly<i32, atomic_load_8, ATOMIC_LOAD8_U_I32>;
193def : LoadPatExternSymOffOnly<i32, atomic_load_16, ATOMIC_LOAD16_U_I32>;
Heejin Ahnd31bc982018-07-09 20:18:21 +0000194def : LoadPatExternSymOffOnly<i64, sext_aload_8_64, ATOMIC_LOAD8_U_I64>;
195def : LoadPatExternSymOffOnly<i64, sext_aload_16_64, ATOMIC_LOAD16_U_I64>;
Derek Schuff885dc592017-10-05 21:18:42 +0000196
197} // Predicates = [HasAtomics]
Dan Gohman10e730a2015-06-29 23:51:55 +0000198
199//===----------------------------------------------------------------------===//
200// Atomic stores
201//===----------------------------------------------------------------------===//
202
Heejin Ahn402b4902018-07-02 21:22:59 +0000203let Defs = [ARGUMENTS] in {
204defm ATOMIC_STORE_I32 : WebAssemblyStore<I32, "i32.atomic.store", 0xfe17>;
205defm ATOMIC_STORE_I64 : WebAssemblyStore<I64, "i64.atomic.store", 0xfe18>;
206} // Defs = [ARGUMENTS]
207
208// We need an 'atomic' version of store patterns because store and atomic_store
209// nodes have different operand orders:
210// store: (store $val, $ptr)
211// atomic_store: (store $ptr, $val)
212
213let Predicates = [HasAtomics] in {
214
215// Select stores with no constant offset.
Heejin Ahnd31bc982018-07-09 20:18:21 +0000216class AStorePatNoOffset<ValueType ty, PatFrag kind, NI inst> :
217 Pat<(kind I32:$addr, ty:$val), (inst 0, 0, I32:$addr, ty:$val)>;
Heejin Ahn402b4902018-07-02 21:22:59 +0000218def : AStorePatNoOffset<i32, atomic_store_32, ATOMIC_STORE_I32>;
219def : AStorePatNoOffset<i64, atomic_store_64, ATOMIC_STORE_I64>;
220
221// Select stores with a constant offset.
222
223// Pattern with address + immediate offset
Heejin Ahnd31bc982018-07-09 20:18:21 +0000224class AStorePatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
225 Pat<(kind (operand I32:$addr, imm:$off), ty:$val),
226 (inst 0, imm:$off, I32:$addr, ty:$val)>;
Heejin Ahn402b4902018-07-02 21:22:59 +0000227def : AStorePatImmOff<i32, atomic_store_32, regPlusImm, ATOMIC_STORE_I32>;
228def : AStorePatImmOff<i64, atomic_store_64, regPlusImm, ATOMIC_STORE_I64>;
229def : AStorePatImmOff<i32, atomic_store_32, or_is_add, ATOMIC_STORE_I32>;
230def : AStorePatImmOff<i64, atomic_store_64, or_is_add, ATOMIC_STORE_I64>;
231
Heejin Ahnd31bc982018-07-09 20:18:21 +0000232class AStorePatGlobalAddr<ValueType ty, PatFrag kind, NI inst> :
233 Pat<(kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)),
234 ty:$val),
Heejin Ahn402b4902018-07-02 21:22:59 +0000235 (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>;
236def : AStorePatGlobalAddr<i32, atomic_store_32, ATOMIC_STORE_I32>;
237def : AStorePatGlobalAddr<i64, atomic_store_64, ATOMIC_STORE_I64>;
238
Heejin Ahnd31bc982018-07-09 20:18:21 +0000239class AStorePatExternalSym<ValueType ty, PatFrag kind, NI inst> :
240 Pat<(kind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)), ty:$val),
Heejin Ahn402b4902018-07-02 21:22:59 +0000241 (inst 0, texternalsym:$off, I32:$addr, ty:$val)>;
242def : AStorePatExternalSym<i32, atomic_store_32, ATOMIC_STORE_I32>;
243def : AStorePatExternalSym<i64, atomic_store_64, ATOMIC_STORE_I64>;
244
245// Select stores with just a constant offset.
Heejin Ahnd31bc982018-07-09 20:18:21 +0000246class AStorePatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
247 Pat<(kind imm:$off, ty:$val), (inst 0, imm:$off, (CONST_I32 0), ty:$val)>;
Heejin Ahn402b4902018-07-02 21:22:59 +0000248def : AStorePatOffsetOnly<i32, atomic_store_32, ATOMIC_STORE_I32>;
249def : AStorePatOffsetOnly<i64, atomic_store_64, ATOMIC_STORE_I64>;
250
Heejin Ahnd31bc982018-07-09 20:18:21 +0000251class AStorePatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
252 Pat<(kind (WebAssemblywrapper tglobaladdr:$off), ty:$val),
Heejin Ahn402b4902018-07-02 21:22:59 +0000253 (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>;
254def : AStorePatGlobalAddrOffOnly<i32, atomic_store_32, ATOMIC_STORE_I32>;
255def : AStorePatGlobalAddrOffOnly<i64, atomic_store_64, ATOMIC_STORE_I64>;
256
Heejin Ahnd31bc982018-07-09 20:18:21 +0000257class AStorePatExternSymOffOnly<ValueType ty, PatFrag kind, NI inst> :
258 Pat<(kind (WebAssemblywrapper texternalsym:$off), ty:$val),
Heejin Ahn402b4902018-07-02 21:22:59 +0000259 (inst 0, texternalsym:$off, (CONST_I32 0), ty:$val)>;
260def : AStorePatExternSymOffOnly<i32, atomic_store_32, ATOMIC_STORE_I32>;
261def : AStorePatExternSymOffOnly<i64, atomic_store_64, ATOMIC_STORE_I64>;
262
263} // Predicates = [HasAtomics]
264
265// Truncating stores.
266let Defs = [ARGUMENTS] in {
267defm ATOMIC_STORE8_I32 : WebAssemblyStore<I32, "i32.atomic.store8", 0xfe19>;
268defm ATOMIC_STORE16_I32 : WebAssemblyStore<I32, "i32.atomic.store16", 0xfe1a>;
269defm ATOMIC_STORE8_I64 : WebAssemblyStore<I64, "i64.atomic.store8", 0xfe1b>;
270defm ATOMIC_STORE16_I64 : WebAssemblyStore<I64, "i64.atomic.store16", 0xfe1c>;
271defm ATOMIC_STORE32_I64 : WebAssemblyStore<I64, "i64.atomic.store32", 0xfe1d>;
272} // Defs = [ARGUMENTS]
273
274// Fragments for truncating stores.
275
276// We don't have single truncating atomic store instructions. For 32-bit
277// instructions, we just need to match bare atomic stores. On the other hand,
278// truncating stores from i64 values are once truncated to i32 first.
Heejin Ahnd31bc982018-07-09 20:18:21 +0000279class trunc_astore_64<PatFrag kind> :
Heejin Ahn402b4902018-07-02 21:22:59 +0000280 PatFrag<(ops node:$addr, node:$val),
Heejin Ahnd31bc982018-07-09 20:18:21 +0000281 (kind node:$addr, (i32 (trunc (i64 node:$val))))>;
Heejin Ahn402b4902018-07-02 21:22:59 +0000282def trunc_astore_8_64 : trunc_astore_64<atomic_store_8>;
283def trunc_astore_16_64 : trunc_astore_64<atomic_store_16>;
284def trunc_astore_32_64 : trunc_astore_64<atomic_store_32>;
285
286let Predicates = [HasAtomics] in {
287
288// Truncating stores with no constant offset
289def : AStorePatNoOffset<i32, atomic_store_8, ATOMIC_STORE8_I32>;
290def : AStorePatNoOffset<i32, atomic_store_16, ATOMIC_STORE16_I32>;
291def : AStorePatNoOffset<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
292def : AStorePatNoOffset<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
293def : AStorePatNoOffset<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
294
295// Truncating stores with a constant offset
296def : AStorePatImmOff<i32, atomic_store_8, regPlusImm, ATOMIC_STORE8_I32>;
297def : AStorePatImmOff<i32, atomic_store_16, regPlusImm, ATOMIC_STORE16_I32>;
298def : AStorePatImmOff<i64, trunc_astore_8_64, regPlusImm, ATOMIC_STORE8_I64>;
299def : AStorePatImmOff<i64, trunc_astore_16_64, regPlusImm, ATOMIC_STORE16_I64>;
300def : AStorePatImmOff<i64, trunc_astore_32_64, regPlusImm, ATOMIC_STORE32_I64>;
301def : AStorePatImmOff<i32, atomic_store_8, or_is_add, ATOMIC_STORE8_I32>;
302def : AStorePatImmOff<i32, atomic_store_16, or_is_add, ATOMIC_STORE16_I32>;
303def : AStorePatImmOff<i64, trunc_astore_8_64, or_is_add, ATOMIC_STORE8_I64>;
304def : AStorePatImmOff<i64, trunc_astore_16_64, or_is_add, ATOMIC_STORE16_I64>;
305def : AStorePatImmOff<i64, trunc_astore_32_64, or_is_add, ATOMIC_STORE32_I64>;
306
307def : AStorePatGlobalAddr<i32, atomic_store_8, ATOMIC_STORE8_I32>;
308def : AStorePatGlobalAddr<i32, atomic_store_16, ATOMIC_STORE16_I32>;
309def : AStorePatGlobalAddr<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
310def : AStorePatGlobalAddr<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
311def : AStorePatGlobalAddr<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
312
313def : AStorePatExternalSym<i32, atomic_store_8, ATOMIC_STORE8_I32>;
314def : AStorePatExternalSym<i32, atomic_store_16, ATOMIC_STORE16_I32>;
315def : AStorePatExternalSym<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
316def : AStorePatExternalSym<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
317def : AStorePatExternalSym<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
318
319// Truncating stores with just a constant offset
320def : AStorePatOffsetOnly<i32, atomic_store_8, ATOMIC_STORE8_I32>;
321def : AStorePatOffsetOnly<i32, atomic_store_16, ATOMIC_STORE16_I32>;
322def : AStorePatOffsetOnly<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
323def : AStorePatOffsetOnly<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
324def : AStorePatOffsetOnly<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
325
326def : AStorePatGlobalAddrOffOnly<i32, atomic_store_8, ATOMIC_STORE8_I32>;
327def : AStorePatGlobalAddrOffOnly<i32, atomic_store_16, ATOMIC_STORE16_I32>;
328def : AStorePatGlobalAddrOffOnly<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
329def : AStorePatGlobalAddrOffOnly<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
330def : AStorePatGlobalAddrOffOnly<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
331
332def : AStorePatExternSymOffOnly<i32, atomic_store_8, ATOMIC_STORE8_I32>;
333def : AStorePatExternSymOffOnly<i32, atomic_store_16, ATOMIC_STORE16_I32>;
334def : AStorePatExternSymOffOnly<i64, trunc_astore_8_64, ATOMIC_STORE8_I64>;
335def : AStorePatExternSymOffOnly<i64, trunc_astore_16_64, ATOMIC_STORE16_I64>;
336def : AStorePatExternSymOffOnly<i64, trunc_astore_32_64, ATOMIC_STORE32_I64>;
337
338} // Predicates = [HasAtomics]
Dan Gohman10e730a2015-06-29 23:51:55 +0000339
340//===----------------------------------------------------------------------===//
Heejin Ahnfed73822018-07-09 22:30:51 +0000341// Atomic binary read-modify-writes
Dan Gohman10e730a2015-06-29 23:51:55 +0000342//===----------------------------------------------------------------------===//
343
Heejin Ahnfed73822018-07-09 22:30:51 +0000344let Defs = [ARGUMENTS] in {
Dan Gohman10e730a2015-06-29 23:51:55 +0000345
Heejin Ahnfed73822018-07-09 22:30:51 +0000346multiclass WebAssemblyBinRMW<WebAssemblyRegClass rc, string Name, int Opcode> {
347 defm "" : I<(outs rc:$dst),
348 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
349 (outs), (ins P2Align:$p2align, offset32_op:$off), [],
350 !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}, $val"),
351 !strconcat(Name, "\t${off}, ${p2align}"), Opcode>;
352}
Dan Gohman10e730a2015-06-29 23:51:55 +0000353
Heejin Ahnfed73822018-07-09 22:30:51 +0000354defm ATOMIC_RMW_ADD_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.add", 0xfe1e>;
355defm ATOMIC_RMW_ADD_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.add", 0xfe1f>;
356defm ATOMIC_RMW8_U_ADD_I32 :
357 WebAssemblyBinRMW<I32, "i32.atomic.rmw8_u.add", 0xfe20>;
358defm ATOMIC_RMW16_U_ADD_I32 :
359 WebAssemblyBinRMW<I32, "i32.atomic.rmw16_u.add", 0xfe21>;
360defm ATOMIC_RMW8_U_ADD_I64 :
361 WebAssemblyBinRMW<I64, "i64.atomic.rmw8_u.add", 0xfe22>;
362defm ATOMIC_RMW16_U_ADD_I64 :
363 WebAssemblyBinRMW<I64, "i64.atomic.rmw16_u.add", 0xfe23>;
364defm ATOMIC_RMW32_U_ADD_I64 :
365 WebAssemblyBinRMW<I64, "i64.atomic.rmw32_u.add", 0xfe24>;
Dan Gohman10e730a2015-06-29 23:51:55 +0000366
Heejin Ahnfed73822018-07-09 22:30:51 +0000367defm ATOMIC_RMW_SUB_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.sub", 0xfe25>;
368defm ATOMIC_RMW_SUB_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.sub", 0xfe26>;
369defm ATOMIC_RMW8_U_SUB_I32 :
370 WebAssemblyBinRMW<I32, "i32.atomic.rmw8_u.sub", 0xfe27>;
371defm ATOMIC_RMW16_U_SUB_I32 :
372 WebAssemblyBinRMW<I32, "i32.atomic.rmw16_u.sub", 0xfe28>;
373defm ATOMIC_RMW8_U_SUB_I64 :
374 WebAssemblyBinRMW<I64, "i64.atomic.rmw8_u.sub", 0xfe29>;
375defm ATOMIC_RMW16_U_SUB_I64 :
376 WebAssemblyBinRMW<I64, "i64.atomic.rmw16_u.sub", 0xfe2a>;
377defm ATOMIC_RMW32_U_SUB_I64 :
378 WebAssemblyBinRMW<I64, "i64.atomic.rmw32_u.sub", 0xfe2b>;
Dan Gohman10e730a2015-06-29 23:51:55 +0000379
Heejin Ahnfed73822018-07-09 22:30:51 +0000380defm ATOMIC_RMW_AND_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.and", 0xfe2c>;
381defm ATOMIC_RMW_AND_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.and", 0xfe2d>;
382defm ATOMIC_RMW8_U_AND_I32 :
383 WebAssemblyBinRMW<I32, "i32.atomic.rmw8_u.and", 0xfe2e>;
384defm ATOMIC_RMW16_U_AND_I32 :
385 WebAssemblyBinRMW<I32, "i32.atomic.rmw16_u.and", 0xfe2f>;
386defm ATOMIC_RMW8_U_AND_I64 :
387 WebAssemblyBinRMW<I64, "i64.atomic.rmw8_u.and", 0xfe30>;
388defm ATOMIC_RMW16_U_AND_I64 :
389 WebAssemblyBinRMW<I64, "i64.atomic.rmw16_u.and", 0xfe31>;
390defm ATOMIC_RMW32_U_AND_I64 :
391 WebAssemblyBinRMW<I64, "i64.atomic.rmw32_u.and", 0xfe32>;
Derek Schuff18ba1922017-08-30 18:07:45 +0000392
Heejin Ahnfed73822018-07-09 22:30:51 +0000393defm ATOMIC_RMW_OR_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.or", 0xfe33>;
394defm ATOMIC_RMW_OR_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.or", 0xfe34>;
395defm ATOMIC_RMW8_U_OR_I32 :
396 WebAssemblyBinRMW<I32, "i32.atomic.rmw8_u.or", 0xfe35>;
397defm ATOMIC_RMW16_U_OR_I32 :
398 WebAssemblyBinRMW<I32, "i32.atomic.rmw16_u.or", 0xfe36>;
399defm ATOMIC_RMW8_U_OR_I64 :
400 WebAssemblyBinRMW<I64, "i64.atomic.rmw8_u.or", 0xfe37>;
401defm ATOMIC_RMW16_U_OR_I64 :
402 WebAssemblyBinRMW<I64, "i64.atomic.rmw16_u.or", 0xfe38>;
403defm ATOMIC_RMW32_U_OR_I64 :
404 WebAssemblyBinRMW<I64, "i64.atomic.rmw32_u.or", 0xfe39>;
405
406defm ATOMIC_RMW_XOR_I32 : WebAssemblyBinRMW<I32, "i32.atomic.rmw.xor", 0xfe3a>;
407defm ATOMIC_RMW_XOR_I64 : WebAssemblyBinRMW<I64, "i64.atomic.rmw.xor", 0xfe3b>;
408defm ATOMIC_RMW8_U_XOR_I32 :
409 WebAssemblyBinRMW<I32, "i32.atomic.rmw8_u.xor", 0xfe3c>;
410defm ATOMIC_RMW16_U_XOR_I32 :
411 WebAssemblyBinRMW<I32, "i32.atomic.rmw16_u.xor", 0xfe3d>;
412defm ATOMIC_RMW8_U_XOR_I64 :
413 WebAssemblyBinRMW<I64, "i64.atomic.rmw8_u.xor", 0xfe3e>;
414defm ATOMIC_RMW16_U_XOR_I64 :
415 WebAssemblyBinRMW<I64, "i64.atomic.rmw16_u.xor", 0xfe3f>;
416defm ATOMIC_RMW32_U_XOR_I64 :
417 WebAssemblyBinRMW<I64, "i64.atomic.rmw32_u.xor", 0xfe40>;
418
419defm ATOMIC_RMW_XCHG_I32 :
420 WebAssemblyBinRMW<I32, "i32.atomic.rmw.xchg", 0xfe41>;
421defm ATOMIC_RMW_XCHG_I64 :
422 WebAssemblyBinRMW<I64, "i64.atomic.rmw.xchg", 0xfe42>;
423defm ATOMIC_RMW8_U_XCHG_I32 :
424 WebAssemblyBinRMW<I32, "i32.atomic.rmw8_u.xchg", 0xfe43>;
425defm ATOMIC_RMW16_U_XCHG_I32 :
426 WebAssemblyBinRMW<I32, "i32.atomic.rmw16_u.xchg", 0xfe44>;
427defm ATOMIC_RMW8_U_XCHG_I64 :
428 WebAssemblyBinRMW<I64, "i64.atomic.rmw8_u.xchg", 0xfe45>;
429defm ATOMIC_RMW16_U_XCHG_I64 :
430 WebAssemblyBinRMW<I64, "i64.atomic.rmw16_u.xchg", 0xfe46>;
431defm ATOMIC_RMW32_U_XCHG_I64 :
432 WebAssemblyBinRMW<I64, "i64.atomic.rmw32_u.xchg", 0xfe47>;
433}
434
435// Select binary RMWs with no constant offset.
436class BinRMWPatNoOffset<ValueType ty, PatFrag kind, NI inst> :
437 Pat<(ty (kind I32:$addr, ty:$val)), (inst 0, 0, I32:$addr, ty:$val)>;
438
439// Select binary RMWs with a constant offset.
440
441// Pattern with address + immediate offset
442class BinRMWPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
443 Pat<(ty (kind (operand I32:$addr, imm:$off), ty:$val)),
444 (inst 0, imm:$off, I32:$addr, ty:$val)>;
445
446class BinRMWPatGlobalAddr<ValueType ty, PatFrag kind, NI inst> :
447 Pat<(ty (kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)),
448 ty:$val)),
449 (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>;
450
451class BinRMWPatExternalSym<ValueType ty, PatFrag kind, NI inst> :
452 Pat<(ty (kind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)),
453 ty:$val)),
454 (inst 0, texternalsym:$off, I32:$addr, ty:$val)>;
455
456// Select binary RMWs with just a constant offset.
457class BinRMWPatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
458 Pat<(ty (kind imm:$off, ty:$val)),
459 (inst 0, imm:$off, (CONST_I32 0), ty:$val)>;
460
461class BinRMWPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
462 Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off), ty:$val)),
463 (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>;
464
465class BinRMWPatExternSymOffOnly<ValueType ty, PatFrag kind, NI inst> :
466 Pat<(ty (kind (WebAssemblywrapper texternalsym:$off), ty:$val)),
467 (inst 0, texternalsym:$off, (CONST_I32 0), ty:$val)>;
468
469// Patterns for various addressing modes.
470multiclass BinRMWPattern<PatFrag rmw_32, PatFrag rmw_64, NI inst_32,
471 NI inst_64> {
472 def : BinRMWPatNoOffset<i32, rmw_32, inst_32>;
473 def : BinRMWPatNoOffset<i64, rmw_64, inst_64>;
474
475 def : BinRMWPatImmOff<i32, rmw_32, regPlusImm, inst_32>;
476 def : BinRMWPatImmOff<i64, rmw_64, regPlusImm, inst_64>;
477 def : BinRMWPatImmOff<i32, rmw_32, or_is_add, inst_32>;
478 def : BinRMWPatImmOff<i64, rmw_64, or_is_add, inst_64>;
479
480 def : BinRMWPatGlobalAddr<i32, rmw_32, inst_32>;
481 def : BinRMWPatGlobalAddr<i64, rmw_64, inst_64>;
482
483 def : BinRMWPatExternalSym<i32, rmw_32, inst_32>;
484 def : BinRMWPatExternalSym<i64, rmw_64, inst_64>;
485
486 def : BinRMWPatOffsetOnly<i32, rmw_32, inst_32>;
487 def : BinRMWPatOffsetOnly<i64, rmw_64, inst_64>;
488
489 def : BinRMWPatGlobalAddrOffOnly<i32, rmw_32, inst_32>;
490 def : BinRMWPatGlobalAddrOffOnly<i64, rmw_64, inst_64>;
491
492 def : BinRMWPatExternSymOffOnly<i32, rmw_32, inst_32>;
493 def : BinRMWPatExternSymOffOnly<i64, rmw_64, inst_64>;
494}
495
496let Predicates = [HasAtomics] in {
497defm : BinRMWPattern<atomic_load_add_32, atomic_load_add_64, ATOMIC_RMW_ADD_I32,
498 ATOMIC_RMW_ADD_I64>;
499defm : BinRMWPattern<atomic_load_sub_32, atomic_load_sub_64, ATOMIC_RMW_SUB_I32,
500 ATOMIC_RMW_SUB_I64>;
501defm : BinRMWPattern<atomic_load_and_32, atomic_load_and_64, ATOMIC_RMW_AND_I32,
502 ATOMIC_RMW_AND_I64>;
503defm : BinRMWPattern<atomic_load_or_32, atomic_load_or_64, ATOMIC_RMW_OR_I32,
504 ATOMIC_RMW_OR_I64>;
505defm : BinRMWPattern<atomic_load_xor_32, atomic_load_xor_64, ATOMIC_RMW_XOR_I32,
506 ATOMIC_RMW_XOR_I64>;
507defm : BinRMWPattern<atomic_swap_32, atomic_swap_64, ATOMIC_RMW_XCHG_I32,
508 ATOMIC_RMW_XCHG_I64>;
509} // Predicates = [HasAtomics]
510
511// Truncating & zero-extending binary RMW patterns.
512// These are combined patterns of truncating store patterns and zero-extending
513// load patterns above.
514class zext_bin_rmw_8_32<PatFrag kind> :
515 PatFrag<(ops node:$addr, node:$val),
516 (and (i32 (kind node:$addr, node:$val)), 255)>;
517class zext_bin_rmw_16_32<PatFrag kind> :
518 PatFrag<(ops node:$addr, node:$val),
519 (and (i32 (kind node:$addr, node:$val)), 65535)>;
520class zext_bin_rmw_8_64<PatFrag kind> :
521 PatFrag<(ops node:$addr, node:$val),
522 (and (i64 (anyext (i32 (kind node:$addr,
523 (i32 (trunc (i64 node:$val))))))), 255)>;
524class zext_bin_rmw_16_64<PatFrag kind> :
525 PatFrag<(ops node:$addr, node:$val),
526 (and (i64 (anyext (i32 (kind node:$addr,
527 (i32 (trunc (i64 node:$val))))))), 65535)>;
528class zext_bin_rmw_32_64<PatFrag kind> :
529 PatFrag<(ops node:$addr, node:$val),
530 (zext (i32 (kind node:$addr, (i32 (trunc (i64 node:$val))))))>;
531
532// Truncating & sign-extending binary RMW patterns.
533// These are combined patterns of truncating store patterns and sign-extending
534// load patterns above. We match subword RMWs (for 32-bit) and anyext RMWs (for
535// 64-bit) and select a zext RMW; the next instruction will be sext_inreg which
536// is selected by itself.
537class sext_bin_rmw_8_32<PatFrag kind> :
538 PatFrag<(ops node:$addr, node:$val), (kind node:$addr, node:$val)>;
539class sext_bin_rmw_16_32<PatFrag kind> : sext_bin_rmw_8_32<kind>;
540class sext_bin_rmw_8_64<PatFrag kind> :
541 PatFrag<(ops node:$addr, node:$val),
542 (anyext (i32 (kind node:$addr, (i32 (trunc (i64 node:$val))))))>;
543class sext_bin_rmw_16_64<PatFrag kind> : sext_bin_rmw_8_64<kind>;
544// 32->64 sext RMW gets selected as i32.atomic.rmw.***, i64.extend_s/i32
545
546// Patterns for various addressing modes for truncating-extending binary RMWs.
547multiclass BinRMWTruncExtPattern<
548 PatFrag rmw_8, PatFrag rmw_16, PatFrag rmw_32, PatFrag rmw_64,
549 NI inst8_32, NI inst16_32, NI inst8_64, NI inst16_64, NI inst32_64> {
550 // Truncating-extending binary RMWs with no constant offset
551 def : BinRMWPatNoOffset<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
552 def : BinRMWPatNoOffset<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
553 def : BinRMWPatNoOffset<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
554 def : BinRMWPatNoOffset<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
555 def : BinRMWPatNoOffset<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
556
557 def : BinRMWPatNoOffset<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
558 def : BinRMWPatNoOffset<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
559 def : BinRMWPatNoOffset<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
560 def : BinRMWPatNoOffset<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
561
562 // Truncating-extending binary RMWs with a constant offset
563 def : BinRMWPatImmOff<i32, zext_bin_rmw_8_32<rmw_8>, regPlusImm, inst8_32>;
564 def : BinRMWPatImmOff<i32, zext_bin_rmw_16_32<rmw_16>, regPlusImm, inst16_32>;
565 def : BinRMWPatImmOff<i64, zext_bin_rmw_8_64<rmw_8>, regPlusImm, inst8_64>;
566 def : BinRMWPatImmOff<i64, zext_bin_rmw_16_64<rmw_16>, regPlusImm, inst16_64>;
567 def : BinRMWPatImmOff<i64, zext_bin_rmw_32_64<rmw_32>, regPlusImm, inst32_64>;
568 def : BinRMWPatImmOff<i32, zext_bin_rmw_8_32<rmw_8>, or_is_add, inst8_32>;
569 def : BinRMWPatImmOff<i32, zext_bin_rmw_16_32<rmw_16>, or_is_add, inst16_32>;
570 def : BinRMWPatImmOff<i64, zext_bin_rmw_8_64<rmw_8>, or_is_add, inst8_64>;
571 def : BinRMWPatImmOff<i64, zext_bin_rmw_16_64<rmw_16>, or_is_add, inst16_64>;
572 def : BinRMWPatImmOff<i64, zext_bin_rmw_32_64<rmw_32>, or_is_add, inst32_64>;
573
574 def : BinRMWPatImmOff<i32, sext_bin_rmw_8_32<rmw_8>, regPlusImm, inst8_32>;
575 def : BinRMWPatImmOff<i32, sext_bin_rmw_16_32<rmw_16>, regPlusImm, inst16_32>;
576 def : BinRMWPatImmOff<i64, sext_bin_rmw_8_64<rmw_8>, regPlusImm, inst8_64>;
577 def : BinRMWPatImmOff<i64, sext_bin_rmw_16_64<rmw_16>, regPlusImm, inst16_64>;
578 def : BinRMWPatImmOff<i32, sext_bin_rmw_8_32<rmw_8>, or_is_add, inst8_32>;
579 def : BinRMWPatImmOff<i32, sext_bin_rmw_16_32<rmw_16>, or_is_add, inst16_32>;
580 def : BinRMWPatImmOff<i64, sext_bin_rmw_8_64<rmw_8>, or_is_add, inst8_64>;
581 def : BinRMWPatImmOff<i64, sext_bin_rmw_16_64<rmw_16>, or_is_add, inst16_64>;
582
583 def : BinRMWPatGlobalAddr<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
584 def : BinRMWPatGlobalAddr<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
585 def : BinRMWPatGlobalAddr<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
586 def : BinRMWPatGlobalAddr<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
587 def : BinRMWPatGlobalAddr<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
588
589 def : BinRMWPatGlobalAddr<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
590 def : BinRMWPatGlobalAddr<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
591 def : BinRMWPatGlobalAddr<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
592 def : BinRMWPatGlobalAddr<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
593
594 def : BinRMWPatExternalSym<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
595 def : BinRMWPatExternalSym<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
596 def : BinRMWPatExternalSym<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
597 def : BinRMWPatExternalSym<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
598 def : BinRMWPatExternalSym<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
599
600 def : BinRMWPatExternalSym<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
601 def : BinRMWPatExternalSym<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
602 def : BinRMWPatExternalSym<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
603 def : BinRMWPatExternalSym<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
604
605 // Truncating-extending binary RMWs with just a constant offset
606 def : BinRMWPatOffsetOnly<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
607 def : BinRMWPatOffsetOnly<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
608 def : BinRMWPatOffsetOnly<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
609 def : BinRMWPatOffsetOnly<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
610 def : BinRMWPatOffsetOnly<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
611
612 def : BinRMWPatOffsetOnly<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
613 def : BinRMWPatOffsetOnly<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
614 def : BinRMWPatOffsetOnly<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
615 def : BinRMWPatOffsetOnly<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
616
617 def : BinRMWPatGlobalAddrOffOnly<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
618 def : BinRMWPatGlobalAddrOffOnly<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
619 def : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
620 def : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
621 def : BinRMWPatGlobalAddrOffOnly<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
622
623 def : BinRMWPatGlobalAddrOffOnly<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
624 def : BinRMWPatGlobalAddrOffOnly<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
625 def : BinRMWPatGlobalAddrOffOnly<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
626 def : BinRMWPatGlobalAddrOffOnly<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
627
628 def : BinRMWPatExternSymOffOnly<i32, zext_bin_rmw_8_32<rmw_8>, inst8_32>;
629 def : BinRMWPatExternSymOffOnly<i32, zext_bin_rmw_16_32<rmw_16>, inst16_32>;
630 def : BinRMWPatExternSymOffOnly<i64, zext_bin_rmw_8_64<rmw_8>, inst8_64>;
631 def : BinRMWPatExternSymOffOnly<i64, zext_bin_rmw_16_64<rmw_16>, inst16_64>;
632 def : BinRMWPatExternSymOffOnly<i64, zext_bin_rmw_32_64<rmw_32>, inst32_64>;
633
634 def : BinRMWPatExternSymOffOnly<i32, sext_bin_rmw_8_32<rmw_8>, inst8_32>;
635 def : BinRMWPatExternSymOffOnly<i32, sext_bin_rmw_16_32<rmw_16>, inst16_32>;
636 def : BinRMWPatExternSymOffOnly<i64, sext_bin_rmw_8_64<rmw_8>, inst8_64>;
637 def : BinRMWPatExternSymOffOnly<i64, sext_bin_rmw_16_64<rmw_16>, inst16_64>;
638}
639
640let Predicates = [HasAtomics] in {
641defm : BinRMWTruncExtPattern<
642 atomic_load_add_8, atomic_load_add_16, atomic_load_add_32, atomic_load_add_64,
643 ATOMIC_RMW8_U_ADD_I32, ATOMIC_RMW16_U_ADD_I32,
644 ATOMIC_RMW8_U_ADD_I64, ATOMIC_RMW16_U_ADD_I64, ATOMIC_RMW32_U_ADD_I64>;
645defm : BinRMWTruncExtPattern<
646 atomic_load_sub_8, atomic_load_sub_16, atomic_load_sub_32, atomic_load_sub_64,
647 ATOMIC_RMW8_U_SUB_I32, ATOMIC_RMW16_U_SUB_I32,
648 ATOMIC_RMW8_U_SUB_I64, ATOMIC_RMW16_U_SUB_I64, ATOMIC_RMW32_U_SUB_I64>;
649defm : BinRMWTruncExtPattern<
650 atomic_load_and_8, atomic_load_and_16, atomic_load_and_32, atomic_load_and_64,
651 ATOMIC_RMW8_U_AND_I32, ATOMIC_RMW16_U_AND_I32,
652 ATOMIC_RMW8_U_AND_I64, ATOMIC_RMW16_U_AND_I64, ATOMIC_RMW32_U_AND_I64>;
653defm : BinRMWTruncExtPattern<
654 atomic_load_or_8, atomic_load_or_16, atomic_load_or_32, atomic_load_or_64,
655 ATOMIC_RMW8_U_OR_I32, ATOMIC_RMW16_U_OR_I32,
656 ATOMIC_RMW8_U_OR_I64, ATOMIC_RMW16_U_OR_I64, ATOMIC_RMW32_U_OR_I64>;
657defm : BinRMWTruncExtPattern<
658 atomic_load_xor_8, atomic_load_xor_16, atomic_load_xor_32, atomic_load_xor_64,
659 ATOMIC_RMW8_U_XOR_I32, ATOMIC_RMW16_U_XOR_I32,
660 ATOMIC_RMW8_U_XOR_I64, ATOMIC_RMW16_U_XOR_I64, ATOMIC_RMW32_U_XOR_I64>;
661defm : BinRMWTruncExtPattern<
662 atomic_swap_8, atomic_swap_16, atomic_swap_32, atomic_swap_64,
663 ATOMIC_RMW8_U_XCHG_I32, ATOMIC_RMW16_U_XCHG_I32,
664 ATOMIC_RMW8_U_XCHG_I64, ATOMIC_RMW16_U_XCHG_I64, ATOMIC_RMW32_U_XCHG_I64>;
665} // Predicates = [HasAtomics]
Heejin Ahnb3724b72018-08-01 19:40:28 +0000666
667//===----------------------------------------------------------------------===//
668// Atomic ternary read-modify-writes
669//===----------------------------------------------------------------------===//
670
Heejin Ahne8653bb2018-08-07 00:22:22 +0000671// TODO LLVM IR's cmpxchg instruction returns a pair of {loaded value, success
672// flag}. When we use the success flag or both values, we can't make use of i64
673// truncate/extend versions of instructions for now, which is suboptimal.
674// Consider adding a pass after instruction selection that optimizes this case
675// if it is frequent.
Heejin Ahnb3724b72018-08-01 19:40:28 +0000676
677let Defs = [ARGUMENTS] in {
678
679multiclass WebAssemblyTerRMW<WebAssemblyRegClass rc, string Name, int Opcode> {
680 defm "" : I<(outs rc:$dst),
681 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$exp,
682 rc:$new),
683 (outs), (ins P2Align:$p2align, offset32_op:$off), [],
684 !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}, $exp, $new"),
685 !strconcat(Name, "\t${off}, ${p2align}"), Opcode>;
686}
687
688defm ATOMIC_RMW_CMPXCHG_I32 :
689 WebAssemblyTerRMW<I32, "i32.atomic.rmw.cmpxchg", 0xfe48>;
690defm ATOMIC_RMW_CMPXCHG_I64 :
691 WebAssemblyTerRMW<I64, "i64.atomic.rmw.cmpxchg", 0xfe49>;
692defm ATOMIC_RMW8_U_CMPXCHG_I32 :
693 WebAssemblyTerRMW<I32, "i32.atomic.rmw8_u.cmpxchg", 0xfe4a>;
694defm ATOMIC_RMW16_U_CMPXCHG_I32 :
695 WebAssemblyTerRMW<I32, "i32.atomic.rmw16_u.cmpxchg", 0xfe4b>;
696defm ATOMIC_RMW8_U_CMPXCHG_I64 :
697 WebAssemblyTerRMW<I64, "i64.atomic.rmw8_u.cmpxchg", 0xfe4c>;
698defm ATOMIC_RMW16_U_CMPXCHG_I64 :
699 WebAssemblyTerRMW<I64, "i64.atomic.rmw16_u.cmpxchg", 0xfe4d>;
700defm ATOMIC_RMW32_U_CMPXCHG_I64 :
701 WebAssemblyTerRMW<I64, "i64.atomic.rmw32_u.cmpxchg", 0xfe4e>;
702}
703
704// Select ternary RMWs with no constant offset.
705class TerRMWPatNoOffset<ValueType ty, PatFrag kind, NI inst> :
706 Pat<(ty (kind I32:$addr, ty:$exp, ty:$new)),
707 (inst 0, 0, I32:$addr, ty:$exp, ty:$new)>;
708
709// Select ternary RMWs with a constant offset.
710
711// Pattern with address + immediate offset
712class TerRMWPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
713 Pat<(ty (kind (operand I32:$addr, imm:$off), ty:$exp, ty:$new)),
714 (inst 0, imm:$off, I32:$addr, ty:$exp, ty:$new)>;
715
716class TerRMWPatGlobalAddr<ValueType ty, PatFrag kind, NI inst> :
717 Pat<(ty (kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)),
718 ty:$exp, ty:$new)),
719 (inst 0, tglobaladdr:$off, I32:$addr, ty:$exp, ty:$new)>;
720
721class TerRMWPatExternalSym<ValueType ty, PatFrag kind, NI inst> :
722 Pat<(ty (kind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)),
723 ty:$exp, ty:$new)),
724 (inst 0, texternalsym:$off, I32:$addr, ty:$exp, ty:$new)>;
725
726// Select ternary RMWs with just a constant offset.
727class TerRMWPatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
728 Pat<(ty (kind imm:$off, ty:$exp, ty:$new)),
729 (inst 0, imm:$off, (CONST_I32 0), ty:$exp, ty:$new)>;
730
731class TerRMWPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
732 Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off), ty:$exp, ty:$new)),
733 (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$exp, ty:$new)>;
734
735class TerRMWPatExternSymOffOnly<ValueType ty, PatFrag kind, NI inst> :
736 Pat<(ty (kind (WebAssemblywrapper texternalsym:$off), ty:$exp, ty:$new)),
737 (inst 0, texternalsym:$off, (CONST_I32 0), ty:$exp, ty:$new)>;
738
739// Patterns for various addressing modes.
740multiclass TerRMWPattern<PatFrag rmw_32, PatFrag rmw_64, NI inst_32,
741 NI inst_64> {
742 def : TerRMWPatNoOffset<i32, rmw_32, inst_32>;
743 def : TerRMWPatNoOffset<i64, rmw_64, inst_64>;
744
745 def : TerRMWPatImmOff<i32, rmw_32, regPlusImm, inst_32>;
746 def : TerRMWPatImmOff<i64, rmw_64, regPlusImm, inst_64>;
747 def : TerRMWPatImmOff<i32, rmw_32, or_is_add, inst_32>;
748 def : TerRMWPatImmOff<i64, rmw_64, or_is_add, inst_64>;
749
750 def : TerRMWPatGlobalAddr<i32, rmw_32, inst_32>;
751 def : TerRMWPatGlobalAddr<i64, rmw_64, inst_64>;
752
753 def : TerRMWPatExternalSym<i32, rmw_32, inst_32>;
754 def : TerRMWPatExternalSym<i64, rmw_64, inst_64>;
755
756 def : TerRMWPatOffsetOnly<i32, rmw_32, inst_32>;
757 def : TerRMWPatOffsetOnly<i64, rmw_64, inst_64>;
758
759 def : TerRMWPatGlobalAddrOffOnly<i32, rmw_32, inst_32>;
760 def : TerRMWPatGlobalAddrOffOnly<i64, rmw_64, inst_64>;
761
762 def : TerRMWPatExternSymOffOnly<i32, rmw_32, inst_32>;
763 def : TerRMWPatExternSymOffOnly<i64, rmw_64, inst_64>;
764}
765
766let Predicates = [HasAtomics] in {
767defm : TerRMWPattern<atomic_cmp_swap_32, atomic_cmp_swap_64,
768 ATOMIC_RMW_CMPXCHG_I32, ATOMIC_RMW_CMPXCHG_I64>;
769} // Predicates = [HasAtomics]
770
771// Truncating & zero-extending ternary RMW patterns.
772// DAG legalization & optimization before instruction selection may introduce
773// additional nodes such as anyext or assertzext depending on operand types.
774class zext_ter_rmw_8_32<PatFrag kind> :
775 PatFrag<(ops node:$addr, node:$exp, node:$new),
776 (and (i32 (kind node:$addr, node:$exp, node:$new)), 255)>;
777class zext_ter_rmw_16_32<PatFrag kind> :
778 PatFrag<(ops node:$addr, node:$exp, node:$new),
779 (and (i32 (kind node:$addr, node:$exp, node:$new)), 65535)>;
780class zext_ter_rmw_8_64<PatFrag kind> :
781 PatFrag<(ops node:$addr, node:$exp, node:$new),
782 (zext (i32 (assertzext (i32 (kind node:$addr,
783 (i32 (trunc (i64 node:$exp))),
784 (i32 (trunc (i64 node:$new))))))))>;
785class zext_ter_rmw_16_64<PatFrag kind> : zext_ter_rmw_8_64<kind>;
786class zext_ter_rmw_32_64<PatFrag kind> :
787 PatFrag<(ops node:$addr, node:$exp, node:$new),
788 (zext (i32 (kind node:$addr,
789 (i32 (trunc (i64 node:$exp))),
790 (i32 (trunc (i64 node:$new))))))>;
791
792// Truncating & sign-extending ternary RMW patterns.
793// We match subword RMWs (for 32-bit) and anyext RMWs (for 64-bit) and select a
794// zext RMW; the next instruction will be sext_inreg which is selected by
795// itself.
796class sext_ter_rmw_8_32<PatFrag kind> :
797 PatFrag<(ops node:$addr, node:$exp, node:$new),
798 (kind node:$addr, node:$exp, node:$new)>;
799class sext_ter_rmw_16_32<PatFrag kind> : sext_ter_rmw_8_32<kind>;
800class sext_ter_rmw_8_64<PatFrag kind> :
801 PatFrag<(ops node:$addr, node:$exp, node:$new),
802 (anyext (i32 (assertzext (i32
803 (kind node:$addr,
804 (i32 (trunc (i64 node:$exp))),
805 (i32 (trunc (i64 node:$new))))))))>;
806class sext_ter_rmw_16_64<PatFrag kind> : sext_ter_rmw_8_64<kind>;
807// 32->64 sext RMW gets selected as i32.atomic.rmw.***, i64.extend_s/i32
808
809// Patterns for various addressing modes for truncating-extending ternary RMWs.
810multiclass TerRMWTruncExtPattern<
811 PatFrag rmw_8, PatFrag rmw_16, PatFrag rmw_32, PatFrag rmw_64,
812 NI inst8_32, NI inst16_32, NI inst8_64, NI inst16_64, NI inst32_64> {
813 // Truncating-extending ternary RMWs with no constant offset
814 def : TerRMWPatNoOffset<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>;
815 def : TerRMWPatNoOffset<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>;
816 def : TerRMWPatNoOffset<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>;
817 def : TerRMWPatNoOffset<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>;
818 def : TerRMWPatNoOffset<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>;
819
820 def : TerRMWPatNoOffset<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>;
821 def : TerRMWPatNoOffset<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>;
822 def : TerRMWPatNoOffset<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>;
823 def : TerRMWPatNoOffset<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>;
824
825 // Truncating-extending ternary RMWs with a constant offset
826 def : TerRMWPatImmOff<i32, zext_ter_rmw_8_32<rmw_8>, regPlusImm, inst8_32>;
827 def : TerRMWPatImmOff<i32, zext_ter_rmw_16_32<rmw_16>, regPlusImm, inst16_32>;
828 def : TerRMWPatImmOff<i64, zext_ter_rmw_8_64<rmw_8>, regPlusImm, inst8_64>;
829 def : TerRMWPatImmOff<i64, zext_ter_rmw_16_64<rmw_16>, regPlusImm, inst16_64>;
830 def : TerRMWPatImmOff<i64, zext_ter_rmw_32_64<rmw_32>, regPlusImm, inst32_64>;
831 def : TerRMWPatImmOff<i32, zext_ter_rmw_8_32<rmw_8>, or_is_add, inst8_32>;
832 def : TerRMWPatImmOff<i32, zext_ter_rmw_16_32<rmw_16>, or_is_add, inst16_32>;
833 def : TerRMWPatImmOff<i64, zext_ter_rmw_8_64<rmw_8>, or_is_add, inst8_64>;
834 def : TerRMWPatImmOff<i64, zext_ter_rmw_16_64<rmw_16>, or_is_add, inst16_64>;
835 def : TerRMWPatImmOff<i64, zext_ter_rmw_32_64<rmw_32>, or_is_add, inst32_64>;
836
837 def : TerRMWPatImmOff<i32, sext_ter_rmw_8_32<rmw_8>, regPlusImm, inst8_32>;
838 def : TerRMWPatImmOff<i32, sext_ter_rmw_16_32<rmw_16>, regPlusImm, inst16_32>;
839 def : TerRMWPatImmOff<i64, sext_ter_rmw_8_64<rmw_8>, regPlusImm, inst8_64>;
840 def : TerRMWPatImmOff<i64, sext_ter_rmw_16_64<rmw_16>, regPlusImm, inst16_64>;
841 def : TerRMWPatImmOff<i32, sext_ter_rmw_8_32<rmw_8>, or_is_add, inst8_32>;
842 def : TerRMWPatImmOff<i32, sext_ter_rmw_16_32<rmw_16>, or_is_add, inst16_32>;
843 def : TerRMWPatImmOff<i64, sext_ter_rmw_8_64<rmw_8>, or_is_add, inst8_64>;
844 def : TerRMWPatImmOff<i64, sext_ter_rmw_16_64<rmw_16>, or_is_add, inst16_64>;
845
846 def : TerRMWPatGlobalAddr<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>;
847 def : TerRMWPatGlobalAddr<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>;
848 def : TerRMWPatGlobalAddr<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>;
849 def : TerRMWPatGlobalAddr<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>;
850 def : TerRMWPatGlobalAddr<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>;
851
852 def : TerRMWPatGlobalAddr<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>;
853 def : TerRMWPatGlobalAddr<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>;
854 def : TerRMWPatGlobalAddr<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>;
855 def : TerRMWPatGlobalAddr<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>;
856
857 def : TerRMWPatExternalSym<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>;
858 def : TerRMWPatExternalSym<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>;
859 def : TerRMWPatExternalSym<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>;
860 def : TerRMWPatExternalSym<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>;
861 def : TerRMWPatExternalSym<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>;
862
863 def : TerRMWPatExternalSym<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>;
864 def : TerRMWPatExternalSym<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>;
865 def : TerRMWPatExternalSym<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>;
866 def : TerRMWPatExternalSym<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>;
867
868 // Truncating-extending ternary RMWs with just a constant offset
869 def : TerRMWPatOffsetOnly<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>;
870 def : TerRMWPatOffsetOnly<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>;
871 def : TerRMWPatOffsetOnly<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>;
872 def : TerRMWPatOffsetOnly<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>;
873 def : TerRMWPatOffsetOnly<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>;
874
875 def : TerRMWPatOffsetOnly<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>;
876 def : TerRMWPatOffsetOnly<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>;
877 def : TerRMWPatOffsetOnly<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>;
878 def : TerRMWPatOffsetOnly<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>;
879
880 def : TerRMWPatGlobalAddrOffOnly<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>;
881 def : TerRMWPatGlobalAddrOffOnly<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>;
882 def : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>;
883 def : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>;
884 def : TerRMWPatGlobalAddrOffOnly<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>;
885
886 def : TerRMWPatGlobalAddrOffOnly<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>;
887 def : TerRMWPatGlobalAddrOffOnly<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>;
888 def : TerRMWPatGlobalAddrOffOnly<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>;
889 def : TerRMWPatGlobalAddrOffOnly<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>;
890
891 def : TerRMWPatExternSymOffOnly<i32, zext_ter_rmw_8_32<rmw_8>, inst8_32>;
892 def : TerRMWPatExternSymOffOnly<i32, zext_ter_rmw_16_32<rmw_16>, inst16_32>;
893 def : TerRMWPatExternSymOffOnly<i64, zext_ter_rmw_8_64<rmw_8>, inst8_64>;
894 def : TerRMWPatExternSymOffOnly<i64, zext_ter_rmw_16_64<rmw_16>, inst16_64>;
895 def : TerRMWPatExternSymOffOnly<i64, zext_ter_rmw_32_64<rmw_32>, inst32_64>;
896
897 def : TerRMWPatExternSymOffOnly<i32, sext_ter_rmw_8_32<rmw_8>, inst8_32>;
898 def : TerRMWPatExternSymOffOnly<i32, sext_ter_rmw_16_32<rmw_16>, inst16_32>;
899 def : TerRMWPatExternSymOffOnly<i64, sext_ter_rmw_8_64<rmw_8>, inst8_64>;
900 def : TerRMWPatExternSymOffOnly<i64, sext_ter_rmw_16_64<rmw_16>, inst16_64>;
901}
902
903let Predicates = [HasAtomics] in {
904defm : TerRMWTruncExtPattern<
905 atomic_cmp_swap_8, atomic_cmp_swap_16, atomic_cmp_swap_32, atomic_cmp_swap_64,
906 ATOMIC_RMW8_U_CMPXCHG_I32, ATOMIC_RMW16_U_CMPXCHG_I32,
907 ATOMIC_RMW8_U_CMPXCHG_I64, ATOMIC_RMW16_U_CMPXCHG_I64,
908 ATOMIC_RMW32_U_CMPXCHG_I64>;
Heejin Ahn4128cb02018-08-02 21:44:24 +0000909}
910
911//===----------------------------------------------------------------------===//
912// Atomic wait / notify
913//===----------------------------------------------------------------------===//
914
915let Defs = [ARGUMENTS] in {
916let hasSideEffects = 1 in {
917defm ATOMIC_NOTIFY :
Heejin Ahn487992c2018-08-20 23:49:29 +0000918 I<(outs I32:$dst),
919 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$count),
Heejin Ahn4128cb02018-08-02 21:44:24 +0000920 (outs), (ins P2Align:$p2align, offset32_op:$off), [],
921 "atomic.notify \t$dst, ${off}(${addr})${p2align}, $count",
922 "atomic.notify \t${off}, ${p2align}", 0xfe00>;
923let mayLoad = 1 in {
924defm ATOMIC_WAIT_I32 :
925 I<(outs I32:$dst),
926 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I32:$exp, I64:$timeout),
927 (outs), (ins P2Align:$p2align, offset32_op:$off), [],
928 "i32.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
929 "i32.atomic.wait \t${off}, ${p2align}", 0xfe01>;
930defm ATOMIC_WAIT_I64 :
931 I<(outs I32:$dst),
932 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, I64:$exp, I64:$timeout),
933 (outs), (ins P2Align:$p2align, offset32_op:$off), [],
934 "i64.atomic.wait \t$dst, ${off}(${addr})${p2align}, $exp, $timeout",
935 "i64.atomic.wait \t${off}, ${p2align}", 0xfe02>;
936} // mayLoad = 1
937} // hasSideEffects = 1
938} // Defs = [ARGUMENTS]
939
940let Predicates = [HasAtomics] in {
941// Select notifys with no constant offset.
942class NotifyPatNoOffset<Intrinsic kind> :
Heejin Ahn487992c2018-08-20 23:49:29 +0000943 Pat<(i32 (kind I32:$addr, I32:$count)),
944 (ATOMIC_NOTIFY 0, 0, I32:$addr, I32:$count)>;
Heejin Ahn4128cb02018-08-02 21:44:24 +0000945def : NotifyPatNoOffset<int_wasm_atomic_notify>;
946
947// Select notifys with a constant offset.
948
949// Pattern with address + immediate offset
950class NotifyPatImmOff<Intrinsic kind, PatFrag operand> :
Heejin Ahn487992c2018-08-20 23:49:29 +0000951 Pat<(i32 (kind (operand I32:$addr, imm:$off), I32:$count)),
952 (ATOMIC_NOTIFY 0, imm:$off, I32:$addr, I32:$count)>;
Heejin Ahn4128cb02018-08-02 21:44:24 +0000953def : NotifyPatImmOff<int_wasm_atomic_notify, regPlusImm>;
954def : NotifyPatImmOff<int_wasm_atomic_notify, or_is_add>;
955
956class NotifyPatGlobalAddr<Intrinsic kind> :
Heejin Ahn487992c2018-08-20 23:49:29 +0000957 Pat<(i32 (kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)),
958 I32:$count)),
959 (ATOMIC_NOTIFY 0, tglobaladdr:$off, I32:$addr, I32:$count)>;
Heejin Ahn4128cb02018-08-02 21:44:24 +0000960def : NotifyPatGlobalAddr<int_wasm_atomic_notify>;
961
962class NotifyPatExternalSym<Intrinsic kind> :
Heejin Ahn487992c2018-08-20 23:49:29 +0000963 Pat<(i32 (kind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)),
964 I32:$count)),
965 (ATOMIC_NOTIFY 0, texternalsym:$off, I32:$addr, I32:$count)>;
Heejin Ahn4128cb02018-08-02 21:44:24 +0000966def : NotifyPatExternalSym<int_wasm_atomic_notify>;
967
968// Select notifys with just a constant offset.
969class NotifyPatOffsetOnly<Intrinsic kind> :
Heejin Ahn487992c2018-08-20 23:49:29 +0000970 Pat<(i32 (kind imm:$off, I32:$count)),
971 (ATOMIC_NOTIFY 0, imm:$off, (CONST_I32 0), I32:$count)>;
Heejin Ahn4128cb02018-08-02 21:44:24 +0000972def : NotifyPatOffsetOnly<int_wasm_atomic_notify>;
973
974class NotifyPatGlobalAddrOffOnly<Intrinsic kind> :
Heejin Ahn487992c2018-08-20 23:49:29 +0000975 Pat<(i32 (kind (WebAssemblywrapper tglobaladdr:$off), I32:$count)),
976 (ATOMIC_NOTIFY 0, tglobaladdr:$off, (CONST_I32 0), I32:$count)>;
Heejin Ahn4128cb02018-08-02 21:44:24 +0000977def : NotifyPatGlobalAddrOffOnly<int_wasm_atomic_notify>;
978
979class NotifyPatExternSymOffOnly<Intrinsic kind> :
Heejin Ahn487992c2018-08-20 23:49:29 +0000980 Pat<(i32 (kind (WebAssemblywrapper texternalsym:$off), I32:$count)),
981 (ATOMIC_NOTIFY 0, texternalsym:$off, (CONST_I32 0), I32:$count)>;
Heejin Ahn4128cb02018-08-02 21:44:24 +0000982def : NotifyPatExternSymOffOnly<int_wasm_atomic_notify>;
983
984// Select waits with no constant offset.
985class WaitPatNoOffset<ValueType ty, Intrinsic kind, NI inst> :
986 Pat<(i32 (kind I32:$addr, ty:$exp, I64:$timeout)),
987 (inst 0, 0, I32:$addr, ty:$exp, I64:$timeout)>;
988def : WaitPatNoOffset<i32, int_wasm_atomic_wait_i32, ATOMIC_WAIT_I32>;
989def : WaitPatNoOffset<i64, int_wasm_atomic_wait_i64, ATOMIC_WAIT_I64>;
990
991// Select waits with a constant offset.
992
993// Pattern with address + immediate offset
994class WaitPatImmOff<ValueType ty, Intrinsic kind, PatFrag operand, NI inst> :
995 Pat<(i32 (kind (operand I32:$addr, imm:$off), ty:$exp, I64:$timeout)),
996 (inst 0, imm:$off, I32:$addr, ty:$exp, I64:$timeout)>;
997def : WaitPatImmOff<i32, int_wasm_atomic_wait_i32, regPlusImm, ATOMIC_WAIT_I32>;
998def : WaitPatImmOff<i32, int_wasm_atomic_wait_i32, or_is_add, ATOMIC_WAIT_I32>;
999def : WaitPatImmOff<i64, int_wasm_atomic_wait_i64, regPlusImm, ATOMIC_WAIT_I64>;
1000def : WaitPatImmOff<i64, int_wasm_atomic_wait_i64, or_is_add, ATOMIC_WAIT_I64>;
1001
1002class WaitPatGlobalAddr<ValueType ty, Intrinsic kind, NI inst> :
1003 Pat<(i32 (kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)),
1004 ty:$exp, I64:$timeout)),
1005 (inst 0, tglobaladdr:$off, I32:$addr, ty:$exp, I64:$timeout)>;
1006def : WaitPatGlobalAddr<i32, int_wasm_atomic_wait_i32, ATOMIC_WAIT_I32>;
1007def : WaitPatGlobalAddr<i64, int_wasm_atomic_wait_i64, ATOMIC_WAIT_I64>;
1008
1009class WaitPatExternalSym<ValueType ty, Intrinsic kind, NI inst> :
1010 Pat<(i32 (kind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)),
1011 ty:$exp, I64:$timeout)),
1012 (inst 0, texternalsym:$off, I32:$addr, ty:$exp, I64:$timeout)>;
1013def : WaitPatExternalSym<i32, int_wasm_atomic_wait_i32, ATOMIC_WAIT_I32>;
1014def : WaitPatExternalSym<i64, int_wasm_atomic_wait_i64, ATOMIC_WAIT_I64>;
1015
1016// Select wait_i32, ATOMIC_WAIT_I32s with just a constant offset.
1017class WaitPatOffsetOnly<ValueType ty, Intrinsic kind, NI inst> :
1018 Pat<(i32 (kind imm:$off, ty:$exp, I64:$timeout)),
1019 (inst 0, imm:$off, (CONST_I32 0), ty:$exp, I64:$timeout)>;
1020def : WaitPatOffsetOnly<i32, int_wasm_atomic_wait_i32, ATOMIC_WAIT_I32>;
1021def : WaitPatOffsetOnly<i64, int_wasm_atomic_wait_i64, ATOMIC_WAIT_I64>;
1022
1023class WaitPatGlobalAddrOffOnly<ValueType ty, Intrinsic kind, NI inst> :
1024 Pat<(i32 (kind (WebAssemblywrapper tglobaladdr:$off), ty:$exp, I64:$timeout)),
1025 (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$exp, I64:$timeout)>;
1026def : WaitPatGlobalAddrOffOnly<i32, int_wasm_atomic_wait_i32, ATOMIC_WAIT_I32>;
1027def : WaitPatGlobalAddrOffOnly<i64, int_wasm_atomic_wait_i64, ATOMIC_WAIT_I64>;
1028
1029class WaitPatExternSymOffOnly<ValueType ty, Intrinsic kind, NI inst> :
1030 Pat<(i32 (kind (WebAssemblywrapper texternalsym:$off), ty:$exp,
1031 I64:$timeout)),
1032 (inst 0, texternalsym:$off, (CONST_I32 0), ty:$exp, I64:$timeout)>;
1033def : WaitPatExternSymOffOnly<i32, int_wasm_atomic_wait_i32, ATOMIC_WAIT_I32>;
1034def : WaitPatExternSymOffOnly<i64, int_wasm_atomic_wait_i64, ATOMIC_WAIT_I64>;
Heejin Ahnb3724b72018-08-01 19:40:28 +00001035} // Predicates = [HasAtomics]