1// WebAssemblyInstrMemory.td-WebAssembly Memory 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//===----------------------------------------------------------------------===//
9///
10/// \file
11/// WebAssembly Memory operand code-gen constructs.
12///
13//===----------------------------------------------------------------------===//
14
15// TODO:
16//  - HasAddr64
17//  - WebAssemblyTargetLowering having to do with atomics
18//  - Each has optional alignment.
19
20// WebAssembly has i8/i16/i32/i64/f32/f64 memory types, but doesn't have i8/i16
21// local types. These memory-only types instead zero- or sign-extend into local
22// types when loading, and truncate when storing.
23
24// WebAssembly constant offsets are performed as unsigned with infinite
25// precision, so we need to check for NoUnsignedWrap so that we don't fold an
26// offset for an add that needs wrapping.
27def regPlusImm : PatFrag<(ops node:$addr, node:$off),
28                         (add node:$addr, node:$off),
29                         [{ return N->getFlags().hasNoUnsignedWrap(); }]>;
30
31// Treat an 'or' node as an 'add' if the or'ed bits are known to be zero.
32def or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{
33  if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))
34    return CurDAG->MaskedValueIsZero(N->getOperand(0), CN->getAPIntValue());
35
36  KnownBits Known0 = CurDAG->computeKnownBits(N->getOperand(0), 0);
37  KnownBits Known1 = CurDAG->computeKnownBits(N->getOperand(1), 0);
38  return (~Known0.Zero & ~Known1.Zero) == 0;
39}]>;
40
41// GlobalAddresses are conceptually unsigned values, so we can also fold them
42// into immediate values as long as the add is 'nuw'.
43// TODO: We'd like to also match GA offsets but there are cases where the
44// register can have a negative value. Find out what more we can do.
45def regPlusGA : PatFrag<(ops node:$addr, node:$off),
46                        (add node:$addr, node:$off),
47                        [{
48  return N->getFlags().hasNoUnsignedWrap();
49}]>;
50
51// We don't need a regPlusES because external symbols never have constant
52// offsets folded into them, so we can just use add.
53
54// Defines atomic and non-atomic loads, regular and extending.
55multiclass WebAssemblyLoad<WebAssemblyRegClass rc, string Name, int Opcode> {
56  let mayLoad = 1 in
57  defm "": I<(outs rc:$dst),
58             (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
59             (outs), (ins P2Align:$p2align, offset32_op:$off),
60             [], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"),
61             !strconcat(Name, "\t${off}${p2align}"), Opcode>;
62}
63
64// Basic load.
65// FIXME: When we can break syntax compatibility, reorder the fields in the
66// asmstrings to match the binary encoding.
67defm LOAD_I32 : WebAssemblyLoad<I32, "i32.load", 0x28>;
68defm LOAD_I64 : WebAssemblyLoad<I64, "i64.load", 0x29>;
69defm LOAD_F32 : WebAssemblyLoad<F32, "f32.load", 0x2a>;
70defm LOAD_F64 : WebAssemblyLoad<F64, "f64.load", 0x2b>;
71
72// Select loads with no constant offset.
73class LoadPatNoOffset<ValueType ty, PatFrag kind, NI inst> :
74  Pat<(ty (kind I32:$addr)), (inst 0, 0, I32:$addr)>;
75
76def : LoadPatNoOffset<i32, load, LOAD_I32>;
77def : LoadPatNoOffset<i64, load, LOAD_I64>;
78def : LoadPatNoOffset<f32, load, LOAD_F32>;
79def : LoadPatNoOffset<f64, load, LOAD_F64>;
80
81
82// Select loads with a constant offset.
83
84// Pattern with address + immediate offset
85class LoadPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
86  Pat<(ty (kind (operand I32:$addr, imm:$off))), (inst 0, imm:$off, I32:$addr)>;
87
88def : LoadPatImmOff<i32, load, regPlusImm, LOAD_I32>;
89def : LoadPatImmOff<i64, load, regPlusImm, LOAD_I64>;
90def : LoadPatImmOff<f32, load, regPlusImm, LOAD_F32>;
91def : LoadPatImmOff<f64, load, regPlusImm, LOAD_F64>;
92def : LoadPatImmOff<i32, load, or_is_add, LOAD_I32>;
93def : LoadPatImmOff<i64, load, or_is_add, LOAD_I64>;
94def : LoadPatImmOff<f32, load, or_is_add, LOAD_F32>;
95def : LoadPatImmOff<f64, load, or_is_add, LOAD_F64>;
96
97class LoadPatGlobalAddr<ValueType ty, PatFrag kind, NI inst> :
98  Pat<(ty (kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)))),
99      (inst 0, tglobaladdr:$off, I32:$addr)>;
100
101def : LoadPatGlobalAddr<i32, load, LOAD_I32>;
102def : LoadPatGlobalAddr<i64, load, LOAD_I64>;
103def : LoadPatGlobalAddr<f32, load, LOAD_F32>;
104def : LoadPatGlobalAddr<f64, load, LOAD_F64>;
105
106class LoadPatExternalSym<ValueType ty, PatFrag kind, NI inst> :
107  Pat<(ty (kind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))),
108      (inst 0, texternalsym:$off, I32:$addr)>;
109def : LoadPatExternalSym<i32, load, LOAD_I32>;
110def : LoadPatExternalSym<i64, load, LOAD_I64>;
111def : LoadPatExternalSym<f32, load, LOAD_F32>;
112def : LoadPatExternalSym<f64, load, LOAD_F64>;
113
114
115// Select loads with just a constant offset.
116class LoadPatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
117  Pat<(ty (kind imm:$off)), (inst 0, imm:$off, (CONST_I32 0))>;
118
119def : LoadPatOffsetOnly<i32, load, LOAD_I32>;
120def : LoadPatOffsetOnly<i64, load, LOAD_I64>;
121def : LoadPatOffsetOnly<f32, load, LOAD_F32>;
122def : LoadPatOffsetOnly<f64, load, LOAD_F64>;
123
124class LoadPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
125  Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off))),
126      (inst 0, tglobaladdr:$off, (CONST_I32 0))>;
127
128def : LoadPatGlobalAddrOffOnly<i32, load, LOAD_I32>;
129def : LoadPatGlobalAddrOffOnly<i64, load, LOAD_I64>;
130def : LoadPatGlobalAddrOffOnly<f32, load, LOAD_F32>;
131def : LoadPatGlobalAddrOffOnly<f64, load, LOAD_F64>;
132
133class LoadPatExternSymOffOnly<ValueType ty, PatFrag kind, NI inst> :
134  Pat<(ty (kind (WebAssemblywrapper texternalsym:$off))),
135      (inst 0, texternalsym:$off, (CONST_I32 0))>;
136def : LoadPatExternSymOffOnly<i32, load, LOAD_I32>;
137def : LoadPatExternSymOffOnly<i64, load, LOAD_I64>;
138def : LoadPatExternSymOffOnly<f32, load, LOAD_F32>;
139def : LoadPatExternSymOffOnly<f64, load, LOAD_F64>;
140
141// Extending load.
142defm LOAD8_S_I32 : WebAssemblyLoad<I32, "i32.load8_s", 0x2c>;
143defm LOAD8_U_I32 : WebAssemblyLoad<I32, "i32.load8_u", 0x2d>;
144defm LOAD16_S_I32 : WebAssemblyLoad<I32, "i32.load16_s", 0x2e>;
145defm LOAD16_U_I32 : WebAssemblyLoad<I32, "i32.load16_u", 0x2f>;
146defm LOAD8_S_I64 : WebAssemblyLoad<I64, "i64.load8_s", 0x30>;
147defm LOAD8_U_I64 : WebAssemblyLoad<I64, "i64.load8_u", 0x31>;
148defm LOAD16_S_I64 : WebAssemblyLoad<I64, "i64.load16_s", 0x32>;
149defm LOAD16_U_I64 : WebAssemblyLoad<I64, "i64.load16_u", 0x33>;
150defm LOAD32_S_I64 : WebAssemblyLoad<I64, "i64.load32_s", 0x34>;
151defm LOAD32_U_I64 : WebAssemblyLoad<I64, "i64.load32_u", 0x35>;
152
153// Select extending loads with no constant offset.
154def : LoadPatNoOffset<i32, sextloadi8, LOAD8_S_I32>;
155def : LoadPatNoOffset<i32, zextloadi8, LOAD8_U_I32>;
156def : LoadPatNoOffset<i32, sextloadi16, LOAD16_S_I32>;
157def : LoadPatNoOffset<i32, zextloadi16, LOAD16_U_I32>;
158def : LoadPatNoOffset<i64, sextloadi8, LOAD8_S_I64>;
159def : LoadPatNoOffset<i64, zextloadi8, LOAD8_U_I64>;
160def : LoadPatNoOffset<i64, sextloadi16, LOAD16_S_I64>;
161def : LoadPatNoOffset<i64, zextloadi16, LOAD16_U_I64>;
162def : LoadPatNoOffset<i64, sextloadi32, LOAD32_S_I64>;
163def : LoadPatNoOffset<i64, zextloadi32, LOAD32_U_I64>;
164
165// Select extending loads with a constant offset.
166def : LoadPatImmOff<i32, sextloadi8, regPlusImm, LOAD8_S_I32>;
167def : LoadPatImmOff<i32, zextloadi8, regPlusImm, LOAD8_U_I32>;
168def : LoadPatImmOff<i32, sextloadi16, regPlusImm, LOAD16_S_I32>;
169def : LoadPatImmOff<i32, zextloadi16, regPlusImm, LOAD16_U_I32>;
170def : LoadPatImmOff<i64, sextloadi8, regPlusImm, LOAD8_S_I64>;
171def : LoadPatImmOff<i64, zextloadi8, regPlusImm, LOAD8_U_I64>;
172def : LoadPatImmOff<i64, sextloadi16, regPlusImm, LOAD16_S_I64>;
173def : LoadPatImmOff<i64, zextloadi16, regPlusImm, LOAD16_U_I64>;
174def : LoadPatImmOff<i64, sextloadi32, regPlusImm, LOAD32_S_I64>;
175def : LoadPatImmOff<i64, zextloadi32, regPlusImm, LOAD32_U_I64>;
176
177def : LoadPatImmOff<i32, sextloadi8, or_is_add, LOAD8_S_I32>;
178def : LoadPatImmOff<i32, zextloadi8, or_is_add, LOAD8_U_I32>;
179def : LoadPatImmOff<i32, sextloadi16, or_is_add, LOAD16_S_I32>;
180def : LoadPatImmOff<i32, zextloadi16, or_is_add, LOAD16_U_I32>;
181def : LoadPatImmOff<i64, sextloadi8, or_is_add, LOAD8_S_I64>;
182def : LoadPatImmOff<i64, zextloadi8, or_is_add, LOAD8_U_I64>;
183def : LoadPatImmOff<i64, sextloadi16, or_is_add, LOAD16_S_I64>;
184def : LoadPatImmOff<i64, zextloadi16, or_is_add, LOAD16_U_I64>;
185def : LoadPatImmOff<i64, sextloadi32, or_is_add, LOAD32_S_I64>;
186def : LoadPatImmOff<i64, zextloadi32, or_is_add, LOAD32_U_I64>;
187
188def : LoadPatGlobalAddr<i32, sextloadi8, LOAD8_S_I32>;
189def : LoadPatGlobalAddr<i32, zextloadi8, LOAD8_U_I32>;
190def : LoadPatGlobalAddr<i32, sextloadi16, LOAD16_S_I32>;
191def : LoadPatGlobalAddr<i32, zextloadi8, LOAD16_U_I32>;
192
193def : LoadPatGlobalAddr<i64, sextloadi8, LOAD8_S_I64>;
194def : LoadPatGlobalAddr<i64, zextloadi8, LOAD8_U_I64>;
195def : LoadPatGlobalAddr<i64, sextloadi16, LOAD16_S_I64>;
196def : LoadPatGlobalAddr<i64, zextloadi16, LOAD16_U_I64>;
197def : LoadPatGlobalAddr<i64, sextloadi32, LOAD32_S_I64>;
198def : LoadPatGlobalAddr<i64, zextloadi32, LOAD32_U_I64>;
199
200def : LoadPatExternalSym<i32, sextloadi8, LOAD8_S_I32>;
201def : LoadPatExternalSym<i32, zextloadi8, LOAD8_U_I32>;
202def : LoadPatExternalSym<i32, sextloadi16, LOAD16_S_I32>;
203def : LoadPatExternalSym<i32, zextloadi16, LOAD16_U_I32>;
204def : LoadPatExternalSym<i64, sextloadi8, LOAD8_S_I64>;
205def : LoadPatExternalSym<i64, zextloadi8, LOAD8_U_I64>;
206def : LoadPatExternalSym<i64, sextloadi16, LOAD16_S_I64>;
207def : LoadPatExternalSym<i64, zextloadi16, LOAD16_U_I64>;
208def : LoadPatExternalSym<i64, sextloadi32, LOAD32_S_I64>;
209def : LoadPatExternalSym<i64, zextloadi32, LOAD32_U_I64>;
210
211
212// Select extending loads with just a constant offset.
213def : LoadPatOffsetOnly<i32, sextloadi8, LOAD8_S_I32>;
214def : LoadPatOffsetOnly<i32, zextloadi8, LOAD8_U_I32>;
215def : LoadPatOffsetOnly<i32, sextloadi16, LOAD16_S_I32>;
216def : LoadPatOffsetOnly<i32, zextloadi16, LOAD16_U_I32>;
217
218def : LoadPatOffsetOnly<i64, sextloadi8, LOAD8_S_I64>;
219def : LoadPatOffsetOnly<i64, zextloadi8, LOAD8_U_I64>;
220def : LoadPatOffsetOnly<i64, sextloadi16, LOAD16_S_I64>;
221def : LoadPatOffsetOnly<i64, zextloadi16, LOAD16_U_I64>;
222def : LoadPatOffsetOnly<i64, sextloadi32, LOAD32_S_I64>;
223def : LoadPatOffsetOnly<i64, zextloadi32, LOAD32_U_I64>;
224
225def : LoadPatGlobalAddrOffOnly<i32, sextloadi8, LOAD8_S_I32>;
226def : LoadPatGlobalAddrOffOnly<i32, zextloadi8, LOAD8_U_I32>;
227def : LoadPatGlobalAddrOffOnly<i32, sextloadi16, LOAD16_S_I32>;
228def : LoadPatGlobalAddrOffOnly<i32, zextloadi16, LOAD16_U_I32>;
229def : LoadPatGlobalAddrOffOnly<i64, sextloadi8, LOAD8_S_I64>;
230def : LoadPatGlobalAddrOffOnly<i64, zextloadi8, LOAD8_U_I64>;
231def : LoadPatGlobalAddrOffOnly<i64, sextloadi16, LOAD16_S_I64>;
232def : LoadPatGlobalAddrOffOnly<i64, zextloadi16, LOAD16_U_I64>;
233def : LoadPatGlobalAddrOffOnly<i64, sextloadi32, LOAD32_S_I64>;
234def : LoadPatGlobalAddrOffOnly<i64, zextloadi32, LOAD32_U_I64>;
235
236def : LoadPatExternSymOffOnly<i32, sextloadi8, LOAD8_S_I32>;
237def : LoadPatExternSymOffOnly<i32, zextloadi8, LOAD8_U_I32>;
238def : LoadPatExternSymOffOnly<i32, sextloadi16, LOAD16_S_I32>;
239def : LoadPatExternSymOffOnly<i32, zextloadi16, LOAD16_U_I32>;
240def : LoadPatExternSymOffOnly<i64, sextloadi8, LOAD8_S_I64>;
241def : LoadPatExternSymOffOnly<i64, zextloadi8, LOAD8_U_I64>;
242def : LoadPatExternSymOffOnly<i64, sextloadi16, LOAD16_S_I64>;
243def : LoadPatExternSymOffOnly<i64, zextloadi16, LOAD16_U_I64>;
244def : LoadPatExternSymOffOnly<i64, sextloadi32, LOAD32_S_I64>;
245def : LoadPatExternSymOffOnly<i64, zextloadi32, LOAD32_U_I64>;
246
247// Resolve "don't care" extending loads to zero-extending loads. This is
248// somewhat arbitrary, but zero-extending is conceptually simpler.
249
250// Select "don't care" extending loads with no constant offset.
251def : LoadPatNoOffset<i32, extloadi8, LOAD8_U_I32>;
252def : LoadPatNoOffset<i32, extloadi16, LOAD16_U_I32>;
253def : LoadPatNoOffset<i64, extloadi8, LOAD8_U_I64>;
254def : LoadPatNoOffset<i64, extloadi16, LOAD16_U_I64>;
255def : LoadPatNoOffset<i64, extloadi32, LOAD32_U_I64>;
256
257// Select "don't care" extending loads with a constant offset.
258def : LoadPatImmOff<i32, extloadi8, regPlusImm, LOAD8_U_I32>;
259def : LoadPatImmOff<i32, extloadi16, regPlusImm, LOAD16_U_I32>;
260def : LoadPatImmOff<i64, extloadi8, regPlusImm, LOAD8_U_I64>;
261def : LoadPatImmOff<i64, extloadi16, regPlusImm, LOAD16_U_I64>;
262def : LoadPatImmOff<i64, extloadi32, regPlusImm, LOAD32_U_I64>;
263def : LoadPatImmOff<i32, extloadi8, or_is_add, LOAD8_U_I32>;
264def : LoadPatImmOff<i32, extloadi16, or_is_add, LOAD16_U_I32>;
265def : LoadPatImmOff<i64, extloadi8, or_is_add, LOAD8_U_I64>;
266def : LoadPatImmOff<i64, extloadi16, or_is_add, LOAD16_U_I64>;
267def : LoadPatImmOff<i64, extloadi32, or_is_add, LOAD32_U_I64>;
268def : LoadPatGlobalAddr<i32, extloadi8, LOAD8_U_I32>;
269def : LoadPatGlobalAddr<i32, extloadi16, LOAD16_U_I32>;
270def : LoadPatGlobalAddr<i64, extloadi8, LOAD8_U_I64>;
271def : LoadPatGlobalAddr<i64, extloadi16, LOAD16_U_I64>;
272def : LoadPatGlobalAddr<i64, extloadi32, LOAD32_U_I64>;
273def : LoadPatExternalSym<i32, extloadi8, LOAD8_U_I32>;
274def : LoadPatExternalSym<i32, extloadi16, LOAD16_U_I32>;
275def : LoadPatExternalSym<i64, extloadi8, LOAD8_U_I64>;
276def : LoadPatExternalSym<i64, extloadi16, LOAD16_U_I64>;
277def : LoadPatExternalSym<i64, extloadi32, LOAD32_U_I64>;
278
279// Select "don't care" extending loads with just a constant offset.
280def : LoadPatOffsetOnly<i32, extloadi8, LOAD8_U_I32>;
281def : LoadPatOffsetOnly<i32, extloadi16, LOAD16_U_I32>;
282def : LoadPatOffsetOnly<i64, extloadi8, LOAD8_U_I64>;
283def : LoadPatOffsetOnly<i64, extloadi16, LOAD16_U_I64>;
284def : LoadPatOffsetOnly<i64, extloadi32, LOAD32_U_I64>;
285def : LoadPatGlobalAddrOffOnly<i32, extloadi8, LOAD8_U_I32>;
286def : LoadPatGlobalAddrOffOnly<i32, extloadi16, LOAD16_U_I32>;
287def : LoadPatGlobalAddrOffOnly<i64, extloadi8, LOAD8_U_I64>;
288def : LoadPatGlobalAddrOffOnly<i64, extloadi16, LOAD16_U_I64>;
289def : LoadPatGlobalAddrOffOnly<i64, extloadi32, LOAD32_U_I64>;
290def : LoadPatExternSymOffOnly<i32, extloadi8, LOAD8_U_I32>;
291def : LoadPatExternSymOffOnly<i32, extloadi16, LOAD16_U_I32>;
292def : LoadPatExternSymOffOnly<i64, extloadi8, LOAD8_U_I64>;
293def : LoadPatExternSymOffOnly<i64, extloadi16, LOAD16_U_I64>;
294def : LoadPatExternSymOffOnly<i64, extloadi32, LOAD32_U_I64>;
295
296// Defines atomic and non-atomic stores, regular and truncating
297multiclass WebAssemblyStore<WebAssemblyRegClass rc, string Name, int Opcode> {
298  let mayStore = 1 in
299  defm "" : I<(outs),
300              (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
301              (outs),
302              (ins P2Align:$p2align, offset32_op:$off), [],
303              !strconcat(Name, "\t${off}(${addr})${p2align}, $val"),
304              !strconcat(Name, "\t${off}${p2align}"), Opcode>;
305}
306// Basic store.
307// Note: WebAssembly inverts SelectionDAG's usual operand order.
308defm STORE_I32  : WebAssemblyStore<I32, "i32.store", 0x36>;
309defm STORE_I64  : WebAssemblyStore<I64, "i64.store", 0x37>;
310defm STORE_F32  : WebAssemblyStore<F32, "f32.store", 0x38>;
311defm STORE_F64  : WebAssemblyStore<F64, "f64.store", 0x39>;
312
313// Select stores with no constant offset.
314class StorePatNoOffset<ValueType ty, PatFrag node, NI inst> :
315  Pat<(node ty:$val, I32:$addr), (inst 0, 0, I32:$addr, ty:$val)>;
316
317def : StorePatNoOffset<i32, store, STORE_I32>;
318def : StorePatNoOffset<i64, store, STORE_I64>;
319def : StorePatNoOffset<f32, store, STORE_F32>;
320def : StorePatNoOffset<f64, store, STORE_F64>;
321
322// Select stores with a constant offset.
323class StorePatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
324  Pat<(kind ty:$val, (operand I32:$addr, imm:$off)),
325      (inst 0, imm:$off, I32:$addr, ty:$val)>;
326
327def : StorePatImmOff<i32, store, regPlusImm, STORE_I32>;
328def : StorePatImmOff<i64, store, regPlusImm, STORE_I64>;
329def : StorePatImmOff<f32, store, regPlusImm, STORE_F32>;
330def : StorePatImmOff<f64, store, regPlusImm, STORE_F64>;
331def : StorePatImmOff<i32, store, or_is_add, STORE_I32>;
332def : StorePatImmOff<i64, store, or_is_add, STORE_I64>;
333def : StorePatImmOff<f32, store, or_is_add, STORE_F32>;
334def : StorePatImmOff<f64, store, or_is_add, STORE_F64>;
335
336class StorePatGlobalAddr<ValueType ty, PatFrag kind, NI inst> :
337  Pat<(kind ty:$val,
338            (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off))),
339      (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>;
340def : StorePatGlobalAddr<i32, store, STORE_I32>;
341def : StorePatGlobalAddr<i64, store, STORE_I64>;
342def : StorePatGlobalAddr<f32, store, STORE_F32>;
343def : StorePatGlobalAddr<f64, store, STORE_F64>;
344
345class StorePatExternalSym<ValueType ty, PatFrag kind, NI inst> :
346  Pat<(kind ty:$val, (add I32:$addr, (WebAssemblywrapper texternalsym:$off))),
347      (inst 0, texternalsym:$off, I32:$addr, ty:$val)>;
348def : StorePatExternalSym<i32, store, STORE_I32>;
349def : StorePatExternalSym<i64, store, STORE_I64>;
350def : StorePatExternalSym<f32, store, STORE_F32>;
351def : StorePatExternalSym<f64, store, STORE_F64>;
352
353// Select stores with just a constant offset.
354class StorePatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
355  Pat<(kind ty:$val, imm:$off), (inst 0, imm:$off, (CONST_I32 0), ty:$val)>;
356def : StorePatOffsetOnly<i32, store, STORE_I32>;
357def : StorePatOffsetOnly<i64, store, STORE_I64>;
358def : StorePatOffsetOnly<f32, store, STORE_F32>;
359def : StorePatOffsetOnly<f64, store, STORE_F64>;
360
361class StorePatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
362  Pat<(kind ty:$val, (WebAssemblywrapper tglobaladdr:$off)),
363      (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>;
364def : StorePatGlobalAddrOffOnly<i32, store, STORE_I32>;
365def : StorePatGlobalAddrOffOnly<i64, store, STORE_I64>;
366def : StorePatGlobalAddrOffOnly<f32, store, STORE_F32>;
367def : StorePatGlobalAddrOffOnly<f64, store, STORE_F64>;
368
369class StorePatExternSymOffOnly<ValueType ty, PatFrag kind, NI inst> :
370  Pat<(kind ty:$val, (WebAssemblywrapper texternalsym:$off)),
371      (inst 0, texternalsym:$off, (CONST_I32 0), ty:$val)>;
372def : StorePatExternSymOffOnly<i32, store, STORE_I32>;
373def : StorePatExternSymOffOnly<i64, store, STORE_I64>;
374def : StorePatExternSymOffOnly<f32, store, STORE_F32>;
375def : StorePatExternSymOffOnly<f64, store, STORE_F64>;
376
377// Truncating store.
378defm STORE8_I32 : WebAssemblyStore<I32, "i32.store8", 0x3a>;
379defm STORE16_I32 : WebAssemblyStore<I32, "i32.store16", 0x3b>;
380defm STORE8_I64 : WebAssemblyStore<I64, "i64.store8", 0x3c>;
381defm STORE16_I64 : WebAssemblyStore<I64, "i64.store16", 0x3d>;
382defm STORE32_I64 : WebAssemblyStore<I64, "i64.store32", 0x3e>;
383
384// Select truncating stores with no constant offset.
385def : StorePatNoOffset<i32, truncstorei8, STORE8_I32>;
386def : StorePatNoOffset<i32, truncstorei16, STORE16_I32>;
387def : StorePatNoOffset<i64, truncstorei8, STORE8_I64>;
388def : StorePatNoOffset<i64, truncstorei16, STORE16_I64>;
389def : StorePatNoOffset<i64, truncstorei32, STORE32_I64>;
390
391// Select truncating stores with a constant offset.
392def : StorePatImmOff<i32, truncstorei8, regPlusImm, STORE8_I32>;
393def : StorePatImmOff<i32, truncstorei16, regPlusImm, STORE16_I32>;
394def : StorePatImmOff<i64, truncstorei8, regPlusImm, STORE8_I64>;
395def : StorePatImmOff<i64, truncstorei16, regPlusImm, STORE16_I64>;
396def : StorePatImmOff<i64, truncstorei32, regPlusImm, STORE32_I64>;
397def : StorePatImmOff<i32, truncstorei8, or_is_add, STORE8_I32>;
398def : StorePatImmOff<i32, truncstorei16, or_is_add, STORE16_I32>;
399def : StorePatImmOff<i64, truncstorei8, or_is_add, STORE8_I64>;
400def : StorePatImmOff<i64, truncstorei16, or_is_add, STORE16_I64>;
401def : StorePatImmOff<i64, truncstorei32, or_is_add, STORE32_I64>;
402
403def : StorePatGlobalAddr<i32, truncstorei8, STORE8_I32>;
404def : StorePatGlobalAddr<i32, truncstorei16, STORE16_I32>;
405def : StorePatGlobalAddr<i64, truncstorei8, STORE8_I64>;
406def : StorePatGlobalAddr<i64, truncstorei16, STORE16_I64>;
407def : StorePatGlobalAddr<i64, truncstorei32, STORE32_I64>;
408def : StorePatExternalSym<i32, truncstorei8, STORE8_I32>;
409def : StorePatExternalSym<i32, truncstorei16, STORE16_I32>;
410def : StorePatExternalSym<i64, truncstorei8, STORE8_I64>;
411def : StorePatExternalSym<i64, truncstorei16, STORE16_I64>;
412def : StorePatExternalSym<i64, truncstorei32, STORE32_I64>;
413
414// Select truncating stores with just a constant offset.
415def : StorePatOffsetOnly<i32, truncstorei8, STORE8_I32>;
416def : StorePatOffsetOnly<i32, truncstorei16, STORE16_I32>;
417def : StorePatOffsetOnly<i64, truncstorei8, STORE8_I64>;
418def : StorePatOffsetOnly<i64, truncstorei16, STORE16_I64>;
419def : StorePatOffsetOnly<i64, truncstorei32, STORE32_I64>;
420def : StorePatGlobalAddrOffOnly<i32, truncstorei8, STORE8_I32>;
421def : StorePatGlobalAddrOffOnly<i32, truncstorei16, STORE16_I32>;
422def : StorePatGlobalAddrOffOnly<i64, truncstorei8, STORE8_I64>;
423def : StorePatGlobalAddrOffOnly<i64, truncstorei16, STORE16_I64>;
424def : StorePatGlobalAddrOffOnly<i64, truncstorei32, STORE32_I64>;
425def : StorePatExternSymOffOnly<i32, truncstorei8, STORE8_I32>;
426def : StorePatExternSymOffOnly<i32, truncstorei16, STORE16_I32>;
427def : StorePatExternSymOffOnly<i64, truncstorei8, STORE8_I64>;
428def : StorePatExternSymOffOnly<i64, truncstorei16, STORE16_I64>;
429def : StorePatExternSymOffOnly<i64, truncstorei32, STORE32_I64>;
430
431// Current memory size.
432defm MEMORY_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags),
433                         (outs), (ins i32imm:$flags),
434                         [(set I32:$dst,
435                           (int_wasm_memory_size (i32 imm:$flags)))],
436                         "memory.size\t$dst, $flags", "memory.size\t$flags",
437                         0x3f>,
438                       Requires<[HasAddr32]>;
439
440// Grow memory.
441defm MEMORY_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
442                         (outs), (ins i32imm:$flags),
443                         [(set I32:$dst,
444                           (int_wasm_memory_grow (i32 imm:$flags),
445                             I32:$delta))],
446                         "memory.grow\t$dst, $flags, $delta",
447                         "memory.grow\t$flags", 0x40>,
448                       Requires<[HasAddr32]>;
449