blob: e97e34b183dc182c35974d75d32ca0544ab5aa36 [file] [log] [blame]
JF Bastien5ca0bac2015-07-10 18:23:10 +00001// 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
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000011/// WebAssembly Memory operand code-gen constructs.
JF Bastien5ca0bac2015-07-10 18:23:10 +000012///
13//===----------------------------------------------------------------------===//
14
Dan Gohman9c54d3b2015-11-25 18:13:18 +000015// TODO:
JF Bastien73ff6af2015-08-31 22:24:11 +000016// - HasAddr64
JF Bastien73ff6af2015-08-31 22:24:11 +000017// - WebAssemblyTargetLowering having to do with atomics
Dan Gohman4b9d7912015-12-15 22:01:29 +000018// - Each has optional alignment.
JF Bastien73ff6af2015-08-31 22:24:11 +000019
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
Dan Gohman4b9d7912015-12-15 22:01:29 +000024// 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.
Dan Gohmanf225a632016-01-11 22:05:44 +000027def regPlusImm : PatFrag<(ops node:$addr, node:$off),
Dan Gohman4b9d7912015-12-15 22:01:29 +000028 (add node:$addr, node:$off),
Derek Schuff2fa36042017-05-01 16:49:39 +000029 [{ return N->getFlags().hasNoUnsignedWrap(); }]>;
Dan Gohman4b9d7912015-12-15 22:01:29 +000030
Dan Gohman3b09d272016-02-22 20:04:02 +000031// Treat an 'or' node as an 'add' if the or'ed bits are known to be zero.
32def or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{
33 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N->getOperand(1)))
34 return CurDAG->MaskedValueIsZero(N->getOperand(0), CN->getAPIntValue());
35
Craig Topper053cf4d2017-04-28 08:15:33 +000036 KnownBits Known0;
37 CurDAG->computeKnownBits(N->getOperand(0), Known0, 0);
38 KnownBits Known1;
39 CurDAG->computeKnownBits(N->getOperand(1), Known1, 0);
40 return (~Known0.Zero & ~Known1.Zero) == 0;
Dan Gohman3b09d272016-02-22 20:04:02 +000041}]>;
42
Dan Gohmanf225a632016-01-11 22:05:44 +000043// GlobalAddresses are conceptually unsigned values, so we can also fold them
Derek Schuff1b258d32016-08-31 20:27:20 +000044// into immediate values as long as the add is 'nuw'.
45// TODO: We'd like to also match GA offsets but there are cases where the
46// register can have a negative value. Find out what more we can do.
Dan Gohmanf225a632016-01-11 22:05:44 +000047def regPlusGA : PatFrag<(ops node:$addr, node:$off),
48 (add node:$addr, node:$off),
49 [{
Derek Schuff2fa36042017-05-01 16:49:39 +000050 return N->getFlags().hasNoUnsignedWrap();
Dan Gohmanf225a632016-01-11 22:05:44 +000051}]>;
52
53// We don't need a regPlusES because external symbols never have constant
54// offsets folded into them, so we can just use add.
55
Dan Gohmanfb3e0592015-11-25 19:36:19 +000056let Defs = [ARGUMENTS] in {
57
Derek Schuff885dc592017-10-05 21:18:42 +000058// Defines atomic and non-atomic loads, regular and extending.
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +000059multiclass WebAssemblyLoad<WebAssemblyRegClass rc, string Name, int Opcode> {
60 defm "": I<(outs rc:$dst),
61 (ins P2Align:$p2align, offset32_op:$off, I32:$addr),
62 (outs), (ins P2Align:$p2align, offset32_op:$off),
63 [], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"),
64 !strconcat(Name, "\t${off}, ${p2align}"), Opcode>;
65}
Derek Schuff0f3bc0f2017-08-31 21:51:48 +000066
JF Bastien73ff6af2015-08-31 22:24:11 +000067// Basic load.
Dan Gohman48abaa92016-10-25 00:17:11 +000068// FIXME: When we can break syntax compatibility, reorder the fields in the
69// asmstrings to match the binary encoding.
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +000070defm LOAD_I32 : WebAssemblyLoad<I32, "i32.load", 0x28>;
71defm LOAD_I64 : WebAssemblyLoad<I64, "i64.load", 0x29>;
72defm LOAD_F32 : WebAssemblyLoad<F32, "f32.load", 0x2a>;
73defm LOAD_F64 : WebAssemblyLoad<F64, "f64.load", 0x2b>;
JF Bastien73ff6af2015-08-31 22:24:11 +000074
Dan Gohman4b9d7912015-12-15 22:01:29 +000075} // Defs = [ARGUMENTS]
76
77// Select loads with no constant offset.
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +000078class LoadPatNoOffset<ValueType ty, PatFrag node, NI inst> :
Derek Schuff0f3bc0f2017-08-31 21:51:48 +000079 Pat<(ty (node I32:$addr)), (inst 0, 0, $addr)>;
80
81def : LoadPatNoOffset<i32, load, LOAD_I32>;
82def : LoadPatNoOffset<i64, load, LOAD_I64>;
83def : LoadPatNoOffset<f32, load, LOAD_F32>;
84def : LoadPatNoOffset<f64, load, LOAD_F64>;
85
Dan Gohman4b9d7912015-12-15 22:01:29 +000086
87// Select loads with a constant offset.
Derek Schuff0f3bc0f2017-08-31 21:51:48 +000088
89// Pattern with address + immediate offset
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +000090class LoadPatImmOff<ValueType ty, PatFrag loadkind, PatFrag operand, NI inst> :
Derek Schuff0f3bc0f2017-08-31 21:51:48 +000091 Pat<(ty (loadkind (operand I32:$addr, imm:$off))),
92 (inst 0, imm:$off, $addr)>;
93
94def : LoadPatImmOff<i32, load, regPlusImm, LOAD_I32>;
95def : LoadPatImmOff<i64, load, regPlusImm, LOAD_I64>;
96def : LoadPatImmOff<f32, load, regPlusImm, LOAD_F32>;
97def : LoadPatImmOff<f64, load, regPlusImm, LOAD_F64>;
98def : LoadPatImmOff<i32, load, or_is_add, LOAD_I32>;
99def : LoadPatImmOff<i64, load, or_is_add, LOAD_I64>;
100def : LoadPatImmOff<f32, load, or_is_add, LOAD_F32>;
101def : LoadPatImmOff<f64, load, or_is_add, LOAD_F64>;
102
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000103class LoadPatGlobalAddr<ValueType ty, PatFrag loadkind, NI inst> :
Derek Schuff0f3bc0f2017-08-31 21:51:48 +0000104 Pat<(ty (loadkind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)))),
105 (inst 0, tglobaladdr:$off, $addr)>;
106
107def : LoadPatGlobalAddr<i32, load, LOAD_I32>;
108def : LoadPatGlobalAddr<i64, load, LOAD_I64>;
109def : LoadPatGlobalAddr<f32, load, LOAD_F32>;
110def : LoadPatGlobalAddr<f64, load, LOAD_F64>;
111
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000112class LoadPatExternalSym<ValueType ty, PatFrag loadkind, NI inst> :
Derek Schuff0f3bc0f2017-08-31 21:51:48 +0000113 Pat<(ty (loadkind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))),
114 (inst 0, texternalsym:$off, $addr)>;
115def : LoadPatExternalSym<i32, load, LOAD_I32>;
116def : LoadPatExternalSym<i64, load, LOAD_I64>;
117def : LoadPatExternalSym<f32, load, LOAD_F32>;
118def : LoadPatExternalSym<f64, load, LOAD_F64>;
119
Dan Gohman4b9d7912015-12-15 22:01:29 +0000120
121// Select loads with just a constant offset.
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000122class LoadPatOffsetOnly<ValueType ty, PatFrag loadkind, NI inst> :
Derek Schuff0f3bc0f2017-08-31 21:51:48 +0000123 Pat<(ty (loadkind imm:$off)), (inst 0, imm:$off, (CONST_I32 0))>;
124
125def : LoadPatOffsetOnly<i32, load, LOAD_I32>;
126def : LoadPatOffsetOnly<i64, load, LOAD_I64>;
127def : LoadPatOffsetOnly<f32, load, LOAD_F32>;
128def : LoadPatOffsetOnly<f64, load, LOAD_F64>;
129
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000130class LoadPatGlobalAddrOffOnly<ValueType ty, PatFrag loadkind, NI inst> :
Derek Schuff0f3bc0f2017-08-31 21:51:48 +0000131 Pat<(ty (loadkind (WebAssemblywrapper tglobaladdr:$off))),
132 (inst 0, tglobaladdr:$off, (CONST_I32 0))>;
133
134def : LoadPatGlobalAddrOffOnly<i32, load, LOAD_I32>;
135def : LoadPatGlobalAddrOffOnly<i64, load, LOAD_I64>;
136def : LoadPatGlobalAddrOffOnly<f32, load, LOAD_F32>;
137def : LoadPatGlobalAddrOffOnly<f64, load, LOAD_F64>;
138
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000139class LoadPatExternSymOffOnly<ValueType ty, PatFrag loadkind, NI inst> :
Derek Schuff0f3bc0f2017-08-31 21:51:48 +0000140 Pat<(ty (loadkind (WebAssemblywrapper texternalsym:$off))),
141 (inst 0, texternalsym:$off, (CONST_I32 0))>;
142def : LoadPatExternSymOffOnly<i32, load, LOAD_I32>;
143def : LoadPatExternSymOffOnly<i64, load, LOAD_I64>;
144def : LoadPatExternSymOffOnly<f32, load, LOAD_F32>;
145def : LoadPatExternSymOffOnly<f64, load, LOAD_F64>;
Dan Gohman4b9d7912015-12-15 22:01:29 +0000146
147let Defs = [ARGUMENTS] in {
148
JF Bastien73ff6af2015-08-31 22:24:11 +0000149// Extending load.
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000150defm LOAD8_S_I32 : WebAssemblyLoad<I32, "i32.load8_s", 0x2c>;
151defm LOAD8_U_I32 : WebAssemblyLoad<I32, "i32.load8_u", 0x2d>;
152defm LOAD16_S_I32 : WebAssemblyLoad<I32, "i32.load16_s", 0x2e>;
153defm LOAD16_U_I32 : WebAssemblyLoad<I32, "i32.load16_u", 0x2f>;
154defm LOAD8_S_I64 : WebAssemblyLoad<I64, "i64.load8_s", 0x30>;
155defm LOAD8_U_I64 : WebAssemblyLoad<I64, "i64.load8_u", 0x31>;
156defm LOAD16_S_I64 : WebAssemblyLoad<I64, "i64.load16_s", 0x32>;
157defm LOAD16_U_I64 : WebAssemblyLoad<I64, "i64.load16_u", 0x33>;
158defm LOAD32_S_I64 : WebAssemblyLoad<I64, "i64.load32_s", 0x34>;
159defm LOAD32_U_I64 : WebAssemblyLoad<I64, "i64.load32_u", 0x35>;
JF Bastien73ff6af2015-08-31 22:24:11 +0000160
Dan Gohmanfb3e0592015-11-25 19:36:19 +0000161} // Defs = [ARGUMENTS]
162
Derek Schuff9d779522015-12-05 00:26:39 +0000163// Select extending loads with no constant offset.
Derek Schuff0f3bc0f2017-08-31 21:51:48 +0000164def : LoadPatNoOffset<i32, sextloadi8, LOAD8_S_I32>;
165def : LoadPatNoOffset<i32, zextloadi8, LOAD8_U_I32>;
166def : LoadPatNoOffset<i32, sextloadi16, LOAD16_S_I32>;
167def : LoadPatNoOffset<i32, zextloadi16, LOAD16_U_I32>;
168def : LoadPatNoOffset<i64, sextloadi8, LOAD8_S_I64>;
169def : LoadPatNoOffset<i64, zextloadi8, LOAD8_U_I64>;
170def : LoadPatNoOffset<i64, sextloadi16, LOAD16_S_I64>;
171def : LoadPatNoOffset<i64, zextloadi16, LOAD16_U_I64>;
172def : LoadPatNoOffset<i64, sextloadi32, LOAD32_S_I64>;
173def : LoadPatNoOffset<i64, zextloadi32, LOAD32_U_I64>;
Derek Schuff9d779522015-12-05 00:26:39 +0000174
Dan Gohman4b9d7912015-12-15 22:01:29 +0000175// Select extending loads with a constant offset.
Derek Schuff0f3bc0f2017-08-31 21:51:48 +0000176def : LoadPatImmOff<i32, sextloadi8, regPlusImm, LOAD8_S_I32>;
177def : LoadPatImmOff<i32, zextloadi8, regPlusImm, LOAD8_U_I32>;
178def : LoadPatImmOff<i32, sextloadi16, regPlusImm, LOAD16_S_I32>;
179def : LoadPatImmOff<i32, zextloadi16, regPlusImm, LOAD16_U_I32>;
180def : LoadPatImmOff<i64, sextloadi8, regPlusImm, LOAD8_S_I64>;
181def : LoadPatImmOff<i64, zextloadi8, regPlusImm, LOAD8_U_I64>;
182def : LoadPatImmOff<i64, sextloadi16, regPlusImm, LOAD16_S_I64>;
183def : LoadPatImmOff<i64, zextloadi16, regPlusImm, LOAD16_U_I64>;
184def : LoadPatImmOff<i64, sextloadi32, regPlusImm, LOAD32_S_I64>;
185def : LoadPatImmOff<i64, zextloadi32, regPlusImm, LOAD32_U_I64>;
186
187def : LoadPatImmOff<i32, sextloadi8, or_is_add, LOAD8_S_I32>;
188def : LoadPatImmOff<i32, zextloadi8, or_is_add, LOAD8_U_I32>;
189def : LoadPatImmOff<i32, sextloadi16, or_is_add, LOAD16_S_I32>;
190def : LoadPatImmOff<i32, zextloadi16, or_is_add, LOAD16_U_I32>;
191def : LoadPatImmOff<i64, sextloadi8, or_is_add, LOAD8_S_I64>;
192def : LoadPatImmOff<i64, zextloadi8, or_is_add, LOAD8_U_I64>;
193def : LoadPatImmOff<i64, sextloadi16, or_is_add, LOAD16_S_I64>;
194def : LoadPatImmOff<i64, zextloadi16, or_is_add, LOAD16_U_I64>;
195def : LoadPatImmOff<i64, sextloadi32, or_is_add, LOAD32_S_I64>;
196def : LoadPatImmOff<i64, zextloadi32, or_is_add, LOAD32_U_I64>;
197
198def : LoadPatGlobalAddr<i32, sextloadi8, LOAD8_S_I32>;
199def : LoadPatGlobalAddr<i32, zextloadi8, LOAD8_U_I32>;
200def : LoadPatGlobalAddr<i32, sextloadi16, LOAD16_S_I32>;
201def : LoadPatGlobalAddr<i32, zextloadi8, LOAD16_U_I32>;
202
203def : LoadPatGlobalAddr<i64, sextloadi8, LOAD8_S_I64>;
204def : LoadPatGlobalAddr<i64, zextloadi8, LOAD8_U_I64>;
205def : LoadPatGlobalAddr<i64, sextloadi16, LOAD16_S_I64>;
206def : LoadPatGlobalAddr<i64, zextloadi16, LOAD16_U_I64>;
207def : LoadPatGlobalAddr<i64, sextloadi32, LOAD32_S_I64>;
208def : LoadPatGlobalAddr<i64, zextloadi32, LOAD32_U_I64>;
209
210def : LoadPatExternalSym<i32, sextloadi8, LOAD8_S_I32>;
211def : LoadPatExternalSym<i32, zextloadi8, LOAD8_U_I32>;
212def : LoadPatExternalSym<i32, sextloadi16, LOAD16_S_I32>;
213def : LoadPatExternalSym<i32, zextloadi16, LOAD16_U_I32>;
214def : LoadPatExternalSym<i64, sextloadi8, LOAD8_S_I64>;
215def : LoadPatExternalSym<i64, zextloadi8, LOAD8_U_I64>;
216def : LoadPatExternalSym<i64, sextloadi16, LOAD16_S_I64>;
217def : LoadPatExternalSym<i64, zextloadi16, LOAD16_U_I64>;
218def : LoadPatExternalSym<i64, sextloadi32, LOAD32_S_I64>;
219def : LoadPatExternalSym<i64, zextloadi32, LOAD32_U_I64>;
220
Dan Gohman4b9d7912015-12-15 22:01:29 +0000221
222// Select extending loads with just a constant offset.
Derek Schuff0f3bc0f2017-08-31 21:51:48 +0000223def : LoadPatOffsetOnly<i32, sextloadi8, LOAD8_S_I32>;
224def : LoadPatOffsetOnly<i32, zextloadi8, LOAD8_U_I32>;
225def : LoadPatOffsetOnly<i32, sextloadi16, LOAD16_S_I32>;
226def : LoadPatOffsetOnly<i32, zextloadi16, LOAD16_U_I32>;
227
228def : LoadPatOffsetOnly<i64, sextloadi8, LOAD8_S_I64>;
229def : LoadPatOffsetOnly<i64, zextloadi8, LOAD8_U_I64>;
230def : LoadPatOffsetOnly<i64, sextloadi16, LOAD16_S_I64>;
231def : LoadPatOffsetOnly<i64, zextloadi16, LOAD16_U_I64>;
232def : LoadPatOffsetOnly<i64, sextloadi32, LOAD32_S_I64>;
233def : LoadPatOffsetOnly<i64, zextloadi32, LOAD32_U_I64>;
234
235def : LoadPatGlobalAddrOffOnly<i32, sextloadi8, LOAD8_S_I32>;
236def : LoadPatGlobalAddrOffOnly<i32, zextloadi8, LOAD8_U_I32>;
237def : LoadPatGlobalAddrOffOnly<i32, sextloadi16, LOAD16_S_I32>;
238def : LoadPatGlobalAddrOffOnly<i32, zextloadi16, LOAD16_U_I32>;
239def : LoadPatGlobalAddrOffOnly<i64, sextloadi8, LOAD8_S_I64>;
240def : LoadPatGlobalAddrOffOnly<i64, zextloadi8, LOAD8_U_I64>;
241def : LoadPatGlobalAddrOffOnly<i64, sextloadi16, LOAD16_S_I64>;
242def : LoadPatGlobalAddrOffOnly<i64, zextloadi16, LOAD16_U_I64>;
243def : LoadPatGlobalAddrOffOnly<i64, sextloadi32, LOAD32_S_I64>;
244def : LoadPatGlobalAddrOffOnly<i64, zextloadi32, LOAD32_U_I64>;
245
246def : LoadPatExternSymOffOnly<i32, sextloadi8, LOAD8_S_I32>;
247def : LoadPatExternSymOffOnly<i32, zextloadi8, LOAD8_U_I32>;
248def : LoadPatExternSymOffOnly<i32, sextloadi16, LOAD16_S_I32>;
249def : LoadPatExternSymOffOnly<i32, zextloadi16, LOAD16_U_I32>;
250def : LoadPatExternSymOffOnly<i64, sextloadi8, LOAD8_S_I64>;
251def : LoadPatExternSymOffOnly<i64, zextloadi8, LOAD8_U_I64>;
252def : LoadPatExternSymOffOnly<i64, sextloadi16, LOAD16_S_I64>;
253def : LoadPatExternSymOffOnly<i64, zextloadi16, LOAD16_U_I64>;
254def : LoadPatExternSymOffOnly<i64, sextloadi32, LOAD32_S_I64>;
255def : LoadPatExternSymOffOnly<i64, zextloadi32, LOAD32_U_I64>;
Dan Gohman4b9d7912015-12-15 22:01:29 +0000256
257// Resolve "don't care" extending loads to zero-extending loads. This is
258// somewhat arbitrary, but zero-extending is conceptually simpler.
259
260// Select "don't care" extending loads with no constant offset.
Derek Schuff0f3bc0f2017-08-31 21:51:48 +0000261def : LoadPatNoOffset<i32, extloadi8, LOAD8_U_I32>;
262def : LoadPatNoOffset<i32, extloadi16, LOAD16_U_I32>;
263def : LoadPatNoOffset<i64, extloadi8, LOAD8_U_I64>;
264def : LoadPatNoOffset<i64, extloadi16, LOAD16_U_I64>;
265def : LoadPatNoOffset<i64, extloadi32, LOAD32_U_I64>;
266
Dan Gohman4b9d7912015-12-15 22:01:29 +0000267// Select "don't care" extending loads with a constant offset.
Derek Schuff0f3bc0f2017-08-31 21:51:48 +0000268def : LoadPatImmOff<i32, extloadi8, regPlusImm, LOAD8_U_I32>;
269def : LoadPatImmOff<i32, extloadi16, regPlusImm, LOAD16_U_I32>;
270def : LoadPatImmOff<i64, extloadi8, regPlusImm, LOAD8_U_I64>;
271def : LoadPatImmOff<i64, extloadi16, regPlusImm, LOAD16_U_I64>;
272def : LoadPatImmOff<i64, extloadi32, regPlusImm, LOAD32_U_I64>;
273def : LoadPatImmOff<i32, extloadi8, or_is_add, LOAD8_U_I32>;
274def : LoadPatImmOff<i32, extloadi16, or_is_add, LOAD16_U_I32>;
275def : LoadPatImmOff<i64, extloadi8, or_is_add, LOAD8_U_I64>;
276def : LoadPatImmOff<i64, extloadi16, or_is_add, LOAD16_U_I64>;
277def : LoadPatImmOff<i64, extloadi32, or_is_add, LOAD32_U_I64>;
278def : LoadPatGlobalAddr<i32, extloadi8, LOAD8_U_I32>;
279def : LoadPatGlobalAddr<i32, extloadi16, LOAD16_U_I32>;
280def : LoadPatGlobalAddr<i64, extloadi8, LOAD8_U_I64>;
281def : LoadPatGlobalAddr<i64, extloadi16, LOAD16_U_I64>;
282def : LoadPatGlobalAddr<i64, extloadi32, LOAD32_U_I64>;
283def : LoadPatExternalSym<i32, extloadi8, LOAD8_U_I32>;
284def : LoadPatExternalSym<i32, extloadi16, LOAD16_U_I32>;
285def : LoadPatExternalSym<i64, extloadi8, LOAD8_U_I64>;
286def : LoadPatExternalSym<i64, extloadi16, LOAD16_U_I64>;
287def : LoadPatExternalSym<i64, extloadi32, LOAD32_U_I64>;
288
Dan Gohman4b9d7912015-12-15 22:01:29 +0000289// Select "don't care" extending loads with just a constant offset.
Derek Schuff0f3bc0f2017-08-31 21:51:48 +0000290def : LoadPatOffsetOnly<i32, extloadi8, LOAD8_U_I32>;
291def : LoadPatOffsetOnly<i32, extloadi16, LOAD16_U_I32>;
292def : LoadPatOffsetOnly<i64, extloadi8, LOAD8_U_I64>;
293def : LoadPatOffsetOnly<i64, extloadi16, LOAD16_U_I64>;
294def : LoadPatOffsetOnly<i64, extloadi32, LOAD32_U_I64>;
295def : LoadPatGlobalAddrOffOnly<i32, extloadi8, LOAD8_U_I32>;
296def : LoadPatGlobalAddrOffOnly<i32, extloadi16, LOAD16_U_I32>;
297def : LoadPatGlobalAddrOffOnly<i64, extloadi8, LOAD8_U_I64>;
298def : LoadPatGlobalAddrOffOnly<i64, extloadi16, LOAD16_U_I64>;
299def : LoadPatGlobalAddrOffOnly<i64, extloadi32, LOAD32_U_I64>;
300def : LoadPatExternSymOffOnly<i32, extloadi8, LOAD8_U_I32>;
301def : LoadPatExternSymOffOnly<i32, extloadi16, LOAD16_U_I32>;
302def : LoadPatExternSymOffOnly<i64, extloadi8, LOAD8_U_I64>;
303def : LoadPatExternSymOffOnly<i64, extloadi16, LOAD16_U_I64>;
304def : LoadPatExternSymOffOnly<i64, extloadi32, LOAD32_U_I64>;
305
Dan Gohman4b9d7912015-12-15 22:01:29 +0000306
Dan Gohmanfb3e0592015-11-25 19:36:19 +0000307let Defs = [ARGUMENTS] in {
308
Derek Schuffa2726e92018-03-30 17:02:50 +0000309// Defines atomic and non-atomic stores, regular and truncating
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000310multiclass WebAssemblyStore<WebAssemblyRegClass rc, string Name, int Opcode> {
311 defm "" : I<(outs),
312 (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val),
313 (outs),
314 (ins P2Align:$p2align, offset32_op:$off), [],
315 !strconcat(Name, "\t${off}(${addr})${p2align}, $val"),
316 !strconcat(Name, "\t${off}, ${p2align}"), Opcode>;
317}
JF Bastien73ff6af2015-08-31 22:24:11 +0000318// Basic store.
319// Note: WebAssembly inverts SelectionDAG's usual operand order.
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000320defm STORE_I32 : WebAssemblyStore<I32, "i32.store", 0x36>;
321defm STORE_I64 : WebAssemblyStore<I64, "i64.store", 0x37>;
322defm STORE_F32 : WebAssemblyStore<F32, "f32.store", 0x38>;
323defm STORE_F64 : WebAssemblyStore<F64, "f64.store", 0x39>;
Dan Gohman7054ac12015-11-23 21:16:35 +0000324
Dan Gohmanfb3e0592015-11-25 19:36:19 +0000325} // Defs = [ARGUMENTS]
326
Dan Gohman4b9d7912015-12-15 22:01:29 +0000327// Select stores with no constant offset.
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000328class StorePatNoOffset<ValueType ty, PatFrag node, NI inst> :
Derek Schuffa2726e92018-03-30 17:02:50 +0000329 Pat<(node ty:$val, I32:$addr), (inst 0, 0, $addr, $val)>;
330
331def : StorePatNoOffset<i32, store, STORE_I32>;
332def : StorePatNoOffset<i64, store, STORE_I64>;
333def : StorePatNoOffset<f32, store, STORE_F32>;
334def : StorePatNoOffset<f64, store, STORE_F64>;
Derek Schuff9d779522015-12-05 00:26:39 +0000335
Dan Gohman4b9d7912015-12-15 22:01:29 +0000336// Select stores with a constant offset.
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000337class StorePatImmOff<ValueType ty, PatFrag storekind, PatFrag operand, NI inst> :
Derek Schuffa2726e92018-03-30 17:02:50 +0000338 Pat<(storekind ty:$val, (operand I32:$addr, imm:$off)),
339 (inst 0, imm:$off, $addr, ty:$val)>;
340
341def : StorePatImmOff<i32, store, regPlusImm, STORE_I32>;
342def : StorePatImmOff<i64, store, regPlusImm, STORE_I64>;
343def : StorePatImmOff<f32, store, regPlusImm, STORE_F32>;
344def : StorePatImmOff<f64, store, regPlusImm, STORE_F64>;
345def : StorePatImmOff<i32, store, or_is_add, STORE_I32>;
346def : StorePatImmOff<i64, store, or_is_add, STORE_I64>;
347def : StorePatImmOff<f32, store, or_is_add, STORE_F32>;
348def : StorePatImmOff<f64, store, or_is_add, STORE_F64>;
349
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000350class StorePatGlobalAddr<ValueType ty, PatFrag storekind, NI inst> :
Derek Schuffa2726e92018-03-30 17:02:50 +0000351 Pat<(storekind ty:$val, (regPlusGA I32:$addr,
352 (WebAssemblywrapper tglobaladdr:$off))),
353 (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>;
354def : StorePatGlobalAddr<i32, store, STORE_I32>;
355def : StorePatGlobalAddr<i64, store, STORE_I64>;
356def : StorePatGlobalAddr<f32, store, STORE_F32>;
357def : StorePatGlobalAddr<f64, store, STORE_F64>;
358
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000359class StorePatExternalSym<ValueType ty, PatFrag storekind, NI inst> :
Derek Schuffa2726e92018-03-30 17:02:50 +0000360 Pat<(storekind ty:$val, (add I32:$addr,
361 (WebAssemblywrapper texternalsym:$off))),
362 (inst 0, texternalsym:$off, I32:$addr, ty:$val)>;
363def : StorePatExternalSym<i32, store, STORE_I32>;
364def : StorePatExternalSym<i64, store, STORE_I64>;
365def : StorePatExternalSym<f32, store, STORE_F32>;
366def : StorePatExternalSym<f64, store, STORE_F64>;
Dan Gohman4b9d7912015-12-15 22:01:29 +0000367
368// Select stores with just a constant offset.
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000369class StorePatOffsetOnly<ValueType ty, PatFrag storekind, NI inst> :
Derek Schuffa2726e92018-03-30 17:02:50 +0000370 Pat<(storekind ty:$val, imm:$off),
371 (inst 0, imm:$off, (CONST_I32 0), ty:$val)>;
372def : StorePatOffsetOnly<i32, store, STORE_I32>;
373def : StorePatOffsetOnly<i64, store, STORE_I64>;
374def : StorePatOffsetOnly<f32, store, STORE_F32>;
375def : StorePatOffsetOnly<f64, store, STORE_F64>;
376
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000377class StorePatGlobalAddrOffOnly<ValueType ty, PatFrag storekind, NI inst> :
Derek Schuffa2726e92018-03-30 17:02:50 +0000378 Pat<(storekind ty:$val, (WebAssemblywrapper tglobaladdr:$off)),
379 (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>;
380def : StorePatGlobalAddrOffOnly<i32, store, STORE_I32>;
381def : StorePatGlobalAddrOffOnly<i64, store, STORE_I64>;
382def : StorePatGlobalAddrOffOnly<f32, store, STORE_F32>;
383def : StorePatGlobalAddrOffOnly<f64, store, STORE_F64>;
384
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000385class StorePatExternSymOffOnly<ValueType ty, PatFrag storekind, NI inst> :
Derek Schuffa2726e92018-03-30 17:02:50 +0000386 Pat<(storekind ty:$val, (WebAssemblywrapper texternalsym:$off)),
387 (inst 0, texternalsym:$off, (CONST_I32 0), ty:$val)>;
388def : StorePatExternSymOffOnly<i32, store, STORE_I32>;
389def : StorePatExternSymOffOnly<i64, store, STORE_I64>;
390def : StorePatExternSymOffOnly<f32, store, STORE_F32>;
391def : StorePatExternSymOffOnly<f64, store, STORE_F64>;
392
JF Bastien73ff6af2015-08-31 22:24:11 +0000393
Dan Gohmanfb3e0592015-11-25 19:36:19 +0000394let Defs = [ARGUMENTS] in {
395
JF Bastien73ff6af2015-08-31 22:24:11 +0000396// Truncating store.
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000397defm STORE8_I32 : WebAssemblyStore<I32, "i32.store8", 0x3a>;
398defm STORE16_I32 : WebAssemblyStore<I32, "i32.store16", 0x3b>;
399defm STORE8_I64 : WebAssemblyStore<I64, "i64.store8", 0x3c>;
400defm STORE16_I64 : WebAssemblyStore<I64, "i64.store16", 0x3d>;
401defm STORE32_I64 : WebAssemblyStore<I64, "i64.store32", 0x3e>;
Dan Gohman7054ac12015-11-23 21:16:35 +0000402
Dan Gohmanfb3e0592015-11-25 19:36:19 +0000403} // Defs = [ARGUMENTS]
404
Dan Gohman4b9d7912015-12-15 22:01:29 +0000405// Select truncating stores with no constant offset.
Derek Schuffa2726e92018-03-30 17:02:50 +0000406def : StorePatNoOffset<i32, truncstorei8, STORE8_I32>;
407def : StorePatNoOffset<i32, truncstorei16, STORE16_I32>;
408def : StorePatNoOffset<i64, truncstorei8, STORE8_I64>;
409def : StorePatNoOffset<i64, truncstorei16, STORE16_I64>;
410def : StorePatNoOffset<i64, truncstorei32, STORE32_I64>;
JF Bastien73ff6af2015-08-31 22:24:11 +0000411
Dan Gohman4b9d7912015-12-15 22:01:29 +0000412// Select truncating stores with a constant offset.
Derek Schuffa2726e92018-03-30 17:02:50 +0000413def : StorePatImmOff<i32, truncstorei8, regPlusImm, STORE8_I32>;
414def : StorePatImmOff<i32, truncstorei16, regPlusImm, STORE16_I32>;
415def : StorePatImmOff<i64, truncstorei8, regPlusImm, STORE8_I64>;
416def : StorePatImmOff<i64, truncstorei16, regPlusImm, STORE16_I64>;
417def : StorePatImmOff<i64, truncstorei32, regPlusImm, STORE32_I64>;
418def : StorePatImmOff<i32, truncstorei8, or_is_add, STORE8_I32>;
419def : StorePatImmOff<i32, truncstorei16, or_is_add, STORE16_I32>;
420def : StorePatImmOff<i64, truncstorei8, or_is_add, STORE8_I64>;
421def : StorePatImmOff<i64, truncstorei16, or_is_add, STORE16_I64>;
422def : StorePatImmOff<i64, truncstorei32, or_is_add, STORE32_I64>;
423
424def : StorePatGlobalAddr<i32, truncstorei8, STORE8_I32>;
425def : StorePatGlobalAddr<i32, truncstorei16, STORE16_I32>;
426def : StorePatGlobalAddr<i64, truncstorei8, STORE8_I64>;
427def : StorePatGlobalAddr<i64, truncstorei16, STORE16_I64>;
428def : StorePatGlobalAddr<i64, truncstorei32, STORE32_I64>;
429def : StorePatExternalSym<i32, truncstorei8, STORE8_I32>;
430def : StorePatExternalSym<i32, truncstorei16, STORE16_I32>;
431def : StorePatExternalSym<i64, truncstorei8, STORE8_I64>;
432def : StorePatExternalSym<i64, truncstorei16, STORE16_I64>;
433def : StorePatExternalSym<i64, truncstorei32, STORE32_I64>;
Dan Gohman4b9d7912015-12-15 22:01:29 +0000434
435// Select truncating stores with just a constant offset.
Derek Schuffa2726e92018-03-30 17:02:50 +0000436def : StorePatOffsetOnly<i32, truncstorei8, STORE8_I32>;
437def : StorePatOffsetOnly<i32, truncstorei16, STORE16_I32>;
438def : StorePatOffsetOnly<i64, truncstorei8, STORE8_I64>;
439def : StorePatOffsetOnly<i64, truncstorei16, STORE16_I64>;
440def : StorePatOffsetOnly<i64, truncstorei32, STORE32_I64>;
441def : StorePatGlobalAddrOffOnly<i32, truncstorei8, STORE8_I32>;
442def : StorePatGlobalAddrOffOnly<i32, truncstorei16, STORE16_I32>;
443def : StorePatGlobalAddrOffOnly<i64, truncstorei8, STORE8_I64>;
444def : StorePatGlobalAddrOffOnly<i64, truncstorei16, STORE16_I64>;
445def : StorePatGlobalAddrOffOnly<i64, truncstorei32, STORE32_I64>;
446def : StorePatExternSymOffOnly<i32, truncstorei8, STORE8_I32>;
447def : StorePatExternSymOffOnly<i32, truncstorei16, STORE16_I32>;
448def : StorePatExternSymOffOnly<i64, truncstorei8, STORE8_I64>;
449def : StorePatExternSymOffOnly<i64, truncstorei16, STORE16_I64>;
450def : StorePatExternSymOffOnly<i64, truncstorei32, STORE32_I64>;
Dan Gohman4b9d7912015-12-15 22:01:29 +0000451
Dan Gohmanfb3e0592015-11-25 19:36:19 +0000452let Defs = [ARGUMENTS] in {
453
Derek Schuff31680dd2016-05-02 17:25:22 +0000454// Current memory size.
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000455defm MEMORY_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags),
456 (outs), (ins i32imm:$flags),
457 [(set I32:$dst,
458 (int_wasm_memory_size (i32 imm:$flags)))],
459 "memory.size\t$dst, $flags", "memory.size\t$flags",
460 0x3f>,
461 Requires<[HasAddr32]>;
462defm MEM_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags),
463 (outs), (ins i32imm:$flags),
464 [(set I32:$dst, (int_wasm_mem_size (i32 imm:$flags)))],
465 "mem.size\t$dst, $flags", "mem.size\t$flags", 0x3f>,
466 Requires<[HasAddr32]>;
467defm CURRENT_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags),
468 (outs), (ins i32imm:$flags),
469 [],
470 "current_memory\t$dst",
471 "current_memory\t$flags", 0x3f>,
472 Requires<[HasAddr32]>;
Dan Gohmanbaba8c62015-10-02 20:10:26 +0000473
Dan Gohmand7ffb912015-11-05 20:16:59 +0000474// Grow memory.
Wouter van Oortmerssen48dac312018-06-18 21:22:44 +0000475defm MEMORY_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
476 (outs), (ins i32imm:$flags, I32:$delta),
477 [(set I32:$dst,
478 (int_wasm_memory_grow (i32 imm:$flags),
479 I32:$delta))],
480 "memory.grow\t$dst, $flags, $delta",
481 "memory.grow\t$flags, $delta", 0x3f>,
482 Requires<[HasAddr32]>;
483defm MEM_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
484 (outs), (ins i32imm:$flags),
485 [(set I32:$dst,
486 (int_wasm_mem_grow (i32 imm:$flags), I32:$delta))],
487 "mem.grow\t$dst, $flags, $delta", "mem.grow\t$flags",
488 0x3f>,
489 Requires<[HasAddr32]>;
490defm GROW_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta),
491 (outs), (ins i32imm:$flags),
492 [],
493 "grow_memory\t$dst, $delta", "grow_memory\t$flags",
494 0x40>,
495 Requires<[HasAddr32]>;
Dan Gohmanfb3e0592015-11-25 19:36:19 +0000496
497} // Defs = [ARGUMENTS]
Dan Gohmanf50d9642016-10-25 16:55:52 +0000498
499def : Pat<(int_wasm_current_memory),
500 (CURRENT_MEMORY_I32 0)>;
501def : Pat<(int_wasm_grow_memory I32:$delta),
502 (GROW_MEMORY_I32 0, $delta)>;