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