WebAssemblyInstrMemory.td revision 344779
1286425Sdim// WebAssemblyInstrMemory.td-WebAssembly Memory codegen support -*- tablegen -*-
2286425Sdim//
3286425Sdim//                     The LLVM Compiler Infrastructure
4286425Sdim//
5286425Sdim// This file is distributed under the University of Illinois Open Source
6286425Sdim// License. See LICENSE.TXT for details.
7286425Sdim//
8286425Sdim//===----------------------------------------------------------------------===//
9286425Sdim///
10286425Sdim/// \file
11341825Sdim/// WebAssembly Memory operand code-gen constructs.
12286425Sdim///
13286425Sdim//===----------------------------------------------------------------------===//
14286425Sdim
15296417Sdim// TODO:
16296417Sdim//  - HasAddr64
17296417Sdim//  - WebAssemblyTargetLowering having to do with atomics
18296417Sdim//  - Each has optional alignment.
19296417Sdim
20296417Sdim// WebAssembly has i8/i16/i32/i64/f32/f64 memory types, but doesn't have i8/i16
21296417Sdim// local types. These memory-only types instead zero- or sign-extend into local
22296417Sdim// types when loading, and truncate when storing.
23296417Sdim
24296417Sdim// WebAssembly constant offsets are performed as unsigned with infinite
25296417Sdim// precision, so we need to check for NoUnsignedWrap so that we don't fold an
26296417Sdim// offset for an add that needs wrapping.
27296417Sdimdef regPlusImm : PatFrag<(ops node:$addr, node:$off),
28296417Sdim                         (add node:$addr, node:$off),
29321369Sdim                         [{ return N->getFlags().hasNoUnsignedWrap(); }]>;
30296417Sdim
31309124Sdim// Treat an 'or' node as an 'add' if the or'ed bits are known to be zero.
32309124Sdimdef or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{
33309124Sdim  if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))
34309124Sdim    return CurDAG->MaskedValueIsZero(N->getOperand(0), CN->getAPIntValue());
35309124Sdim
36344779Sdim  KnownBits Known0 = CurDAG->computeKnownBits(N->getOperand(0), 0);
37344779Sdim  KnownBits Known1 = CurDAG->computeKnownBits(N->getOperand(1), 0);
38321369Sdim  return (~Known0.Zero & ~Known1.Zero) == 0;
39309124Sdim}]>;
40309124Sdim
41296417Sdim// GlobalAddresses are conceptually unsigned values, so we can also fold them
42314564Sdim// into immediate values as long as the add is 'nuw'.
43314564Sdim// TODO: We'd like to also match GA offsets but there are cases where the
44314564Sdim// register can have a negative value. Find out what more we can do.
45296417Sdimdef regPlusGA : PatFrag<(ops node:$addr, node:$off),
46296417Sdim                        (add node:$addr, node:$off),
47296417Sdim                        [{
48321369Sdim  return N->getFlags().hasNoUnsignedWrap();
49296417Sdim}]>;
50296417Sdim
51296417Sdim// We don't need a regPlusES because external symbols never have constant
52296417Sdim// offsets folded into them, so we can just use add.
53296417Sdim
54327952Sdim// Defines atomic and non-atomic loads, regular and extending.
55341825Sdimmulticlass WebAssemblyLoad<WebAssemblyRegClass rc, string Name, int Opcode> {
56344779Sdim  let mayLoad = 1 in
57341825Sdim  defm "": I<(outs rc:$dst),
58341825Sdim             (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
59341825Sdim             (outs), (ins P2Align:$p2align, offset32_op:$off),
60341825Sdim             [], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"),
61344779Sdim             !strconcat(Name, "\t${off}${p2align}"), Opcode>;
62341825Sdim}
63327952Sdim
64296417Sdim// Basic load.
65314564Sdim// FIXME: When we can break syntax compatibility, reorder the fields in the
66314564Sdim// asmstrings to match the binary encoding.
67341825Sdimdefm LOAD_I32 : WebAssemblyLoad<I32, "i32.load", 0x28>;
68341825Sdimdefm LOAD_I64 : WebAssemblyLoad<I64, "i64.load", 0x29>;
69341825Sdimdefm LOAD_F32 : WebAssemblyLoad<F32, "f32.load", 0x2a>;
70341825Sdimdefm LOAD_F64 : WebAssemblyLoad<F64, "f64.load", 0x2b>;
71296417Sdim
72296417Sdim// Select loads with no constant offset.
73341825Sdimclass LoadPatNoOffset<ValueType ty, PatFrag kind, NI inst> :
74341825Sdim  Pat<(ty (kind I32:$addr)), (inst 0, 0, I32:$addr)>;
75296417Sdim
76327952Sdimdef : LoadPatNoOffset<i32, load, LOAD_I32>;
77327952Sdimdef : LoadPatNoOffset<i64, load, LOAD_I64>;
78327952Sdimdef : LoadPatNoOffset<f32, load, LOAD_F32>;
79327952Sdimdef : LoadPatNoOffset<f64, load, LOAD_F64>;
80327952Sdim
81327952Sdim
82296417Sdim// Select loads with a constant offset.
83296417Sdim
84327952Sdim// Pattern with address + immediate offset
85341825Sdimclass LoadPatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
86341825Sdim  Pat<(ty (kind (operand I32:$addr, imm:$off))), (inst 0, imm:$off, I32:$addr)>;
87327952Sdim
88327952Sdimdef : LoadPatImmOff<i32, load, regPlusImm, LOAD_I32>;
89327952Sdimdef : LoadPatImmOff<i64, load, regPlusImm, LOAD_I64>;
90327952Sdimdef : LoadPatImmOff<f32, load, regPlusImm, LOAD_F32>;
91327952Sdimdef : LoadPatImmOff<f64, load, regPlusImm, LOAD_F64>;
92327952Sdimdef : LoadPatImmOff<i32, load, or_is_add, LOAD_I32>;
93327952Sdimdef : LoadPatImmOff<i64, load, or_is_add, LOAD_I64>;
94327952Sdimdef : LoadPatImmOff<f32, load, or_is_add, LOAD_F32>;
95327952Sdimdef : LoadPatImmOff<f64, load, or_is_add, LOAD_F64>;
96327952Sdim
97341825Sdimclass LoadPatGlobalAddr<ValueType ty, PatFrag kind, NI inst> :
98341825Sdim  Pat<(ty (kind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)))),
99341825Sdim      (inst 0, tglobaladdr:$off, I32:$addr)>;
100327952Sdim
101327952Sdimdef : LoadPatGlobalAddr<i32, load, LOAD_I32>;
102327952Sdimdef : LoadPatGlobalAddr<i64, load, LOAD_I64>;
103327952Sdimdef : LoadPatGlobalAddr<f32, load, LOAD_F32>;
104327952Sdimdef : LoadPatGlobalAddr<f64, load, LOAD_F64>;
105327952Sdim
106341825Sdimclass LoadPatExternalSym<ValueType ty, PatFrag kind, NI inst> :
107341825Sdim  Pat<(ty (kind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))),
108341825Sdim      (inst 0, texternalsym:$off, I32:$addr)>;
109327952Sdimdef : LoadPatExternalSym<i32, load, LOAD_I32>;
110327952Sdimdef : LoadPatExternalSym<i64, load, LOAD_I64>;
111327952Sdimdef : LoadPatExternalSym<f32, load, LOAD_F32>;
112327952Sdimdef : LoadPatExternalSym<f64, load, LOAD_F64>;
113327952Sdim
114327952Sdim
115296417Sdim// Select loads with just a constant offset.
116341825Sdimclass LoadPatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
117341825Sdim  Pat<(ty (kind imm:$off)), (inst 0, imm:$off, (CONST_I32 0))>;
118296417Sdim
119327952Sdimdef : LoadPatOffsetOnly<i32, load, LOAD_I32>;
120327952Sdimdef : LoadPatOffsetOnly<i64, load, LOAD_I64>;
121327952Sdimdef : LoadPatOffsetOnly<f32, load, LOAD_F32>;
122327952Sdimdef : LoadPatOffsetOnly<f64, load, LOAD_F64>;
123327952Sdim
124341825Sdimclass LoadPatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
125341825Sdim  Pat<(ty (kind (WebAssemblywrapper tglobaladdr:$off))),
126327952Sdim      (inst 0, tglobaladdr:$off, (CONST_I32 0))>;
127327952Sdim
128327952Sdimdef : LoadPatGlobalAddrOffOnly<i32, load, LOAD_I32>;
129327952Sdimdef : LoadPatGlobalAddrOffOnly<i64, load, LOAD_I64>;
130327952Sdimdef : LoadPatGlobalAddrOffOnly<f32, load, LOAD_F32>;
131327952Sdimdef : LoadPatGlobalAddrOffOnly<f64, load, LOAD_F64>;
132327952Sdim
133341825Sdimclass LoadPatExternSymOffOnly<ValueType ty, PatFrag kind, NI inst> :
134341825Sdim  Pat<(ty (kind (WebAssemblywrapper texternalsym:$off))),
135327952Sdim      (inst 0, texternalsym:$off, (CONST_I32 0))>;
136327952Sdimdef : LoadPatExternSymOffOnly<i32, load, LOAD_I32>;
137327952Sdimdef : LoadPatExternSymOffOnly<i64, load, LOAD_I64>;
138327952Sdimdef : LoadPatExternSymOffOnly<f32, load, LOAD_F32>;
139327952Sdimdef : LoadPatExternSymOffOnly<f64, load, LOAD_F64>;
140327952Sdim
141296417Sdim// Extending load.
142341825Sdimdefm LOAD8_S_I32 : WebAssemblyLoad<I32, "i32.load8_s", 0x2c>;
143341825Sdimdefm LOAD8_U_I32 : WebAssemblyLoad<I32, "i32.load8_u", 0x2d>;
144341825Sdimdefm LOAD16_S_I32 : WebAssemblyLoad<I32, "i32.load16_s", 0x2e>;
145341825Sdimdefm LOAD16_U_I32 : WebAssemblyLoad<I32, "i32.load16_u", 0x2f>;
146341825Sdimdefm LOAD8_S_I64 : WebAssemblyLoad<I64, "i64.load8_s", 0x30>;
147341825Sdimdefm LOAD8_U_I64 : WebAssemblyLoad<I64, "i64.load8_u", 0x31>;
148341825Sdimdefm LOAD16_S_I64 : WebAssemblyLoad<I64, "i64.load16_s", 0x32>;
149341825Sdimdefm LOAD16_U_I64 : WebAssemblyLoad<I64, "i64.load16_u", 0x33>;
150341825Sdimdefm LOAD32_S_I64 : WebAssemblyLoad<I64, "i64.load32_s", 0x34>;
151341825Sdimdefm LOAD32_U_I64 : WebAssemblyLoad<I64, "i64.load32_u", 0x35>;
152296417Sdim
153296417Sdim// Select extending loads with no constant offset.
154327952Sdimdef : LoadPatNoOffset<i32, sextloadi8, LOAD8_S_I32>;
155327952Sdimdef : LoadPatNoOffset<i32, zextloadi8, LOAD8_U_I32>;
156327952Sdimdef : LoadPatNoOffset<i32, sextloadi16, LOAD16_S_I32>;
157327952Sdimdef : LoadPatNoOffset<i32, zextloadi16, LOAD16_U_I32>;
158327952Sdimdef : LoadPatNoOffset<i64, sextloadi8, LOAD8_S_I64>;
159327952Sdimdef : LoadPatNoOffset<i64, zextloadi8, LOAD8_U_I64>;
160327952Sdimdef : LoadPatNoOffset<i64, sextloadi16, LOAD16_S_I64>;
161327952Sdimdef : LoadPatNoOffset<i64, zextloadi16, LOAD16_U_I64>;
162327952Sdimdef : LoadPatNoOffset<i64, sextloadi32, LOAD32_S_I64>;
163327952Sdimdef : LoadPatNoOffset<i64, zextloadi32, LOAD32_U_I64>;
164296417Sdim
165296417Sdim// Select extending loads with a constant offset.
166327952Sdimdef : LoadPatImmOff<i32, sextloadi8, regPlusImm, LOAD8_S_I32>;
167327952Sdimdef : LoadPatImmOff<i32, zextloadi8, regPlusImm, LOAD8_U_I32>;
168327952Sdimdef : LoadPatImmOff<i32, sextloadi16, regPlusImm, LOAD16_S_I32>;
169327952Sdimdef : LoadPatImmOff<i32, zextloadi16, regPlusImm, LOAD16_U_I32>;
170327952Sdimdef : LoadPatImmOff<i64, sextloadi8, regPlusImm, LOAD8_S_I64>;
171327952Sdimdef : LoadPatImmOff<i64, zextloadi8, regPlusImm, LOAD8_U_I64>;
172327952Sdimdef : LoadPatImmOff<i64, sextloadi16, regPlusImm, LOAD16_S_I64>;
173327952Sdimdef : LoadPatImmOff<i64, zextloadi16, regPlusImm, LOAD16_U_I64>;
174327952Sdimdef : LoadPatImmOff<i64, sextloadi32, regPlusImm, LOAD32_S_I64>;
175327952Sdimdef : LoadPatImmOff<i64, zextloadi32, regPlusImm, LOAD32_U_I64>;
176296417Sdim
177327952Sdimdef : LoadPatImmOff<i32, sextloadi8, or_is_add, LOAD8_S_I32>;
178327952Sdimdef : LoadPatImmOff<i32, zextloadi8, or_is_add, LOAD8_U_I32>;
179327952Sdimdef : LoadPatImmOff<i32, sextloadi16, or_is_add, LOAD16_S_I32>;
180327952Sdimdef : LoadPatImmOff<i32, zextloadi16, or_is_add, LOAD16_U_I32>;
181327952Sdimdef : LoadPatImmOff<i64, sextloadi8, or_is_add, LOAD8_S_I64>;
182327952Sdimdef : LoadPatImmOff<i64, zextloadi8, or_is_add, LOAD8_U_I64>;
183327952Sdimdef : LoadPatImmOff<i64, sextloadi16, or_is_add, LOAD16_S_I64>;
184327952Sdimdef : LoadPatImmOff<i64, zextloadi16, or_is_add, LOAD16_U_I64>;
185327952Sdimdef : LoadPatImmOff<i64, sextloadi32, or_is_add, LOAD32_S_I64>;
186327952Sdimdef : LoadPatImmOff<i64, zextloadi32, or_is_add, LOAD32_U_I64>;
187327952Sdim
188327952Sdimdef : LoadPatGlobalAddr<i32, sextloadi8, LOAD8_S_I32>;
189327952Sdimdef : LoadPatGlobalAddr<i32, zextloadi8, LOAD8_U_I32>;
190327952Sdimdef : LoadPatGlobalAddr<i32, sextloadi16, LOAD16_S_I32>;
191327952Sdimdef : LoadPatGlobalAddr<i32, zextloadi8, LOAD16_U_I32>;
192327952Sdim
193327952Sdimdef : LoadPatGlobalAddr<i64, sextloadi8, LOAD8_S_I64>;
194327952Sdimdef : LoadPatGlobalAddr<i64, zextloadi8, LOAD8_U_I64>;
195327952Sdimdef : LoadPatGlobalAddr<i64, sextloadi16, LOAD16_S_I64>;
196327952Sdimdef : LoadPatGlobalAddr<i64, zextloadi16, LOAD16_U_I64>;
197327952Sdimdef : LoadPatGlobalAddr<i64, sextloadi32, LOAD32_S_I64>;
198327952Sdimdef : LoadPatGlobalAddr<i64, zextloadi32, LOAD32_U_I64>;
199327952Sdim
200327952Sdimdef : LoadPatExternalSym<i32, sextloadi8, LOAD8_S_I32>;
201327952Sdimdef : LoadPatExternalSym<i32, zextloadi8, LOAD8_U_I32>;
202327952Sdimdef : LoadPatExternalSym<i32, sextloadi16, LOAD16_S_I32>;
203327952Sdimdef : LoadPatExternalSym<i32, zextloadi16, LOAD16_U_I32>;
204327952Sdimdef : LoadPatExternalSym<i64, sextloadi8, LOAD8_S_I64>;
205327952Sdimdef : LoadPatExternalSym<i64, zextloadi8, LOAD8_U_I64>;
206327952Sdimdef : LoadPatExternalSym<i64, sextloadi16, LOAD16_S_I64>;
207327952Sdimdef : LoadPatExternalSym<i64, zextloadi16, LOAD16_U_I64>;
208327952Sdimdef : LoadPatExternalSym<i64, sextloadi32, LOAD32_S_I64>;
209327952Sdimdef : LoadPatExternalSym<i64, zextloadi32, LOAD32_U_I64>;
210327952Sdim
211327952Sdim
212296417Sdim// Select extending loads with just a constant offset.
213327952Sdimdef : LoadPatOffsetOnly<i32, sextloadi8, LOAD8_S_I32>;
214327952Sdimdef : LoadPatOffsetOnly<i32, zextloadi8, LOAD8_U_I32>;
215327952Sdimdef : LoadPatOffsetOnly<i32, sextloadi16, LOAD16_S_I32>;
216327952Sdimdef : LoadPatOffsetOnly<i32, zextloadi16, LOAD16_U_I32>;
217296417Sdim
218327952Sdimdef : LoadPatOffsetOnly<i64, sextloadi8, LOAD8_S_I64>;
219327952Sdimdef : LoadPatOffsetOnly<i64, zextloadi8, LOAD8_U_I64>;
220327952Sdimdef : LoadPatOffsetOnly<i64, sextloadi16, LOAD16_S_I64>;
221327952Sdimdef : LoadPatOffsetOnly<i64, zextloadi16, LOAD16_U_I64>;
222327952Sdimdef : LoadPatOffsetOnly<i64, sextloadi32, LOAD32_S_I64>;
223327952Sdimdef : LoadPatOffsetOnly<i64, zextloadi32, LOAD32_U_I64>;
224327952Sdim
225327952Sdimdef : LoadPatGlobalAddrOffOnly<i32, sextloadi8, LOAD8_S_I32>;
226327952Sdimdef : LoadPatGlobalAddrOffOnly<i32, zextloadi8, LOAD8_U_I32>;
227327952Sdimdef : LoadPatGlobalAddrOffOnly<i32, sextloadi16, LOAD16_S_I32>;
228327952Sdimdef : LoadPatGlobalAddrOffOnly<i32, zextloadi16, LOAD16_U_I32>;
229327952Sdimdef : LoadPatGlobalAddrOffOnly<i64, sextloadi8, LOAD8_S_I64>;
230327952Sdimdef : LoadPatGlobalAddrOffOnly<i64, zextloadi8, LOAD8_U_I64>;
231327952Sdimdef : LoadPatGlobalAddrOffOnly<i64, sextloadi16, LOAD16_S_I64>;
232327952Sdimdef : LoadPatGlobalAddrOffOnly<i64, zextloadi16, LOAD16_U_I64>;
233327952Sdimdef : LoadPatGlobalAddrOffOnly<i64, sextloadi32, LOAD32_S_I64>;
234327952Sdimdef : LoadPatGlobalAddrOffOnly<i64, zextloadi32, LOAD32_U_I64>;
235327952Sdim
236327952Sdimdef : LoadPatExternSymOffOnly<i32, sextloadi8, LOAD8_S_I32>;
237327952Sdimdef : LoadPatExternSymOffOnly<i32, zextloadi8, LOAD8_U_I32>;
238327952Sdimdef : LoadPatExternSymOffOnly<i32, sextloadi16, LOAD16_S_I32>;
239327952Sdimdef : LoadPatExternSymOffOnly<i32, zextloadi16, LOAD16_U_I32>;
240327952Sdimdef : LoadPatExternSymOffOnly<i64, sextloadi8, LOAD8_S_I64>;
241327952Sdimdef : LoadPatExternSymOffOnly<i64, zextloadi8, LOAD8_U_I64>;
242327952Sdimdef : LoadPatExternSymOffOnly<i64, sextloadi16, LOAD16_S_I64>;
243327952Sdimdef : LoadPatExternSymOffOnly<i64, zextloadi16, LOAD16_U_I64>;
244327952Sdimdef : LoadPatExternSymOffOnly<i64, sextloadi32, LOAD32_S_I64>;
245327952Sdimdef : LoadPatExternSymOffOnly<i64, zextloadi32, LOAD32_U_I64>;
246327952Sdim
247296417Sdim// Resolve "don't care" extending loads to zero-extending loads. This is
248296417Sdim// somewhat arbitrary, but zero-extending is conceptually simpler.
249296417Sdim
250296417Sdim// Select "don't care" extending loads with no constant offset.
251327952Sdimdef : LoadPatNoOffset<i32, extloadi8, LOAD8_U_I32>;
252327952Sdimdef : LoadPatNoOffset<i32, extloadi16, LOAD16_U_I32>;
253327952Sdimdef : LoadPatNoOffset<i64, extloadi8, LOAD8_U_I64>;
254327952Sdimdef : LoadPatNoOffset<i64, extloadi16, LOAD16_U_I64>;
255327952Sdimdef : LoadPatNoOffset<i64, extloadi32, LOAD32_U_I64>;
256296417Sdim
257296417Sdim// Select "don't care" extending loads with a constant offset.
258327952Sdimdef : LoadPatImmOff<i32, extloadi8, regPlusImm, LOAD8_U_I32>;
259327952Sdimdef : LoadPatImmOff<i32, extloadi16, regPlusImm, LOAD16_U_I32>;
260327952Sdimdef : LoadPatImmOff<i64, extloadi8, regPlusImm, LOAD8_U_I64>;
261327952Sdimdef : LoadPatImmOff<i64, extloadi16, regPlusImm, LOAD16_U_I64>;
262327952Sdimdef : LoadPatImmOff<i64, extloadi32, regPlusImm, LOAD32_U_I64>;
263327952Sdimdef : LoadPatImmOff<i32, extloadi8, or_is_add, LOAD8_U_I32>;
264327952Sdimdef : LoadPatImmOff<i32, extloadi16, or_is_add, LOAD16_U_I32>;
265327952Sdimdef : LoadPatImmOff<i64, extloadi8, or_is_add, LOAD8_U_I64>;
266327952Sdimdef : LoadPatImmOff<i64, extloadi16, or_is_add, LOAD16_U_I64>;
267327952Sdimdef : LoadPatImmOff<i64, extloadi32, or_is_add, LOAD32_U_I64>;
268327952Sdimdef : LoadPatGlobalAddr<i32, extloadi8, LOAD8_U_I32>;
269327952Sdimdef : LoadPatGlobalAddr<i32, extloadi16, LOAD16_U_I32>;
270327952Sdimdef : LoadPatGlobalAddr<i64, extloadi8, LOAD8_U_I64>;
271327952Sdimdef : LoadPatGlobalAddr<i64, extloadi16, LOAD16_U_I64>;
272327952Sdimdef : LoadPatGlobalAddr<i64, extloadi32, LOAD32_U_I64>;
273327952Sdimdef : LoadPatExternalSym<i32, extloadi8, LOAD8_U_I32>;
274327952Sdimdef : LoadPatExternalSym<i32, extloadi16, LOAD16_U_I32>;
275327952Sdimdef : LoadPatExternalSym<i64, extloadi8, LOAD8_U_I64>;
276327952Sdimdef : LoadPatExternalSym<i64, extloadi16, LOAD16_U_I64>;
277327952Sdimdef : LoadPatExternalSym<i64, extloadi32, LOAD32_U_I64>;
278296417Sdim
279296417Sdim// Select "don't care" extending loads with just a constant offset.
280327952Sdimdef : LoadPatOffsetOnly<i32, extloadi8, LOAD8_U_I32>;
281327952Sdimdef : LoadPatOffsetOnly<i32, extloadi16, LOAD16_U_I32>;
282327952Sdimdef : LoadPatOffsetOnly<i64, extloadi8, LOAD8_U_I64>;
283327952Sdimdef : LoadPatOffsetOnly<i64, extloadi16, LOAD16_U_I64>;
284327952Sdimdef : LoadPatOffsetOnly<i64, extloadi32, LOAD32_U_I64>;
285327952Sdimdef : LoadPatGlobalAddrOffOnly<i32, extloadi8, LOAD8_U_I32>;
286327952Sdimdef : LoadPatGlobalAddrOffOnly<i32, extloadi16, LOAD16_U_I32>;
287327952Sdimdef : LoadPatGlobalAddrOffOnly<i64, extloadi8, LOAD8_U_I64>;
288327952Sdimdef : LoadPatGlobalAddrOffOnly<i64, extloadi16, LOAD16_U_I64>;
289327952Sdimdef : LoadPatGlobalAddrOffOnly<i64, extloadi32, LOAD32_U_I64>;
290327952Sdimdef : LoadPatExternSymOffOnly<i32, extloadi8, LOAD8_U_I32>;
291327952Sdimdef : LoadPatExternSymOffOnly<i32, extloadi16, LOAD16_U_I32>;
292327952Sdimdef : LoadPatExternSymOffOnly<i64, extloadi8, LOAD8_U_I64>;
293327952Sdimdef : LoadPatExternSymOffOnly<i64, extloadi16, LOAD16_U_I64>;
294327952Sdimdef : LoadPatExternSymOffOnly<i64, extloadi32, LOAD32_U_I64>;
295296417Sdim
296341825Sdim// Defines atomic and non-atomic stores, regular and truncating
297341825Sdimmulticlass WebAssemblyStore<WebAssemblyRegClass rc, string Name, int Opcode> {
298344779Sdim  let mayStore = 1 in
299341825Sdim  defm "" : I<(outs),
300341825Sdim              (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
301341825Sdim              (outs),
302341825Sdim              (ins P2Align:$p2align, offset32_op:$off), [],
303341825Sdim              !strconcat(Name, "\t${off}(${addr})${p2align}, $val"),
304344779Sdim              !strconcat(Name, "\t${off}${p2align}"), Opcode>;
305341825Sdim}
306296417Sdim// Basic store.
307296417Sdim// Note: WebAssembly inverts SelectionDAG's usual operand order.
308341825Sdimdefm STORE_I32  : WebAssemblyStore<I32, "i32.store", 0x36>;
309341825Sdimdefm STORE_I64  : WebAssemblyStore<I64, "i64.store", 0x37>;
310341825Sdimdefm STORE_F32  : WebAssemblyStore<F32, "f32.store", 0x38>;
311341825Sdimdefm STORE_F64  : WebAssemblyStore<F64, "f64.store", 0x39>;
312296417Sdim
313296417Sdim// Select stores with no constant offset.
314341825Sdimclass StorePatNoOffset<ValueType ty, PatFrag node, NI inst> :
315341825Sdim  Pat<(node ty:$val, I32:$addr), (inst 0, 0, I32:$addr, ty:$val)>;
316296417Sdim
317341825Sdimdef : StorePatNoOffset<i32, store, STORE_I32>;
318341825Sdimdef : StorePatNoOffset<i64, store, STORE_I64>;
319341825Sdimdef : StorePatNoOffset<f32, store, STORE_F32>;
320341825Sdimdef : StorePatNoOffset<f64, store, STORE_F64>;
321341825Sdim
322296417Sdim// Select stores with a constant offset.
323341825Sdimclass StorePatImmOff<ValueType ty, PatFrag kind, PatFrag operand, NI inst> :
324341825Sdim  Pat<(kind ty:$val, (operand I32:$addr, imm:$off)),
325341825Sdim      (inst 0, imm:$off, I32:$addr, ty:$val)>;
326296417Sdim
327341825Sdimdef : StorePatImmOff<i32, store, regPlusImm, STORE_I32>;
328341825Sdimdef : StorePatImmOff<i64, store, regPlusImm, STORE_I64>;
329341825Sdimdef : StorePatImmOff<f32, store, regPlusImm, STORE_F32>;
330341825Sdimdef : StorePatImmOff<f64, store, regPlusImm, STORE_F64>;
331341825Sdimdef : StorePatImmOff<i32, store, or_is_add, STORE_I32>;
332341825Sdimdef : StorePatImmOff<i64, store, or_is_add, STORE_I64>;
333341825Sdimdef : StorePatImmOff<f32, store, or_is_add, STORE_F32>;
334341825Sdimdef : StorePatImmOff<f64, store, or_is_add, STORE_F64>;
335341825Sdim
336341825Sdimclass StorePatGlobalAddr<ValueType ty, PatFrag kind, NI inst> :
337341825Sdim  Pat<(kind ty:$val,
338341825Sdim            (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off))),
339341825Sdim      (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>;
340341825Sdimdef : StorePatGlobalAddr<i32, store, STORE_I32>;
341341825Sdimdef : StorePatGlobalAddr<i64, store, STORE_I64>;
342341825Sdimdef : StorePatGlobalAddr<f32, store, STORE_F32>;
343341825Sdimdef : StorePatGlobalAddr<f64, store, STORE_F64>;
344341825Sdim
345341825Sdimclass StorePatExternalSym<ValueType ty, PatFrag kind, NI inst> :
346341825Sdim  Pat<(kind ty:$val, (add I32:$addr, (WebAssemblywrapper texternalsym:$off))),
347341825Sdim      (inst 0, texternalsym:$off, I32:$addr, ty:$val)>;
348341825Sdimdef : StorePatExternalSym<i32, store, STORE_I32>;
349341825Sdimdef : StorePatExternalSym<i64, store, STORE_I64>;
350341825Sdimdef : StorePatExternalSym<f32, store, STORE_F32>;
351341825Sdimdef : StorePatExternalSym<f64, store, STORE_F64>;
352341825Sdim
353296417Sdim// Select stores with just a constant offset.
354341825Sdimclass StorePatOffsetOnly<ValueType ty, PatFrag kind, NI inst> :
355341825Sdim  Pat<(kind ty:$val, imm:$off), (inst 0, imm:$off, (CONST_I32 0), ty:$val)>;
356341825Sdimdef : StorePatOffsetOnly<i32, store, STORE_I32>;
357341825Sdimdef : StorePatOffsetOnly<i64, store, STORE_I64>;
358341825Sdimdef : StorePatOffsetOnly<f32, store, STORE_F32>;
359341825Sdimdef : StorePatOffsetOnly<f64, store, STORE_F64>;
360296417Sdim
361341825Sdimclass StorePatGlobalAddrOffOnly<ValueType ty, PatFrag kind, NI inst> :
362341825Sdim  Pat<(kind ty:$val, (WebAssemblywrapper tglobaladdr:$off)),
363341825Sdim      (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>;
364341825Sdimdef : StorePatGlobalAddrOffOnly<i32, store, STORE_I32>;
365341825Sdimdef : StorePatGlobalAddrOffOnly<i64, store, STORE_I64>;
366341825Sdimdef : StorePatGlobalAddrOffOnly<f32, store, STORE_F32>;
367341825Sdimdef : StorePatGlobalAddrOffOnly<f64, store, STORE_F64>;
368341825Sdim
369341825Sdimclass StorePatExternSymOffOnly<ValueType ty, PatFrag kind, NI inst> :
370341825Sdim  Pat<(kind ty:$val, (WebAssemblywrapper texternalsym:$off)),
371341825Sdim      (inst 0, texternalsym:$off, (CONST_I32 0), ty:$val)>;
372341825Sdimdef : StorePatExternSymOffOnly<i32, store, STORE_I32>;
373341825Sdimdef : StorePatExternSymOffOnly<i64, store, STORE_I64>;
374341825Sdimdef : StorePatExternSymOffOnly<f32, store, STORE_F32>;
375341825Sdimdef : StorePatExternSymOffOnly<f64, store, STORE_F64>;
376341825Sdim
377296417Sdim// Truncating store.
378341825Sdimdefm STORE8_I32 : WebAssemblyStore<I32, "i32.store8", 0x3a>;
379341825Sdimdefm STORE16_I32 : WebAssemblyStore<I32, "i32.store16", 0x3b>;
380341825Sdimdefm STORE8_I64 : WebAssemblyStore<I64, "i64.store8", 0x3c>;
381341825Sdimdefm STORE16_I64 : WebAssemblyStore<I64, "i64.store16", 0x3d>;
382341825Sdimdefm STORE32_I64 : WebAssemblyStore<I64, "i64.store32", 0x3e>;
383296417Sdim
384296417Sdim// Select truncating stores with no constant offset.
385341825Sdimdef : StorePatNoOffset<i32, truncstorei8, STORE8_I32>;
386341825Sdimdef : StorePatNoOffset<i32, truncstorei16, STORE16_I32>;
387341825Sdimdef : StorePatNoOffset<i64, truncstorei8, STORE8_I64>;
388341825Sdimdef : StorePatNoOffset<i64, truncstorei16, STORE16_I64>;
389341825Sdimdef : StorePatNoOffset<i64, truncstorei32, STORE32_I64>;
390296417Sdim
391296417Sdim// Select truncating stores with a constant offset.
392341825Sdimdef : StorePatImmOff<i32, truncstorei8, regPlusImm, STORE8_I32>;
393341825Sdimdef : StorePatImmOff<i32, truncstorei16, regPlusImm, STORE16_I32>;
394341825Sdimdef : StorePatImmOff<i64, truncstorei8, regPlusImm, STORE8_I64>;
395341825Sdimdef : StorePatImmOff<i64, truncstorei16, regPlusImm, STORE16_I64>;
396341825Sdimdef : StorePatImmOff<i64, truncstorei32, regPlusImm, STORE32_I64>;
397341825Sdimdef : StorePatImmOff<i32, truncstorei8, or_is_add, STORE8_I32>;
398341825Sdimdef : StorePatImmOff<i32, truncstorei16, or_is_add, STORE16_I32>;
399341825Sdimdef : StorePatImmOff<i64, truncstorei8, or_is_add, STORE8_I64>;
400341825Sdimdef : StorePatImmOff<i64, truncstorei16, or_is_add, STORE16_I64>;
401341825Sdimdef : StorePatImmOff<i64, truncstorei32, or_is_add, STORE32_I64>;
402296417Sdim
403341825Sdimdef : StorePatGlobalAddr<i32, truncstorei8, STORE8_I32>;
404341825Sdimdef : StorePatGlobalAddr<i32, truncstorei16, STORE16_I32>;
405341825Sdimdef : StorePatGlobalAddr<i64, truncstorei8, STORE8_I64>;
406341825Sdimdef : StorePatGlobalAddr<i64, truncstorei16, STORE16_I64>;
407341825Sdimdef : StorePatGlobalAddr<i64, truncstorei32, STORE32_I64>;
408341825Sdimdef : StorePatExternalSym<i32, truncstorei8, STORE8_I32>;
409341825Sdimdef : StorePatExternalSym<i32, truncstorei16, STORE16_I32>;
410341825Sdimdef : StorePatExternalSym<i64, truncstorei8, STORE8_I64>;
411341825Sdimdef : StorePatExternalSym<i64, truncstorei16, STORE16_I64>;
412341825Sdimdef : StorePatExternalSym<i64, truncstorei32, STORE32_I64>;
413341825Sdim
414296417Sdim// Select truncating stores with just a constant offset.
415341825Sdimdef : StorePatOffsetOnly<i32, truncstorei8, STORE8_I32>;
416341825Sdimdef : StorePatOffsetOnly<i32, truncstorei16, STORE16_I32>;
417341825Sdimdef : StorePatOffsetOnly<i64, truncstorei8, STORE8_I64>;
418341825Sdimdef : StorePatOffsetOnly<i64, truncstorei16, STORE16_I64>;
419341825Sdimdef : StorePatOffsetOnly<i64, truncstorei32, STORE32_I64>;
420341825Sdimdef : StorePatGlobalAddrOffOnly<i32, truncstorei8, STORE8_I32>;
421341825Sdimdef : StorePatGlobalAddrOffOnly<i32, truncstorei16, STORE16_I32>;
422341825Sdimdef : StorePatGlobalAddrOffOnly<i64, truncstorei8, STORE8_I64>;
423341825Sdimdef : StorePatGlobalAddrOffOnly<i64, truncstorei16, STORE16_I64>;
424341825Sdimdef : StorePatGlobalAddrOffOnly<i64, truncstorei32, STORE32_I64>;
425341825Sdimdef : StorePatExternSymOffOnly<i32, truncstorei8, STORE8_I32>;
426341825Sdimdef : StorePatExternSymOffOnly<i32, truncstorei16, STORE16_I32>;
427341825Sdimdef : StorePatExternSymOffOnly<i64, truncstorei8, STORE8_I64>;
428341825Sdimdef : StorePatExternSymOffOnly<i64, truncstorei16, STORE16_I64>;
429341825Sdimdef : StorePatExternSymOffOnly<i64, truncstorei32, STORE32_I64>;
430296417Sdim
431309124Sdim// Current memory size.
432341825Sdimdefm MEMORY_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags),
433341825Sdim                         (outs), (ins i32imm:$flags),
434341825Sdim                         [(set I32:$dst,
435341825Sdim                           (int_wasm_memory_size (i32 imm:$flags)))],
436341825Sdim                         "memory.size\t$dst, $flags", "memory.size\t$flags",
437341825Sdim                         0x3f>,
438341825Sdim                       Requires<[HasAddr32]>;
439296417Sdim
440296417Sdim// Grow memory.
441341825Sdimdefm MEMORY_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
442344779Sdim                         (outs), (ins i32imm:$flags),
443341825Sdim                         [(set I32:$dst,
444341825Sdim                           (int_wasm_memory_grow (i32 imm:$flags),
445341825Sdim                             I32:$delta))],
446341825Sdim                         "memory.grow\t$dst, $flags, $delta",
447344779Sdim                         "memory.grow\t$flags", 0x40>,
448341825Sdim                       Requires<[HasAddr32]>;
449