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}", 0x2a>;
62def LOAD_I64 : I<(outs I64:$dst), (ins i32imm:$off, I32:$addr,
63                                   P2Align:$p2align), [],
64                 "i64.load\t$dst, ${off}(${addr})${p2align}", 0x2b>;
65def LOAD_F32 : I<(outs F32:$dst), (ins i32imm:$off, I32:$addr,
66                                   P2Align:$p2align), [],
67                 "f32.load\t$dst, ${off}(${addr})${p2align}", 0x2c>;
68def LOAD_F64 : I<(outs F64:$dst), (ins i32imm:$off, I32:$addr,
69                                   P2Align:$p2align), [],
70                 "f64.load\t$dst, ${off}(${addr})${p2align}", 0x2d>;
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}", 0x20>;
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}", 0x21>;
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}", 0x22>;
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}", 0x23>;
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}", 0x24>;
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}", 0x25>;
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}", 0x26>;
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}", 0x27>;
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}", 0x28>;
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}", 0x29>;
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: WebAssembly inverts SelectionDAG's usual operand order.
450def STORE_I32  : I<(outs), (ins i32imm:$off, I32:$addr,
451                            P2Align:$p2align, I32:$val), [],
452                   "i32.store\t${off}(${addr})${p2align}, $val", 0x33>;
453def STORE_I64  : I<(outs), (ins i32imm:$off, I32:$addr,
454                            P2Align:$p2align, I64:$val), [],
455                   "i64.store\t${off}(${addr})${p2align}, $val", 0x34>;
456def STORE_F32  : I<(outs), (ins i32imm:$off, I32:$addr,
457                            P2Align:$p2align, F32:$val), [],
458                   "f32.store\t${off}(${addr})${p2align}, $val", 0x35>;
459def STORE_F64  : I<(outs), (ins i32imm:$off, I32:$addr,
460                            P2Align:$p2align, F64:$val), [],
461                   "f64.store\t${off}(${addr})${p2align}, $val", 0x36>;
462
463} // Defs = [ARGUMENTS]
464
465// Select stores with no constant offset.
466def : Pat<(store I32:$val, I32:$addr), (STORE_I32 0, I32:$addr, 0, I32:$val)>;
467def : Pat<(store I64:$val, I32:$addr), (STORE_I64 0, I32:$addr, 0, I64:$val)>;
468def : Pat<(store F32:$val, I32:$addr), (STORE_F32 0, I32:$addr, 0, F32:$val)>;
469def : Pat<(store F64:$val, I32:$addr), (STORE_F64 0, I32:$addr, 0, F64:$val)>;
470
471// Select stores with a constant offset.
472def : Pat<(store I32:$val, (regPlusImm I32:$addr, imm:$off)),
473          (STORE_I32 imm:$off, I32:$addr, 0, I32:$val)>;
474def : Pat<(store I64:$val, (regPlusImm I32:$addr, imm:$off)),
475          (STORE_I64 imm:$off, I32:$addr, 0, I64:$val)>;
476def : Pat<(store F32:$val, (regPlusImm I32:$addr, imm:$off)),
477          (STORE_F32 imm:$off, I32:$addr, 0, F32:$val)>;
478def : Pat<(store F64:$val, (regPlusImm I32:$addr, imm:$off)),
479          (STORE_F64 imm:$off, I32:$addr, 0, F64:$val)>;
480def : Pat<(store I32:$val, (or_is_add I32:$addr, imm:$off)),
481          (STORE_I32 imm:$off, I32:$addr, 0, I32:$val)>;
482def : Pat<(store I64:$val, (or_is_add I32:$addr, imm:$off)),
483          (STORE_I64 imm:$off, I32:$addr, 0, I64:$val)>;
484def : Pat<(store F32:$val, (or_is_add I32:$addr, imm:$off)),
485          (STORE_F32 imm:$off, I32:$addr, 0, F32:$val)>;
486def : Pat<(store F64:$val, (or_is_add I32:$addr, imm:$off)),
487          (STORE_F64 imm:$off, I32:$addr, 0, F64:$val)>;
488def : Pat<(store I32:$val, (regPlusGA I32:$addr,
489                                      (WebAssemblywrapper tglobaladdr:$off))),
490          (STORE_I32 tglobaladdr:$off, I32:$addr, 0, I32:$val)>;
491def : Pat<(store I64:$val, (regPlusGA I32:$addr,
492                                      (WebAssemblywrapper tglobaladdr:$off))),
493          (STORE_I64 tglobaladdr:$off, I32:$addr, 0, I64:$val)>;
494def : Pat<(store F32:$val, (regPlusGA I32:$addr,
495                                      (WebAssemblywrapper tglobaladdr:$off))),
496          (STORE_F32 tglobaladdr:$off, I32:$addr, 0, F32:$val)>;
497def : Pat<(store F64:$val, (regPlusGA I32:$addr,
498                                      (WebAssemblywrapper tglobaladdr:$off))),
499          (STORE_F64 tglobaladdr:$off, I32:$addr, 0, F64:$val)>;
500def : Pat<(store I32:$val, (add I32:$addr,
501                                (WebAssemblywrapper texternalsym:$off))),
502          (STORE_I32 texternalsym:$off, I32:$addr, 0, I32:$val)>;
503def : Pat<(store I64:$val, (add I32:$addr,
504                                (WebAssemblywrapper texternalsym:$off))),
505          (STORE_I64 texternalsym:$off, I32:$addr, 0, I64:$val)>;
506def : Pat<(store F32:$val, (add I32:$addr,
507                                (WebAssemblywrapper texternalsym:$off))),
508          (STORE_F32 texternalsym:$off, I32:$addr, 0, F32:$val)>;
509def : Pat<(store F64:$val, (add I32:$addr,
510                                (WebAssemblywrapper texternalsym:$off))),
511          (STORE_F64 texternalsym:$off, I32:$addr, 0, F64:$val)>;
512
513// Select stores with just a constant offset.
514def : Pat<(store I32:$val, imm:$off),
515          (STORE_I32 imm:$off, (CONST_I32 0), 0, I32:$val)>;
516def : Pat<(store I64:$val, imm:$off),
517          (STORE_I64 imm:$off, (CONST_I32 0), 0, I64:$val)>;
518def : Pat<(store F32:$val, imm:$off),
519          (STORE_F32 imm:$off, (CONST_I32 0), 0, F32:$val)>;
520def : Pat<(store F64:$val, imm:$off),
521          (STORE_F64 imm:$off, (CONST_I32 0), 0, F64:$val)>;
522def : Pat<(store I32:$val, (WebAssemblywrapper tglobaladdr:$off)),
523          (STORE_I32 tglobaladdr:$off, (CONST_I32 0), 0, I32:$val)>;
524def : Pat<(store I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
525          (STORE_I64 tglobaladdr:$off, (CONST_I32 0), 0, I64:$val)>;
526def : Pat<(store F32:$val, (WebAssemblywrapper tglobaladdr:$off)),
527          (STORE_F32 tglobaladdr:$off, (CONST_I32 0), 0, F32:$val)>;
528def : Pat<(store F64:$val, (WebAssemblywrapper tglobaladdr:$off)),
529          (STORE_F64 tglobaladdr:$off, (CONST_I32 0), 0, F64:$val)>;
530def : Pat<(store I32:$val, (WebAssemblywrapper texternalsym:$off)),
531          (STORE_I32 texternalsym:$off, (CONST_I32 0), 0, I32:$val)>;
532def : Pat<(store I64:$val, (WebAssemblywrapper texternalsym:$off)),
533          (STORE_I64 texternalsym:$off, (CONST_I32 0), 0, I64:$val)>;
534def : Pat<(store F32:$val, (WebAssemblywrapper texternalsym:$off)),
535          (STORE_F32 texternalsym:$off, (CONST_I32 0), 0, F32:$val)>;
536def : Pat<(store F64:$val, (WebAssemblywrapper texternalsym:$off)),
537          (STORE_F64 texternalsym:$off, (CONST_I32 0), 0, F64:$val)>;
538
539let Defs = [ARGUMENTS] in {
540
541// Truncating store.
542def STORE8_I32  : I<(outs), (ins i32imm:$off, I32:$addr,
543                             P2Align:$p2align, I32:$val), [],
544                    "i32.store8\t${off}(${addr})${p2align}, $val", 0x2e>;
545def STORE16_I32 : I<(outs), (ins i32imm:$off, I32:$addr,
546                             P2Align:$p2align, I32:$val), [],
547                    "i32.store16\t${off}(${addr})${p2align}, $val", 0x2f>;
548def STORE8_I64  : I<(outs), (ins i32imm:$off, I32:$addr,
549                             P2Align:$p2align, I64:$val), [],
550                    "i64.store8\t${off}(${addr})${p2align}, $val", 0x30>;
551def STORE16_I64 : I<(outs), (ins i32imm:$off, I32:$addr,
552                             P2Align:$p2align, I64:$val), [],
553                    "i64.store16\t${off}(${addr})${p2align}, $val", 0x31>;
554def STORE32_I64 : I<(outs), (ins i32imm:$off, I32:$addr,
555                             P2Align:$p2align, I64:$val), [],
556                    "i64.store32\t${off}(${addr})${p2align}, $val", 0x32>;
557
558} // Defs = [ARGUMENTS]
559
560// Select truncating stores with no constant offset.
561def : Pat<(truncstorei8 I32:$val, I32:$addr),
562          (STORE8_I32 0, I32:$addr, 0, I32:$val)>;
563def : Pat<(truncstorei16 I32:$val, I32:$addr),
564          (STORE16_I32 0, I32:$addr, 0, I32:$val)>;
565def : Pat<(truncstorei8 I64:$val, I32:$addr),
566          (STORE8_I64 0, I32:$addr, 0, I64:$val)>;
567def : Pat<(truncstorei16 I64:$val, I32:$addr),
568          (STORE16_I64 0, I32:$addr, 0, I64:$val)>;
569def : Pat<(truncstorei32 I64:$val, I32:$addr),
570          (STORE32_I64 0, I32:$addr, 0, I64:$val)>;
571
572// Select truncating stores with a constant offset.
573def : Pat<(truncstorei8 I32:$val, (regPlusImm I32:$addr, imm:$off)),
574          (STORE8_I32 imm:$off, I32:$addr, 0, I32:$val)>;
575def : Pat<(truncstorei16 I32:$val, (regPlusImm I32:$addr, imm:$off)),
576          (STORE16_I32 imm:$off, I32:$addr, 0, I32:$val)>;
577def : Pat<(truncstorei8 I64:$val, (regPlusImm I32:$addr, imm:$off)),
578          (STORE8_I64 imm:$off, I32:$addr, 0, I64:$val)>;
579def : Pat<(truncstorei16 I64:$val, (regPlusImm I32:$addr, imm:$off)),
580          (STORE16_I64 imm:$off, I32:$addr, 0, I64:$val)>;
581def : Pat<(truncstorei32 I64:$val, (regPlusImm I32:$addr, imm:$off)),
582          (STORE32_I64 imm:$off, I32:$addr, 0, I64:$val)>;
583def : Pat<(truncstorei8 I32:$val, (or_is_add I32:$addr, imm:$off)),
584          (STORE8_I32 imm:$off, I32:$addr, 0, I32:$val)>;
585def : Pat<(truncstorei16 I32:$val, (or_is_add I32:$addr, imm:$off)),
586          (STORE16_I32 imm:$off, I32:$addr, 0, I32:$val)>;
587def : Pat<(truncstorei8 I64:$val, (or_is_add I32:$addr, imm:$off)),
588          (STORE8_I64 imm:$off, I32:$addr, 0, I64:$val)>;
589def : Pat<(truncstorei16 I64:$val, (or_is_add I32:$addr, imm:$off)),
590          (STORE16_I64 imm:$off, I32:$addr, 0, I64:$val)>;
591def : Pat<(truncstorei32 I64:$val, (or_is_add I32:$addr, imm:$off)),
592          (STORE32_I64 imm:$off, I32:$addr, 0, I64:$val)>;
593def : Pat<(truncstorei8 I32:$val,
594                        (regPlusGA I32:$addr,
595                                   (WebAssemblywrapper tglobaladdr:$off))),
596          (STORE8_I32 tglobaladdr:$off, I32:$addr, 0, I32:$val)>;
597def : Pat<(truncstorei16 I32:$val,
598                         (regPlusGA I32:$addr,
599                                    (WebAssemblywrapper tglobaladdr:$off))),
600          (STORE16_I32 tglobaladdr:$off, I32:$addr, 0, I32:$val)>;
601def : Pat<(truncstorei8 I64:$val,
602                        (regPlusGA I32:$addr,
603                                   (WebAssemblywrapper tglobaladdr:$off))),
604          (STORE8_I64 tglobaladdr:$off, I32:$addr, 0, I64:$val)>;
605def : Pat<(truncstorei16 I64:$val,
606                         (regPlusGA I32:$addr,
607                                    (WebAssemblywrapper tglobaladdr:$off))),
608          (STORE16_I64 tglobaladdr:$off, I32:$addr, 0, I64:$val)>;
609def : Pat<(truncstorei32 I64:$val,
610                         (regPlusGA I32:$addr,
611                                    (WebAssemblywrapper tglobaladdr:$off))),
612          (STORE32_I64 tglobaladdr:$off, I32:$addr, 0, I64:$val)>;
613def : Pat<(truncstorei8 I32:$val, (add I32:$addr,
614                                       (WebAssemblywrapper texternalsym:$off))),
615          (STORE8_I32 texternalsym:$off, I32:$addr, 0, I32:$val)>;
616def : Pat<(truncstorei16 I32:$val,
617                         (add I32:$addr,
618                              (WebAssemblywrapper texternalsym:$off))),
619          (STORE16_I32 texternalsym:$off, I32:$addr, 0, I32:$val)>;
620def : Pat<(truncstorei8 I64:$val,
621                        (add I32:$addr,
622                             (WebAssemblywrapper texternalsym:$off))),
623          (STORE8_I64 texternalsym:$off, I32:$addr, 0, I64:$val)>;
624def : Pat<(truncstorei16 I64:$val,
625                         (add I32:$addr,
626                              (WebAssemblywrapper texternalsym:$off))),
627          (STORE16_I64 texternalsym:$off, I32:$addr, 0, I64:$val)>;
628def : Pat<(truncstorei32 I64:$val,
629                         (add I32:$addr,
630                              (WebAssemblywrapper texternalsym:$off))),
631          (STORE32_I64 texternalsym:$off, I32:$addr, 0, I64:$val)>;
632
633// Select truncating stores with just a constant offset.
634def : Pat<(truncstorei8 I32:$val, imm:$off),
635          (STORE8_I32 imm:$off, (CONST_I32 0), 0, I32:$val)>;
636def : Pat<(truncstorei16 I32:$val, imm:$off),
637          (STORE16_I32 imm:$off, (CONST_I32 0), 0, I32:$val)>;
638def : Pat<(truncstorei8 I64:$val, imm:$off),
639          (STORE8_I64 imm:$off, (CONST_I32 0), 0, I64:$val)>;
640def : Pat<(truncstorei16 I64:$val, imm:$off),
641          (STORE16_I64 imm:$off, (CONST_I32 0), 0, I64:$val)>;
642def : Pat<(truncstorei32 I64:$val, imm:$off),
643          (STORE32_I64 imm:$off, (CONST_I32 0), 0, I64:$val)>;
644def : Pat<(truncstorei8 I32:$val, (WebAssemblywrapper tglobaladdr:$off)),
645          (STORE8_I32 tglobaladdr:$off, (CONST_I32 0), 0, I32:$val)>;
646def : Pat<(truncstorei16 I32:$val, (WebAssemblywrapper tglobaladdr:$off)),
647          (STORE16_I32 tglobaladdr:$off, (CONST_I32 0), 0, I32:$val)>;
648def : Pat<(truncstorei8 I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
649          (STORE8_I64 tglobaladdr:$off, (CONST_I32 0), 0, I64:$val)>;
650def : Pat<(truncstorei16 I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
651          (STORE16_I64 tglobaladdr:$off, (CONST_I32 0), 0, I64:$val)>;
652def : Pat<(truncstorei32 I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
653          (STORE32_I64 tglobaladdr:$off, (CONST_I32 0), 0, I64:$val)>;
654def : Pat<(truncstorei8 I32:$val, (WebAssemblywrapper texternalsym:$off)),
655          (STORE8_I32 texternalsym:$off, (CONST_I32 0), 0, I32:$val)>;
656def : Pat<(truncstorei16 I32:$val, (WebAssemblywrapper texternalsym:$off)),
657          (STORE16_I32 texternalsym:$off, (CONST_I32 0), 0, I32:$val)>;
658def : Pat<(truncstorei8 I64:$val, (WebAssemblywrapper texternalsym:$off)),
659          (STORE8_I64 texternalsym:$off, (CONST_I32 0), 0, I64:$val)>;
660def : Pat<(truncstorei16 I64:$val, (WebAssemblywrapper texternalsym:$off)),
661          (STORE16_I64 texternalsym:$off, (CONST_I32 0), 0, I64:$val)>;
662def : Pat<(truncstorei32 I64:$val, (WebAssemblywrapper texternalsym:$off)),
663          (STORE32_I64 texternalsym:$off, (CONST_I32 0), 0, I64:$val)>;
664
665let Defs = [ARGUMENTS] in {
666
667// Current memory size.
668def CURRENT_MEMORY_I32 : I<(outs I32:$dst), (ins),
669                           [(set I32:$dst, (int_wasm_current_memory))],
670                           "current_memory\t$dst", 0x3b>,
671                         Requires<[HasAddr32]>;
672def CURRENT_MEMORY_I64 : I<(outs I64:$dst), (ins),
673                           [(set I64:$dst, (int_wasm_current_memory))],
674                           "current_memory\t$dst">,
675                         Requires<[HasAddr64]>;
676
677// Grow memory.
678def GROW_MEMORY_I32 : I<(outs), (ins I32:$delta),
679                        [(int_wasm_grow_memory I32:$delta)],
680                        "grow_memory\t$delta", 0x39>,
681                      Requires<[HasAddr32]>;
682def GROW_MEMORY_I64 : I<(outs), (ins I64:$delta),
683                        [(int_wasm_grow_memory I64:$delta)],
684                        "grow_memory\t$delta">,
685                      Requires<[HasAddr64]>;
686
687} // Defs = [ARGUMENTS]
688