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