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