WebAssemblyInstrMemory.td revision 327952
1112918Sjeff// WebAssemblyInstrMemory.td-WebAssembly Memory codegen support -*- tablegen -*-
2144518Sdavidxu//
3144518Sdavidxu//                     The LLVM Compiler Infrastructure
4144518Sdavidxu//
5112918Sjeff// This file is distributed under the University of Illinois Open Source
6112918Sjeff// License. See LICENSE.TXT for details.
7112918Sjeff//
8112918Sjeff//===----------------------------------------------------------------------===//
9112918Sjeff///
10112918Sjeff/// \file
11112918Sjeff/// \brief WebAssembly Memory operand code-gen constructs.
12112918Sjeff///
13112918Sjeff//===----------------------------------------------------------------------===//
14112918Sjeff
15112918Sjeff// TODO:
16112918Sjeff//  - HasAddr64
17112918Sjeff//  - WebAssemblyTargetLowering having to do with atomics
18112918Sjeff//  - Each has optional alignment.
19112918Sjeff
20112918Sjeff// WebAssembly has i8/i16/i32/i64/f32/f64 memory types, but doesn't have i8/i16
21112918Sjeff// local types. These memory-only types instead zero- or sign-extend into local
22112918Sjeff// types when loading, and truncate when storing.
23112918Sjeff
24112918Sjeff// WebAssembly constant offsets are performed as unsigned with infinite
25112918Sjeff// precision, so we need to check for NoUnsignedWrap so that we don't fold an
26112918Sjeff// offset for an add that needs wrapping.
27112918Sjeffdef regPlusImm : PatFrag<(ops node:$addr, node:$off),
28112918Sjeff                         (add node:$addr, node:$off),
29112918Sjeff                         [{ return N->getFlags().hasNoUnsignedWrap(); }]>;
30112918Sjeff
31112918Sjeff// Treat an 'or' node as an 'add' if the or'ed bits are known to be zero.
32112918Sjeffdef or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{
33112918Sjeff  if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))
34112918Sjeff    return CurDAG->MaskedValueIsZero(N->getOperand(0), CN->getAPIntValue());
35112918Sjeff
36112918Sjeff  KnownBits Known0;
37112918Sjeff  CurDAG->computeKnownBits(N->getOperand(0), Known0, 0);
38112918Sjeff  KnownBits Known1;
39112918Sjeff  CurDAG->computeKnownBits(N->getOperand(1), Known1, 0);
40112918Sjeff  return (~Known0.Zero & ~Known1.Zero) == 0;
41112918Sjeff}]>;
42112918Sjeff
43112918Sjeff// GlobalAddresses are conceptually unsigned values, so we can also fold them
44112918Sjeff// into immediate values as long as the add is 'nuw'.
45112918Sjeff// TODO: We'd like to also match GA offsets but there are cases where the
46165967Simp// register can have a negative value. Find out what more we can do.
47112918Sjeffdef regPlusGA : PatFrag<(ops node:$addr, node:$off),
48112918Sjeff                        (add node:$addr, node:$off),
49112918Sjeff                        [{
50112918Sjeff  return N->getFlags().hasNoUnsignedWrap();
51112918Sjeff}]>;
52112918Sjeff
53112918Sjeff// We don't need a regPlusES because external symbols never have constant
54112918Sjeff// offsets folded into them, so we can just use add.
55112918Sjeff
56112918Sjefflet Defs = [ARGUMENTS] in {
57112918Sjeff
58112918Sjeff// Defines atomic and non-atomic loads, regular and extending.
59112918Sjeffclass WebAssemblyLoad<WebAssemblyRegClass rc, string Name, int Opcode> :
60112918Sjeff  I<(outs rc:$dst),
61112918Sjeff    (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
62112918Sjeff    [], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"), Opcode>;
63112918Sjeff
64157457Sdavidxu// Basic load.
65144518Sdavidxu// FIXME: When we can break syntax compatibility, reorder the fields in the
66112918Sjeff// asmstrings to match the binary encoding.
67112918Sjeffdef LOAD_I32 : WebAssemblyLoad<I32, "i32.load", 0x28>;
68112918Sjeffdef LOAD_I64 : WebAssemblyLoad<I64, "i64.load", 0x29>;
69144518Sdavidxudef LOAD_F32 : WebAssemblyLoad<F32, "f32.load", 0x2a>;
70135301Smtmdef LOAD_F64 : WebAssemblyLoad<F64, "f64.load", 0x2b>;
71144518Sdavidxu
72112918Sjeff} // Defs = [ARGUMENTS]
73112918Sjeff
74112918Sjeff// Select loads with no constant offset.
75112918Sjeffclass LoadPatNoOffset<ValueType ty, PatFrag node, I inst> :
76112918Sjeff  Pat<(ty (node I32:$addr)), (inst 0, 0, $addr)>;
77112918Sjeff
78112918Sjeffdef : LoadPatNoOffset<i32, load, LOAD_I32>;
79112918Sjeffdef : LoadPatNoOffset<i64, load, LOAD_I64>;
80112918Sjeffdef : LoadPatNoOffset<f32, load, LOAD_F32>;
81112918Sjeffdef : LoadPatNoOffset<f64, load, LOAD_F64>;
82112918Sjeff
83112918Sjeff
84112918Sjeff// Select loads with a constant offset.
85112918Sjeff
86112918Sjeff// Pattern with address + immediate offset
87144518Sdavidxuclass LoadPatImmOff<ValueType ty, PatFrag loadkind, PatFrag operand, I inst> :
88157457Sdavidxu  Pat<(ty (loadkind (operand I32:$addr, imm:$off))),
89112918Sjeff      (inst 0, imm:$off, $addr)>;
90112918Sjeff
91112918Sjeffdef : LoadPatImmOff<i32, load, regPlusImm, LOAD_I32>;
92157457Sdavidxudef : LoadPatImmOff<i64, load, regPlusImm, LOAD_I64>;
93157457Sdavidxudef : LoadPatImmOff<f32, load, regPlusImm, LOAD_F32>;
94157457Sdavidxudef : LoadPatImmOff<f64, load, regPlusImm, LOAD_F64>;
95157457Sdavidxudef : LoadPatImmOff<i32, load, or_is_add, LOAD_I32>;
96157457Sdavidxudef : LoadPatImmOff<i64, load, or_is_add, LOAD_I64>;
97157457Sdavidxudef : LoadPatImmOff<f32, load, or_is_add, LOAD_F32>;
98157457Sdavidxudef : LoadPatImmOff<f64, load, or_is_add, LOAD_F64>;
99157457Sdavidxu
100157457Sdavidxuclass LoadPatGlobalAddr<ValueType ty, PatFrag loadkind, I inst> :
101157457Sdavidxu  Pat<(ty (loadkind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)))),
102157457Sdavidxu      (inst 0, tglobaladdr:$off, $addr)>;
103157457Sdavidxu
104157457Sdavidxudef : LoadPatGlobalAddr<i32, load, LOAD_I32>;
105157457Sdavidxudef : LoadPatGlobalAddr<i64, load, LOAD_I64>;
106157457Sdavidxudef : LoadPatGlobalAddr<f32, load, LOAD_F32>;
107157457Sdavidxudef : LoadPatGlobalAddr<f64, load, LOAD_F64>;
108157457Sdavidxu
109157457Sdavidxuclass LoadPatExternalSym<ValueType ty, PatFrag loadkind, I inst> :
110157457Sdavidxu  Pat<(ty (loadkind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))),
111157457Sdavidxu      (inst 0, texternalsym:$off, $addr)>;
112157457Sdavidxudef : LoadPatExternalSym<i32, load, LOAD_I32>;
113157457Sdavidxudef : LoadPatExternalSym<i64, load, LOAD_I64>;
114157457Sdavidxudef : LoadPatExternalSym<f32, load, LOAD_F32>;
115157457Sdavidxudef : LoadPatExternalSym<f64, load, LOAD_F64>;
116157457Sdavidxu
117157457Sdavidxu
118157457Sdavidxu// Select loads with just a constant offset.
119115260Smtmclass LoadPatOffsetOnly<ValueType ty, PatFrag loadkind, I inst> :
120157457Sdavidxu  Pat<(ty (loadkind imm:$off)), (inst 0, imm:$off, (CONST_I32 0))>;
121160662Sdavidxu
122160662Sdavidxudef : LoadPatOffsetOnly<i32, load, LOAD_I32>;
123160662Sdavidxudef : LoadPatOffsetOnly<i64, load, LOAD_I64>;
124160662Sdavidxudef : LoadPatOffsetOnly<f32, load, LOAD_F32>;
125160662Sdavidxudef : LoadPatOffsetOnly<f64, load, LOAD_F64>;
126160662Sdavidxu
127160662Sdavidxuclass LoadPatGlobalAddrOffOnly<ValueType ty, PatFrag loadkind, I inst> :
128160662Sdavidxu  Pat<(ty (loadkind (WebAssemblywrapper tglobaladdr:$off))),
129157457Sdavidxu      (inst 0, tglobaladdr:$off, (CONST_I32 0))>;
130160662Sdavidxu
131160662Sdavidxudef : LoadPatGlobalAddrOffOnly<i32, load, LOAD_I32>;
132157457Sdavidxudef : LoadPatGlobalAddrOffOnly<i64, load, LOAD_I64>;
133157457Sdavidxudef : LoadPatGlobalAddrOffOnly<f32, load, LOAD_F32>;
134157457Sdavidxudef : LoadPatGlobalAddrOffOnly<f64, load, LOAD_F64>;
135189549Sdavidxu
136179434Sdfrclass LoadPatExternSymOffOnly<ValueType ty, PatFrag loadkind, I inst> :
137189549Sdavidxu  Pat<(ty (loadkind (WebAssemblywrapper texternalsym:$off))),
138157457Sdavidxu      (inst 0, texternalsym:$off, (CONST_I32 0))>;
139157457Sdavidxudef : LoadPatExternSymOffOnly<i32, load, LOAD_I32>;
140157457Sdavidxudef : LoadPatExternSymOffOnly<i64, load, LOAD_I64>;
141157457Sdavidxudef : LoadPatExternSymOffOnly<f32, load, LOAD_F32>;
142157457Sdavidxudef : LoadPatExternSymOffOnly<f64, load, LOAD_F64>;
143157457Sdavidxu
144157457Sdavidxulet Defs = [ARGUMENTS] in {
145157457Sdavidxu
146157457Sdavidxu// Extending load.
147157457Sdavidxudef LOAD8_S_I32 : WebAssemblyLoad<I32, "i32.load8_s", 0x2c>;
148157457Sdavidxudef LOAD8_U_I32 : WebAssemblyLoad<I32, "i32.load8_u", 0x2d>;
149157457Sdavidxudef LOAD16_S_I32 : WebAssemblyLoad<I32, "i32.load16_s", 0x2e>;
150157457Sdavidxudef LOAD16_U_I32 : WebAssemblyLoad<I32, "i32.load16_u", 0x2f>;
151160662Sdavidxudef LOAD8_S_I64 : WebAssemblyLoad<I64, "i64.load8_s", 0x30>;
152157457Sdavidxudef LOAD8_U_I64 : WebAssemblyLoad<I64, "i64.load8_u", 0x31>;
153157457Sdavidxudef LOAD16_S_I64 : WebAssemblyLoad<I64, "i64.load16_s", 0x32>;
154157457Sdavidxudef LOAD16_U_I64 : WebAssemblyLoad<I64, "i64.load16_u", 0x32>;
155157457Sdavidxudef LOAD32_S_I64 : WebAssemblyLoad<I64, "i64.load32_s", 0x34>;
156144518Sdavidxudef LOAD32_U_I64 : WebAssemblyLoad<I64, "i64.load32_u", 0x35>;
157157457Sdavidxu
158135301Smtm} // Defs = [ARGUMENTS]
159144518Sdavidxu
160135301Smtm// Select extending loads with no constant offset.
161144518Sdavidxudef : LoadPatNoOffset<i32, sextloadi8, LOAD8_S_I32>;
162135301Smtmdef : LoadPatNoOffset<i32, zextloadi8, LOAD8_U_I32>;
163135301Smtmdef : LoadPatNoOffset<i32, sextloadi16, LOAD16_S_I32>;
164144518Sdavidxudef : LoadPatNoOffset<i32, zextloadi16, LOAD16_U_I32>;
165164583Sdavidxudef : LoadPatNoOffset<i64, sextloadi8, LOAD8_S_I64>;
166135301Smtmdef : LoadPatNoOffset<i64, zextloadi8, LOAD8_U_I64>;
167164583Sdavidxudef : LoadPatNoOffset<i64, sextloadi16, LOAD16_S_I64>;
168144518Sdavidxudef : LoadPatNoOffset<i64, zextloadi16, LOAD16_U_I64>;
169144518Sdavidxudef : LoadPatNoOffset<i64, sextloadi32, LOAD32_S_I64>;
170135301Smtmdef : LoadPatNoOffset<i64, zextloadi32, LOAD32_U_I64>;
171135301Smtm
172160662Sdavidxu// Select extending loads with a constant offset.
173112918Sjeffdef : LoadPatImmOff<i32, sextloadi8, regPlusImm, LOAD8_S_I32>;
174112918Sjeffdef : LoadPatImmOff<i32, zextloadi8, regPlusImm, LOAD8_U_I32>;
175160662Sdavidxudef : LoadPatImmOff<i32, sextloadi16, regPlusImm, LOAD16_S_I32>;
176112918Sjeffdef : LoadPatImmOff<i32, zextloadi16, regPlusImm, LOAD16_U_I32>;
177112918Sjeffdef : LoadPatImmOff<i64, sextloadi8, regPlusImm, LOAD8_S_I64>;
178144518Sdavidxudef : LoadPatImmOff<i64, zextloadi8, regPlusImm, LOAD8_U_I64>;
179144518Sdavidxudef : LoadPatImmOff<i64, sextloadi16, regPlusImm, LOAD16_S_I64>;
180112918Sjeffdef : LoadPatImmOff<i64, zextloadi16, regPlusImm, LOAD16_U_I64>;
181164583Sdavidxudef : LoadPatImmOff<i64, sextloadi32, regPlusImm, LOAD32_S_I64>;
182112918Sjeffdef : LoadPatImmOff<i64, zextloadi32, regPlusImm, LOAD32_U_I64>;
183164583Sdavidxu
184112918Sjeffdef : LoadPatImmOff<i32, sextloadi8, or_is_add, LOAD8_S_I32>;
185144518Sdavidxudef : LoadPatImmOff<i32, zextloadi8, or_is_add, LOAD8_U_I32>;
186112918Sjeffdef : LoadPatImmOff<i32, sextloadi16, or_is_add, LOAD16_S_I32>;
187112918Sjeffdef : LoadPatImmOff<i32, zextloadi16, or_is_add, LOAD16_U_I32>;
188144518Sdavidxudef : LoadPatImmOff<i64, sextloadi8, or_is_add, LOAD8_S_I64>;
189112918Sjeffdef : LoadPatImmOff<i64, zextloadi8, or_is_add, LOAD8_U_I64>;
190112918Sjeffdef : LoadPatImmOff<i64, sextloadi16, or_is_add, LOAD16_S_I64>;
191144518Sdavidxudef : LoadPatImmOff<i64, zextloadi16, or_is_add, LOAD16_U_I64>;
192112918Sjeffdef : LoadPatImmOff<i64, sextloadi32, or_is_add, LOAD32_S_I64>;
193144518Sdavidxudef : LoadPatImmOff<i64, zextloadi32, or_is_add, LOAD32_U_I64>;
194112918Sjeff
195112918Sjeffdef : LoadPatGlobalAddr<i32, sextloadi8, LOAD8_S_I32>;
196164583Sdavidxudef : LoadPatGlobalAddr<i32, zextloadi8, LOAD8_U_I32>;
197112918Sjeffdef : LoadPatGlobalAddr<i32, sextloadi16, LOAD16_S_I32>;
198164583Sdavidxudef : LoadPatGlobalAddr<i32, zextloadi8, LOAD16_U_I32>;
199112918Sjeff
200144518Sdavidxudef : LoadPatGlobalAddr<i64, sextloadi8, LOAD8_S_I64>;
201112918Sjeffdef : LoadPatGlobalAddr<i64, zextloadi8, LOAD8_U_I64>;
202135301Smtmdef : LoadPatGlobalAddr<i64, sextloadi16, LOAD16_S_I64>;
203144518Sdavidxudef : LoadPatGlobalAddr<i64, zextloadi16, LOAD16_U_I64>;
204135301Smtmdef : LoadPatGlobalAddr<i64, sextloadi32, LOAD32_S_I64>;
205135301Smtmdef : LoadPatGlobalAddr<i64, zextloadi32, LOAD32_U_I64>;
206144518Sdavidxu
207135301Smtmdef : LoadPatExternalSym<i32, sextloadi8, LOAD8_S_I32>;
208144518Sdavidxudef : LoadPatExternalSym<i32, zextloadi8, LOAD8_U_I32>;
209135301Smtmdef : LoadPatExternalSym<i32, sextloadi16, LOAD16_S_I32>;
210135301Smtmdef : LoadPatExternalSym<i32, zextloadi16, LOAD16_U_I32>;
211164583Sdavidxudef : LoadPatExternalSym<i64, sextloadi8, LOAD8_S_I64>;
212144518Sdavidxudef : LoadPatExternalSym<i64, zextloadi8, LOAD8_U_I64>;
213164583Sdavidxudef : LoadPatExternalSym<i64, sextloadi16, LOAD16_S_I64>;
214144518Sdavidxudef : LoadPatExternalSym<i64, zextloadi16, LOAD16_U_I64>;
215144518Sdavidxudef : LoadPatExternalSym<i64, sextloadi32, LOAD32_S_I64>;
216135301Smtmdef : LoadPatExternalSym<i64, zextloadi32, LOAD32_U_I64>;
217112918Sjeff
218144518Sdavidxu
219144518Sdavidxu// Select extending loads with just a constant offset.
220112918Sjeffdef : LoadPatOffsetOnly<i32, sextloadi8, LOAD8_S_I32>;
221144518Sdavidxudef : LoadPatOffsetOnly<i32, zextloadi8, LOAD8_U_I32>;
222112918Sjeffdef : LoadPatOffsetOnly<i32, sextloadi16, LOAD16_S_I32>;
223144518Sdavidxudef : LoadPatOffsetOnly<i32, zextloadi16, LOAD16_U_I32>;
224144518Sdavidxu
225112918Sjeffdef : LoadPatOffsetOnly<i64, sextloadi8, LOAD8_S_I64>;
226164583Sdavidxudef : LoadPatOffsetOnly<i64, zextloadi8, LOAD8_U_I64>;
227112918Sjeffdef : LoadPatOffsetOnly<i64, sextloadi16, LOAD16_S_I64>;
228164583Sdavidxudef : LoadPatOffsetOnly<i64, zextloadi16, LOAD16_U_I64>;
229112918Sjeffdef : LoadPatOffsetOnly<i64, sextloadi32, LOAD32_S_I64>;
230112918Sjeffdef : LoadPatOffsetOnly<i64, zextloadi32, LOAD32_U_I64>;
231112918Sjeff
232112918Sjeffdef : LoadPatGlobalAddrOffOnly<i32, sextloadi8, LOAD8_S_I32>;
233144518Sdavidxudef : LoadPatGlobalAddrOffOnly<i32, zextloadi8, LOAD8_U_I32>;
234112918Sjeffdef : LoadPatGlobalAddrOffOnly<i32, sextloadi16, LOAD16_S_I32>;
235112918Sjeffdef : LoadPatGlobalAddrOffOnly<i32, zextloadi16, LOAD16_U_I32>;
236144518Sdavidxudef : LoadPatGlobalAddrOffOnly<i64, sextloadi8, LOAD8_S_I64>;
237112918Sjeffdef : LoadPatGlobalAddrOffOnly<i64, zextloadi8, LOAD8_U_I64>;
238144518Sdavidxudef : LoadPatGlobalAddrOffOnly<i64, sextloadi16, LOAD16_S_I64>;
239112918Sjeffdef : LoadPatGlobalAddrOffOnly<i64, zextloadi16, LOAD16_U_I64>;
240112918Sjeffdef : LoadPatGlobalAddrOffOnly<i64, sextloadi32, LOAD32_S_I64>;
241112918Sjeffdef : LoadPatGlobalAddrOffOnly<i64, zextloadi32, LOAD32_U_I64>;
242164583Sdavidxu
243112918Sjeffdef : LoadPatExternSymOffOnly<i32, sextloadi8, LOAD8_S_I32>;
244112918Sjeffdef : LoadPatExternSymOffOnly<i32, zextloadi8, LOAD8_U_I32>;
245112918Sjeffdef : LoadPatExternSymOffOnly<i32, sextloadi16, LOAD16_S_I32>;
246144518Sdavidxudef : LoadPatExternSymOffOnly<i32, zextloadi16, LOAD16_U_I32>;
247144518Sdavidxudef : LoadPatExternSymOffOnly<i64, sextloadi8, LOAD8_S_I64>;
248144518Sdavidxudef : LoadPatExternSymOffOnly<i64, zextloadi8, LOAD8_U_I64>;
249144518Sdavidxudef : LoadPatExternSymOffOnly<i64, sextloadi16, LOAD16_S_I64>;
250144518Sdavidxudef : LoadPatExternSymOffOnly<i64, zextloadi16, LOAD16_U_I64>;
251144518Sdavidxudef : LoadPatExternSymOffOnly<i64, sextloadi32, LOAD32_S_I64>;
252144518Sdavidxudef : LoadPatExternSymOffOnly<i64, zextloadi32, LOAD32_U_I64>;
253144518Sdavidxu
254144518Sdavidxu// Resolve "don't care" extending loads to zero-extending loads. This is
255144518Sdavidxu// somewhat arbitrary, but zero-extending is conceptually simpler.
256144518Sdavidxu
257144518Sdavidxu// Select "don't care" extending loads with no constant offset.
258189549Sdavidxudef : LoadPatNoOffset<i32, extloadi8, LOAD8_U_I32>;
259179434Sdfrdef : LoadPatNoOffset<i32, extloadi16, LOAD16_U_I32>;
260189549Sdavidxudef : LoadPatNoOffset<i64, extloadi8, LOAD8_U_I64>;
261189549Sdavidxudef : LoadPatNoOffset<i64, extloadi16, LOAD16_U_I64>;
262189549Sdavidxudef : LoadPatNoOffset<i64, extloadi32, LOAD32_U_I64>;
263112918Sjeff
264112918Sjeff// Select "don't care" extending loads with a constant offset.
265112918Sjeffdef : LoadPatImmOff<i32, extloadi8, regPlusImm, LOAD8_U_I32>;
266164583Sdavidxudef : LoadPatImmOff<i32, extloadi16, regPlusImm, LOAD16_U_I32>;
267112918Sjeffdef : LoadPatImmOff<i64, extloadi8, regPlusImm, LOAD8_U_I64>;
268144518Sdavidxudef : LoadPatImmOff<i64, extloadi16, regPlusImm, LOAD16_U_I64>;
269112918Sjeffdef : LoadPatImmOff<i64, extloadi32, regPlusImm, LOAD32_U_I64>;
270112918Sjeffdef : LoadPatImmOff<i32, extloadi8, or_is_add, LOAD8_U_I32>;
271144518Sdavidxudef : LoadPatImmOff<i32, extloadi16, or_is_add, LOAD16_U_I32>;
272131181Smtmdef : LoadPatImmOff<i64, extloadi8, or_is_add, LOAD8_U_I64>;
273131181Smtmdef : LoadPatImmOff<i64, extloadi16, or_is_add, LOAD16_U_I64>;
274144518Sdavidxudef : LoadPatImmOff<i64, extloadi32, or_is_add, LOAD32_U_I64>;
275131181Smtmdef : LoadPatGlobalAddr<i32, extloadi8, LOAD8_U_I32>;
276144518Sdavidxudef : LoadPatGlobalAddr<i32, extloadi16, LOAD16_U_I32>;
277131181Smtmdef : LoadPatGlobalAddr<i64, extloadi8, LOAD8_U_I64>;
278131181Smtmdef : LoadPatGlobalAddr<i64, extloadi16, LOAD16_U_I64>;
279164583Sdavidxudef : LoadPatGlobalAddr<i64, extloadi32, LOAD32_U_I64>;
280112918Sjeffdef : LoadPatExternalSym<i32, extloadi8, LOAD8_U_I32>;
281164583Sdavidxudef : LoadPatExternalSym<i32, extloadi16, LOAD16_U_I32>;
282112918Sjeffdef : LoadPatExternalSym<i64, extloadi8, LOAD8_U_I64>;
283144518Sdavidxudef : LoadPatExternalSym<i64, extloadi16, LOAD16_U_I64>;
284112918Sjeffdef : LoadPatExternalSym<i64, extloadi32, LOAD32_U_I64>;
285112918Sjeff
286144518Sdavidxu// Select "don't care" extending loads with just a constant offset.
287135301Smtmdef : LoadPatOffsetOnly<i32, extloadi8, LOAD8_U_I32>;
288135301Smtmdef : LoadPatOffsetOnly<i32, extloadi16, LOAD16_U_I32>;
289144518Sdavidxudef : LoadPatOffsetOnly<i64, extloadi8, LOAD8_U_I64>;
290135301Smtmdef : LoadPatOffsetOnly<i64, extloadi16, LOAD16_U_I64>;
291144518Sdavidxudef : LoadPatOffsetOnly<i64, extloadi32, LOAD32_U_I64>;
292112918Sjeffdef : LoadPatGlobalAddrOffOnly<i32, extloadi8, LOAD8_U_I32>;
293112918Sjeffdef : LoadPatGlobalAddrOffOnly<i32, extloadi16, LOAD16_U_I32>;
294164583Sdavidxudef : LoadPatGlobalAddrOffOnly<i64, extloadi8, LOAD8_U_I64>;
295112918Sjeffdef : LoadPatGlobalAddrOffOnly<i64, extloadi16, LOAD16_U_I64>;
296164583Sdavidxudef : LoadPatGlobalAddrOffOnly<i64, extloadi32, LOAD32_U_I64>;
297112918Sjeffdef : LoadPatExternSymOffOnly<i32, extloadi8, LOAD8_U_I32>;
298112918Sjeffdef : LoadPatExternSymOffOnly<i32, extloadi16, LOAD16_U_I32>;
299112918Sjeffdef : LoadPatExternSymOffOnly<i64, extloadi8, LOAD8_U_I64>;
300112918Sjeffdef : LoadPatExternSymOffOnly<i64, extloadi16, LOAD16_U_I64>;
301144518Sdavidxudef : LoadPatExternSymOffOnly<i64, extloadi32, LOAD32_U_I64>;
302112918Sjeff
303112918Sjeff
304144518Sdavidxulet Defs = [ARGUMENTS] in {
305144518Sdavidxu
306112918Sjeff// Basic store.
307144518Sdavidxu// Note: WebAssembly inverts SelectionDAG's usual operand order.
308144518Sdavidxudef STORE_I32  : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
309112918Sjeff                            I32:$val), [],
310164583Sdavidxu                   "i32.store\t${off}(${addr})${p2align}, $val", 0x36>;
311112918Sjeffdef STORE_I64  : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
312164583Sdavidxu                            I64:$val), [],
313112918Sjeff                   "i64.store\t${off}(${addr})${p2align}, $val", 0x37>;
314144518Sdavidxudef STORE_F32  : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
315112918Sjeff                            F32:$val), [],
316112918Sjeff                   "f32.store\t${off}(${addr})${p2align}, $val", 0x38>;
317144518Sdavidxudef STORE_F64  : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
318112918Sjeff                            F64:$val), [],
319112918Sjeff                   "f64.store\t${off}(${addr})${p2align}, $val", 0x39>;
320144518Sdavidxu
321112918Sjeff} // Defs = [ARGUMENTS]
322144518Sdavidxu
323112918Sjeff// Select stores with no constant offset.
324112918Sjeffdef : Pat<(store I32:$val, I32:$addr), (STORE_I32 0, 0, I32:$addr, I32:$val)>;
325112918Sjeffdef : Pat<(store I64:$val, I32:$addr), (STORE_I64 0, 0, I32:$addr, I64:$val)>;
326112918Sjeffdef : Pat<(store F32:$val, I32:$addr), (STORE_F32 0, 0, I32:$addr, F32:$val)>;
327164583Sdavidxudef : Pat<(store F64:$val, I32:$addr), (STORE_F64 0, 0, I32:$addr, F64:$val)>;
328112918Sjeff
329112918Sjeff// Select stores with a constant offset.
330112918Sjeffdef : Pat<(store I32:$val, (regPlusImm I32:$addr, imm:$off)),
331112918Sjeff          (STORE_I32 0, imm:$off, I32:$addr, I32:$val)>;
332112918Sjeffdef : Pat<(store I64:$val, (regPlusImm I32:$addr, imm:$off)),
333112918Sjeff          (STORE_I64 0, imm:$off, I32:$addr, I64:$val)>;
334112918Sjeffdef : Pat<(store F32:$val, (regPlusImm I32:$addr, imm:$off)),
335112918Sjeff          (STORE_F32 0, imm:$off, I32:$addr, F32:$val)>;
336112918Sjeffdef : Pat<(store F64:$val, (regPlusImm I32:$addr, imm:$off)),
337112918Sjeff          (STORE_F64 0, imm:$off, I32:$addr, F64:$val)>;
338112918Sjeffdef : Pat<(store I32:$val, (or_is_add I32:$addr, imm:$off)),
339164583Sdavidxu          (STORE_I32 0, imm:$off, I32:$addr, I32:$val)>;
340144518Sdavidxudef : Pat<(store I64:$val, (or_is_add I32:$addr, imm:$off)),
341112918Sjeff          (STORE_I64 0, imm:$off, I32:$addr, I64:$val)>;
342112918Sjeffdef : Pat<(store F32:$val, (or_is_add I32:$addr, imm:$off)),
343112918Sjeff          (STORE_F32 0, imm:$off, I32:$addr, F32:$val)>;
344144518Sdavidxudef : Pat<(store F64:$val, (or_is_add I32:$addr, imm:$off)),
345112918Sjeff          (STORE_F64 0, imm:$off, I32:$addr, F64:$val)>;
346112918Sjeffdef : Pat<(store I32:$val, (regPlusGA I32:$addr,
347144518Sdavidxu                                      (WebAssemblywrapper tglobaladdr:$off))),
348112918Sjeff          (STORE_I32 0, tglobaladdr:$off, I32:$addr, I32:$val)>;
349144518Sdavidxudef : Pat<(store I64:$val, (regPlusGA I32:$addr,
350112918Sjeff                                      (WebAssemblywrapper tglobaladdr:$off))),
351112918Sjeff          (STORE_I64 0, tglobaladdr:$off, I32:$addr, I64:$val)>;
352164583Sdavidxudef : Pat<(store F32:$val, (regPlusGA I32:$addr,
353112918Sjeff                                      (WebAssemblywrapper tglobaladdr:$off))),
354164583Sdavidxu          (STORE_F32 0, tglobaladdr:$off, I32:$addr, F32:$val)>;
355112918Sjeffdef : Pat<(store F64:$val, (regPlusGA I32:$addr,
356112918Sjeff                                      (WebAssemblywrapper tglobaladdr:$off))),
357112918Sjeff          (STORE_F64 0, tglobaladdr:$off, I32:$addr, F64:$val)>;
358112918Sjeffdef : Pat<(store I32:$val, (add I32:$addr,
359160662Sdavidxu                                (WebAssemblywrapper texternalsym:$off))),
360135301Smtm          (STORE_I32 0, texternalsym:$off, I32:$addr, I32:$val)>;
361112918Sjeffdef : Pat<(store I64:$val, (add I32:$addr,
362160662Sdavidxu                                (WebAssemblywrapper texternalsym:$off))),
363112918Sjeff          (STORE_I64 0, texternalsym:$off, I32:$addr, I64:$val)>;
364112918Sjeffdef : Pat<(store F32:$val, (add I32:$addr,
365144518Sdavidxu                                (WebAssemblywrapper texternalsym:$off))),
366112918Sjeff          (STORE_F32 0, texternalsym:$off, I32:$addr, F32:$val)>;
367112918Sjeffdef : Pat<(store F64:$val, (add I32:$addr,
368164583Sdavidxu                                (WebAssemblywrapper texternalsym:$off))),
369112918Sjeff          (STORE_F64 0, texternalsym:$off, I32:$addr, F64:$val)>;
370164583Sdavidxu
371112918Sjeff// Select stores with just a constant offset.
372112918Sjeffdef : Pat<(store I32:$val, imm:$off),
373112918Sjeff          (STORE_I32 0, imm:$off, (CONST_I32 0), I32:$val)>;
374112918Sjeffdef : Pat<(store I64:$val, imm:$off),
375144518Sdavidxu          (STORE_I64 0, imm:$off, (CONST_I32 0), I64:$val)>;
376112918Sjeffdef : Pat<(store F32:$val, imm:$off),
377112918Sjeff          (STORE_F32 0, imm:$off, (CONST_I32 0), F32:$val)>;
378144518Sdavidxudef : Pat<(store F64:$val, imm:$off),
379112918Sjeff          (STORE_F64 0, imm:$off, (CONST_I32 0), F64:$val)>;
380144518Sdavidxudef : Pat<(store I32:$val, (WebAssemblywrapper tglobaladdr:$off)),
381112918Sjeff          (STORE_I32 0, tglobaladdr:$off, (CONST_I32 0), I32:$val)>;
382112918Sjeffdef : Pat<(store I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
383164583Sdavidxu          (STORE_I64 0, tglobaladdr:$off, (CONST_I32 0), I64:$val)>;
384112918Sjeffdef : Pat<(store F32:$val, (WebAssemblywrapper tglobaladdr:$off)),
385164583Sdavidxu          (STORE_F32 0, tglobaladdr:$off, (CONST_I32 0), F32:$val)>;
386112918Sjeffdef : Pat<(store F64:$val, (WebAssemblywrapper tglobaladdr:$off)),
387112918Sjeff          (STORE_F64 0, tglobaladdr:$off, (CONST_I32 0), F64:$val)>;
388112918Sjeffdef : Pat<(store I32:$val, (WebAssemblywrapper texternalsym:$off)),
389112918Sjeff          (STORE_I32 0, texternalsym:$off, (CONST_I32 0), I32:$val)>;
390144518Sdavidxudef : Pat<(store I64:$val, (WebAssemblywrapper texternalsym:$off)),
391112918Sjeff          (STORE_I64 0, texternalsym:$off, (CONST_I32 0), I64:$val)>;
392112918Sjeffdef : Pat<(store F32:$val, (WebAssemblywrapper texternalsym:$off)),
393144518Sdavidxu          (STORE_F32 0, texternalsym:$off, (CONST_I32 0), F32:$val)>;
394112918Sjeffdef : Pat<(store F64:$val, (WebAssemblywrapper texternalsym:$off)),
395144518Sdavidxu          (STORE_F64 0, texternalsym:$off, (CONST_I32 0), F64:$val)>;
396112918Sjeff
397112918Sjefflet Defs = [ARGUMENTS] in {
398164583Sdavidxu
399112918Sjeff// Truncating store.
400164583Sdavidxudef STORE8_I32  : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
401112918Sjeff                             I32:$val), [],
402112918Sjeff                    "i32.store8\t${off}(${addr})${p2align}, $val", 0x3a>;
403112918Sjeffdef STORE16_I32 : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
404112918Sjeff                             I32:$val), [],
405144518Sdavidxu                    "i32.store16\t${off}(${addr})${p2align}, $val", 0x3b>;
406135301Smtmdef STORE8_I64  : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
407135301Smtm                             I64:$val), [],
408144518Sdavidxu                    "i64.store8\t${off}(${addr})${p2align}, $val", 0x3c>;
409135301Smtmdef STORE16_I64 : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
410135301Smtm                             I64:$val), [],
411144518Sdavidxu                    "i64.store16\t${off}(${addr})${p2align}, $val", 0x3d>;
412135301Smtmdef STORE32_I64 : I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr,
413135301Smtm                             I64:$val), [],
414164583Sdavidxu                    "i64.store32\t${off}(${addr})${p2align}, $val", 0x3e>;
415135301Smtm
416164583Sdavidxu} // Defs = [ARGUMENTS]
417135301Smtm
418135301Smtm// Select truncating stores with no constant offset.
419135301Smtmdef : Pat<(truncstorei8 I32:$val, I32:$addr),
420144518Sdavidxu          (STORE8_I32 0, 0, I32:$addr, I32:$val)>;
421135301Smtmdef : Pat<(truncstorei16 I32:$val, I32:$addr),
422135301Smtm          (STORE16_I32 0, 0, I32:$addr, I32:$val)>;
423144518Sdavidxudef : Pat<(truncstorei8 I64:$val, I32:$addr),
424135301Smtm          (STORE8_I64 0, 0, I32:$addr, I64:$val)>;
425144518Sdavidxudef : Pat<(truncstorei16 I64:$val, I32:$addr),
426135301Smtm          (STORE16_I64 0, 0, I32:$addr, I64:$val)>;
427135301Smtmdef : Pat<(truncstorei32 I64:$val, I32:$addr),
428164583Sdavidxu          (STORE32_I64 0, 0, I32:$addr, I64:$val)>;
429135301Smtm
430164583Sdavidxu// Select truncating stores with a constant offset.
431135301Smtmdef : Pat<(truncstorei8 I32:$val, (regPlusImm I32:$addr, imm:$off)),
432135301Smtm          (STORE8_I32 0, imm:$off, I32:$addr, I32:$val)>;
433135301Smtmdef : Pat<(truncstorei16 I32:$val, (regPlusImm I32:$addr, imm:$off)),
434144518Sdavidxu          (STORE16_I32 0, imm:$off, I32:$addr, I32:$val)>;
435112918Sjeffdef : Pat<(truncstorei8 I64:$val, (regPlusImm I32:$addr, imm:$off)),
436112918Sjeff          (STORE8_I64 0, imm:$off, I32:$addr, I64:$val)>;
437144518Sdavidxudef : Pat<(truncstorei16 I64:$val, (regPlusImm I32:$addr, imm:$off)),
438112918Sjeff          (STORE16_I64 0, imm:$off, I32:$addr, I64:$val)>;
439112918Sjeffdef : Pat<(truncstorei32 I64:$val, (regPlusImm I32:$addr, imm:$off)),
440144518Sdavidxu          (STORE32_I64 0, imm:$off, I32:$addr, I64:$val)>;
441112918Sjeffdef : Pat<(truncstorei8 I32:$val, (or_is_add I32:$addr, imm:$off)),
442112918Sjeff          (STORE8_I32 0, imm:$off, I32:$addr, I32:$val)>;
443164583Sdavidxudef : Pat<(truncstorei16 I32:$val, (or_is_add I32:$addr, imm:$off)),
444112918Sjeff          (STORE16_I32 0, imm:$off, I32:$addr, I32:$val)>;
445164583Sdavidxudef : Pat<(truncstorei8 I64:$val, (or_is_add I32:$addr, imm:$off)),
446112918Sjeff          (STORE8_I64 0, imm:$off, I32:$addr, I64:$val)>;
447112918Sjeffdef : Pat<(truncstorei16 I64:$val, (or_is_add I32:$addr, imm:$off)),
448112918Sjeff          (STORE16_I64 0, imm:$off, I32:$addr, I64:$val)>;
449144518Sdavidxudef : Pat<(truncstorei32 I64:$val, (or_is_add I32:$addr, imm:$off)),
450135301Smtm          (STORE32_I64 0, imm:$off, I32:$addr, I64:$val)>;
451135301Smtmdef : Pat<(truncstorei8 I32:$val,
452144518Sdavidxu                        (regPlusGA I32:$addr,
453135301Smtm                                   (WebAssemblywrapper tglobaladdr:$off))),
454144518Sdavidxu          (STORE8_I32 0, tglobaladdr:$off, I32:$addr, I32:$val)>;
455135301Smtmdef : Pat<(truncstorei16 I32:$val,
456135301Smtm                         (regPlusGA I32:$addr,
457164583Sdavidxu                                    (WebAssemblywrapper tglobaladdr:$off))),
458135301Smtm          (STORE16_I32 0, tglobaladdr:$off, I32:$addr, I32:$val)>;
459164583Sdavidxudef : Pat<(truncstorei8 I64:$val,
460135301Smtm                        (regPlusGA I32:$addr,
461135301Smtm                                   (WebAssemblywrapper tglobaladdr:$off))),
462135301Smtm          (STORE8_I64 0, tglobaladdr:$off, I32:$addr, I64:$val)>;
463144518Sdavidxudef : Pat<(truncstorei16 I64:$val,
464135301Smtm                         (regPlusGA I32:$addr,
465135301Smtm                                    (WebAssemblywrapper tglobaladdr:$off))),
466144518Sdavidxu          (STORE16_I64 0, tglobaladdr:$off, I32:$addr, I64:$val)>;
467135301Smtmdef : Pat<(truncstorei32 I64:$val,
468135301Smtm                         (regPlusGA I32:$addr,
469144518Sdavidxu                                    (WebAssemblywrapper tglobaladdr:$off))),
470135301Smtm          (STORE32_I64 0, tglobaladdr:$off, I32:$addr, I64:$val)>;
471135301Smtmdef : Pat<(truncstorei8 I32:$val, (add I32:$addr,
472164583Sdavidxu                                       (WebAssemblywrapper texternalsym:$off))),
473135301Smtm          (STORE8_I32 0, texternalsym:$off, I32:$addr, I32:$val)>;
474164583Sdavidxudef : Pat<(truncstorei16 I32:$val,
475135301Smtm                         (add I32:$addr,
476135301Smtm                              (WebAssemblywrapper texternalsym:$off))),
477135301Smtm          (STORE16_I32 0, texternalsym:$off, I32:$addr, I32:$val)>;
478160662Sdavidxudef : Pat<(truncstorei8 I64:$val,
479148658Sdeischen                        (add I32:$addr,
480112918Sjeff                             (WebAssemblywrapper texternalsym:$off))),
481160662Sdavidxu          (STORE8_I64 0, texternalsym:$off, I32:$addr, I64:$val)>;
482112918Sjeffdef : Pat<(truncstorei16 I64:$val,
483144518Sdavidxu                         (add I32:$addr,
484112918Sjeff                              (WebAssemblywrapper texternalsym:$off))),
485112918Sjeff          (STORE16_I64 0, texternalsym:$off, I32:$addr, I64:$val)>;
486164583Sdavidxudef : Pat<(truncstorei32 I64:$val,
487112918Sjeff                         (add I32:$addr,
488164583Sdavidxu                              (WebAssemblywrapper texternalsym:$off))),
489112918Sjeff          (STORE32_I64 0, texternalsym:$off, I32:$addr, I64:$val)>;
490144518Sdavidxu
491112918Sjeff// Select truncating stores with just a constant offset.
492112918Sjeffdef : Pat<(truncstorei8 I32:$val, imm:$off),
493160662Sdavidxu          (STORE8_I32 0, imm:$off, (CONST_I32 0), I32:$val)>;
494112918Sjeffdef : Pat<(truncstorei16 I32:$val, imm:$off),
495112918Sjeff          (STORE16_I32 0, imm:$off, (CONST_I32 0), I32:$val)>;
496160662Sdavidxudef : Pat<(truncstorei8 I64:$val, imm:$off),
497112918Sjeff          (STORE8_I64 0, imm:$off, (CONST_I32 0), I64:$val)>;
498144518Sdavidxudef : Pat<(truncstorei16 I64:$val, imm:$off),
499112918Sjeff          (STORE16_I64 0, imm:$off, (CONST_I32 0), I64:$val)>;
500112918Sjeffdef : Pat<(truncstorei32 I64:$val, imm:$off),
501164583Sdavidxu          (STORE32_I64 0, imm:$off, (CONST_I32 0), I64:$val)>;
502112918Sjeffdef : Pat<(truncstorei8 I32:$val, (WebAssemblywrapper tglobaladdr:$off)),
503164583Sdavidxu          (STORE8_I32 0, tglobaladdr:$off, (CONST_I32 0), I32:$val)>;
504112918Sjeffdef : Pat<(truncstorei16 I32:$val, (WebAssemblywrapper tglobaladdr:$off)),
505112918Sjeff          (STORE16_I32 0, tglobaladdr:$off, (CONST_I32 0), I32:$val)>;
506112918Sjeffdef : Pat<(truncstorei8 I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
507112918Sjeff          (STORE8_I64 0, tglobaladdr:$off, (CONST_I32 0), I64:$val)>;
508160662Sdavidxudef : Pat<(truncstorei16 I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
509112918Sjeff          (STORE16_I64 0, tglobaladdr:$off, (CONST_I32 0), I64:$val)>;
510112918Sjeffdef : Pat<(truncstorei32 I64:$val, (WebAssemblywrapper tglobaladdr:$off)),
511160662Sdavidxu          (STORE32_I64 0, tglobaladdr:$off, (CONST_I32 0), I64:$val)>;
512112918Sjeffdef : Pat<(truncstorei8 I32:$val, (WebAssemblywrapper texternalsym:$off)),
513144518Sdavidxu          (STORE8_I32 0, texternalsym:$off, (CONST_I32 0), I32:$val)>;
514112918Sjeffdef : Pat<(truncstorei16 I32:$val, (WebAssemblywrapper texternalsym:$off)),
515112918Sjeff          (STORE16_I32 0, texternalsym:$off, (CONST_I32 0), I32:$val)>;
516164583Sdavidxudef : Pat<(truncstorei8 I64:$val, (WebAssemblywrapper texternalsym:$off)),
517112918Sjeff          (STORE8_I64 0, texternalsym:$off, (CONST_I32 0), I64:$val)>;
518164583Sdavidxudef : Pat<(truncstorei16 I64:$val, (WebAssemblywrapper texternalsym:$off)),
519112918Sjeff          (STORE16_I64 0, texternalsym:$off, (CONST_I32 0), I64:$val)>;
520144518Sdavidxudef : Pat<(truncstorei32 I64:$val, (WebAssemblywrapper texternalsym:$off)),
521112918Sjeff          (STORE32_I64 0, texternalsym:$off, (CONST_I32 0), I64:$val)>;
522112918Sjeff
523160662Sdavidxulet Defs = [ARGUMENTS] in {
524148658Sdeischen
525148658Sdeischen// Current memory size.
526160662Sdavidxudef CURRENT_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags),
527148658Sdeischen                           [],
528148658Sdeischen                           "current_memory\t$dst", 0x3f>,
529148658Sdeischen                         Requires<[HasAddr32]>;
530148658Sdeischen
531164583Sdavidxu// Grow memory.
532148658Sdeischendef GROW_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
533164583Sdavidxu                        [],
534148658Sdeischen                        "grow_memory\t$dst, $delta", 0x40>,
535148658Sdeischen                      Requires<[HasAddr32]>;
536148658Sdeischen
537148658Sdeischen} // Defs = [ARGUMENTS]
538160662Sdavidxu
539112918Sjeffdef : Pat<(int_wasm_current_memory),
540112918Sjeff          (CURRENT_MEMORY_I32 0)>;
541160662Sdavidxudef : Pat<(int_wasm_grow_memory I32:$delta),
542112918Sjeff          (GROW_MEMORY_I32 0, $delta)>;
543144518Sdavidxu