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