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