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