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