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