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