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