1// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Lowering arithmetic
6(Add(64|32|16|8|Ptr) x y) -> (I64Add x y)
7(Add(64|32)F x y) -> (F(64|32)Add x y)
8
9(Sub(64|32|16|8|Ptr) x y) -> (I64Sub x y)
10(Sub(64|32)F x y) -> (F(64|32)Sub x y)
11
12(Mul(64|32|16|8) x y) -> (I64Mul x y)
13(Mul(64|32)F x y) -> (F(64|32)Mul x y)
14
15(Div64  x y) -> (I64DivS x y)
16(Div64u x y) -> (I64DivU x y)
17(Div32  x y) -> (I64DivS (SignExt32to64 x) (SignExt32to64 y))
18(Div32u x y) -> (I64DivU (ZeroExt32to64 x) (ZeroExt32to64 y))
19(Div16  x y) -> (I64DivS (SignExt16to64 x) (SignExt16to64 y))
20(Div16u x y) -> (I64DivU (ZeroExt16to64 x) (ZeroExt16to64 y))
21(Div8   x y) -> (I64DivS (SignExt8to64 x) (SignExt8to64 y))
22(Div8u  x y) -> (I64DivU (ZeroExt8to64 x) (ZeroExt8to64 y))
23(Div(64|32)F x y) -> (F(64|32)Div x y)
24
25(Mod64  x y) -> (I64RemS x y)
26(Mod64u x y) -> (I64RemU x y)
27(Mod32  x y) -> (I64RemS (SignExt32to64 x) (SignExt32to64 y))
28(Mod32u x y) -> (I64RemU (ZeroExt32to64 x) (ZeroExt32to64 y))
29(Mod16  x y) -> (I64RemS (SignExt16to64 x) (SignExt16to64 y))
30(Mod16u x y) -> (I64RemU (ZeroExt16to64 x) (ZeroExt16to64 y))
31(Mod8   x y) -> (I64RemS (SignExt8to64  x) (SignExt8to64  y))
32(Mod8u  x y) -> (I64RemU (ZeroExt8to64  x) (ZeroExt8to64  y))
33
34(And(64|32|16|8|B) x y) -> (I64And x y)
35
36(Or(64|32|16|8|B) x y) -> (I64Or x y)
37
38(Xor(64|32|16|8) x y) -> (I64Xor x y)
39
40(Neg(64|32|16|8) x) -> (I64Sub (I64Const [0]) x)
41(Neg(64|32)F x) -> (F(64|32)Neg x)
42
43(Com(64|32|16|8) x) -> (I64Xor x (I64Const [-1]))
44
45(Not x) -> (I64Eqz x)
46
47// Lowering pointer arithmetic
48(OffPtr [off] ptr) -> (I64AddConst [off] ptr)
49
50// Lowering extension
51// It is unnecessary to extend loads
52(SignExt32to64        x:(I64Load32S _ _)) -> x
53(SignExt16to(64|32)   x:(I64Load16S _ _)) -> x
54(SignExt8to(64|32|16) x:(I64Load8S  _ _)) -> x
55(ZeroExt32to64        x:(I64Load32U _ _)) -> x
56(ZeroExt16to(64|32)   x:(I64Load16U _ _)) -> x
57(ZeroExt8to(64|32|16) x:(I64Load8U  _ _)) -> x
58(SignExt32to64        x) && objabi.GOWASM.SignExt -> (I64Extend32S x)
59(SignExt8to(64|32|16) x) && objabi.GOWASM.SignExt -> (I64Extend8S x)
60(SignExt16to(64|32)   x) && objabi.GOWASM.SignExt -> (I64Extend16S x)
61(SignExt32to64        x) -> (I64ShrS (I64Shl x (I64Const [32])) (I64Const [32]))
62(SignExt16to(64|32)   x) -> (I64ShrS (I64Shl x (I64Const [48])) (I64Const [48]))
63(SignExt8to(64|32|16) x) -> (I64ShrS (I64Shl x (I64Const [56])) (I64Const [56]))
64(ZeroExt32to64        x) -> (I64And x (I64Const [0xffffffff]))
65(ZeroExt16to(64|32)   x) -> (I64And x (I64Const [0xffff]))
66(ZeroExt8to(64|32|16) x) -> (I64And x (I64Const [0xff]))
67
68(Slicemask x) -> (I64ShrS (I64Sub (I64Const [0]) x) (I64Const [63]))
69
70// Lowering truncation
71// Because we ignore the high parts, truncates are just copies.
72(Trunc64to(32|16|8) x) -> x
73(Trunc32to(16|8)    x) -> x
74(Trunc16to8         x) -> x
75
76// Lowering float <-> int
77(Cvt32to(64|32)F x) -> (F(64|32)ConvertI64S (SignExt32to64 x))
78(Cvt64to(64|32)F x) -> (F(64|32)ConvertI64S x)
79(Cvt32Uto(64|32)F x) -> (F(64|32)ConvertI64U (ZeroExt32to64 x))
80(Cvt64Uto(64|32)F x) -> (F(64|32)ConvertI64U x)
81
82(Cvt32Fto32 x) -> (I64TruncSatF32S x)
83(Cvt32Fto64 x) -> (I64TruncSatF32S x)
84(Cvt64Fto32 x) -> (I64TruncSatF64S x)
85(Cvt64Fto64 x) -> (I64TruncSatF64S x)
86(Cvt32Fto32U x) -> (I64TruncSatF32U x)
87(Cvt32Fto64U x) -> (I64TruncSatF32U x)
88(Cvt64Fto32U x) -> (I64TruncSatF64U x)
89(Cvt64Fto64U x) -> (I64TruncSatF64U x)
90
91(Cvt32Fto64F x) -> (F64PromoteF32 x)
92(Cvt64Fto32F x) -> (F32DemoteF64 x)
93
94(Round32F x) -> x
95(Round64F x) -> x
96
97// Lowering shifts
98// Unsigned shifts need to return 0 if shift amount is >= width of shifted value.
99
100(Lsh64x64 x y) && shiftIsBounded(v) -> (I64Shl x y)
101(Lsh64x64 x (I64Const [c])) && uint64(c) < 64 -> (I64Shl x (I64Const [c]))
102(Lsh64x64 x (I64Const [c])) && uint64(c) >= 64 -> (I64Const [0])
103(Lsh64x64 x y) -> (Select (I64Shl x y) (I64Const [0]) (I64LtU y (I64Const [64])))
104(Lsh64x(32|16|8) x y) -> (Lsh64x64 x (ZeroExt(32|16|8)to64 y))
105
106(Lsh32x64 x y) -> (Lsh64x64 x y)
107(Lsh32x(32|16|8) x y) -> (Lsh64x64 x (ZeroExt(32|16|8)to64 y))
108
109(Lsh16x64 x y) -> (Lsh64x64 x y)
110(Lsh16x(32|16|8) x y) -> (Lsh64x64 x (ZeroExt(32|16|8)to64 y))
111
112(Lsh8x64  x y) -> (Lsh64x64 x y)
113(Lsh8x(32|16|8)  x y) -> (Lsh64x64 x (ZeroExt(32|16|8)to64 y))
114
115(Rsh64Ux64 x y) && shiftIsBounded(v) -> (I64ShrU x y)
116(Rsh64Ux64 x (I64Const [c])) && uint64(c) < 64 -> (I64ShrU x (I64Const [c]))
117(Rsh64Ux64 x (I64Const [c])) && uint64(c) >= 64 -> (I64Const [0])
118(Rsh64Ux64 x y) -> (Select (I64ShrU x y) (I64Const [0]) (I64LtU y (I64Const [64])))
119(Rsh64Ux(32|16|8) x y) -> (Rsh64Ux64 x (ZeroExt(32|16|8)to64 y))
120
121(Rsh32Ux64 x y) -> (Rsh64Ux64 (ZeroExt32to64 x) y)
122(Rsh32Ux(32|16|8) x y) -> (Rsh64Ux64 (ZeroExt32to64 x) (ZeroExt(32|16|8)to64 y))
123
124(Rsh16Ux64 x y) -> (Rsh64Ux64 (ZeroExt16to64 x) y)
125(Rsh16Ux(32|16|8) x y) -> (Rsh64Ux64 (ZeroExt16to64 x) (ZeroExt(32|16|8)to64 y))
126
127(Rsh8Ux64  x y) -> (Rsh64Ux64 (ZeroExt8to64 x) y)
128(Rsh8Ux(32|16|8)  x y) -> (Rsh64Ux64 (ZeroExt8to64 x) (ZeroExt(32|16|8)to64 y))
129
130// Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value.
131// We implement this by setting the shift value to (width - 1) if the shift value is >= width.
132
133(Rsh64x64 x y) && shiftIsBounded(v) -> (I64ShrS x y)
134(Rsh64x64 x (I64Const [c])) && uint64(c) < 64 -> (I64ShrS x (I64Const [c]))
135(Rsh64x64 x (I64Const [c])) && uint64(c) >= 64 -> (I64ShrS x (I64Const [63]))
136(Rsh64x64 x y) -> (I64ShrS x (Select <typ.Int64> y (I64Const [63]) (I64LtU y (I64Const [64]))))
137(Rsh64x(32|16|8) x y) -> (Rsh64x64 x (ZeroExt(32|16|8)to64 y))
138
139(Rsh32x64 x y) -> (Rsh64x64 (SignExt32to64 x) y)
140(Rsh32x(32|16|8) x y) -> (Rsh64x64 (SignExt32to64 x) (ZeroExt(32|16|8)to64 y))
141
142(Rsh16x64 x y) -> (Rsh64x64 (SignExt16to64 x) y)
143(Rsh16x(32|16|8) x y) -> (Rsh64x64 (SignExt16to64 x) (ZeroExt(32|16|8)to64 y))
144
145(Rsh8x64 x y)  -> (Rsh64x64 (SignExt8to64 x) y)
146(Rsh8x(32|16|8) x y)  -> (Rsh64x64 (SignExt8to64 x) (ZeroExt(32|16|8)to64 y))
147
148// Lowering rotates
149(RotateLeft8 <t> x (I64Const [c])) -> (Or8 (Lsh8x64 <t> x (I64Const [c&7])) (Rsh8Ux64 <t> x (I64Const [-c&7])))
150(RotateLeft16 <t> x (I64Const [c])) -> (Or16 (Lsh16x64 <t> x (I64Const [c&15])) (Rsh16Ux64 <t> x (I64Const [-c&15])))
151(RotateLeft32 x y) -> (I32Rotl x y)
152(RotateLeft64 x y) -> (I64Rotl x y)
153
154// Lowering comparisons
155(Less64  x y) -> (I64LtS x y)
156(Less32  x y) -> (I64LtS (SignExt32to64 x) (SignExt32to64 y))
157(Less16  x y) -> (I64LtS (SignExt16to64 x) (SignExt16to64 y))
158(Less8   x y) -> (I64LtS (SignExt8to64  x) (SignExt8to64  y))
159(Less64U x y) -> (I64LtU x y)
160(Less32U x y) -> (I64LtU (ZeroExt32to64 x) (ZeroExt32to64 y))
161(Less16U x y) -> (I64LtU (ZeroExt16to64 x) (ZeroExt16to64 y))
162(Less8U  x y) -> (I64LtU (ZeroExt8to64  x) (ZeroExt8to64  y))
163(Less(64|32)F x y) -> (F(64|32)Lt x y)
164
165(Leq64  x y) -> (I64LeS x y)
166(Leq32  x y) -> (I64LeS (SignExt32to64 x) (SignExt32to64 y))
167(Leq16  x y) -> (I64LeS (SignExt16to64 x) (SignExt16to64 y))
168(Leq8   x y) -> (I64LeS (SignExt8to64  x) (SignExt8to64  y))
169(Leq64U x y) -> (I64LeU x y)
170(Leq32U x y) -> (I64LeU (ZeroExt32to64 x) (ZeroExt32to64 y))
171(Leq16U x y) -> (I64LeU (ZeroExt16to64 x) (ZeroExt16to64 y))
172(Leq8U  x y) -> (I64LeU (ZeroExt8to64  x) (ZeroExt8to64  y))
173(Leq(64|32)F x y) -> (F(64|32)Le x y)
174
175(Greater64  x y) -> (I64GtS x y)
176(Greater32  x y) -> (I64GtS (SignExt32to64 x) (SignExt32to64 y))
177(Greater16  x y) -> (I64GtS (SignExt16to64 x) (SignExt16to64 y))
178(Greater8   x y) -> (I64GtS (SignExt8to64  x) (SignExt8to64  y))
179(Greater64U x y) -> (I64GtU x y)
180(Greater32U x y) -> (I64GtU (ZeroExt32to64 x) (ZeroExt32to64 y))
181(Greater16U x y) -> (I64GtU (ZeroExt16to64 x) (ZeroExt16to64 y))
182(Greater8U  x y) -> (I64GtU (ZeroExt8to64  x) (ZeroExt8to64  y))
183(Greater(64|32)F x y) -> (F(64|32)Gt x y)
184
185(Geq64  x y) -> (I64GeS x y)
186(Geq32  x y) -> (I64GeS (SignExt32to64 x) (SignExt32to64 y))
187(Geq16  x y) -> (I64GeS (SignExt16to64 x) (SignExt16to64 y))
188(Geq8   x y) -> (I64GeS (SignExt8to64  x) (SignExt8to64  y))
189(Geq64U x y) -> (I64GeU x y)
190(Geq32U x y) -> (I64GeU (ZeroExt32to64 x) (ZeroExt32to64 y))
191(Geq16U x y) -> (I64GeU (ZeroExt16to64 x) (ZeroExt16to64 y))
192(Geq8U  x y) -> (I64GeU (ZeroExt8to64  x) (ZeroExt8to64  y))
193(Geq(64|32)F x y) -> (F(64|32)Ge x y)
194
195(Eq64  x y) -> (I64Eq x y)
196(Eq32  x y) -> (I64Eq (ZeroExt32to64 x) (ZeroExt32to64 y))
197(Eq16  x y) -> (I64Eq (ZeroExt16to64 x) (ZeroExt16to64 y))
198(Eq8   x y) -> (I64Eq (ZeroExt8to64  x) (ZeroExt8to64  y))
199(EqB   x y) -> (I64Eq x y)
200(EqPtr x y) -> (I64Eq x y)
201(Eq(64|32)F x y) -> (F(64|32)Eq x y)
202
203(Neq64  x y) -> (I64Ne x y)
204(Neq32  x y) -> (I64Ne (ZeroExt32to64 x) (ZeroExt32to64 y))
205(Neq16  x y) -> (I64Ne (ZeroExt16to64 x) (ZeroExt16to64 y))
206(Neq8   x y) -> (I64Ne (ZeroExt8to64  x) (ZeroExt8to64  y))
207(NeqB   x y) -> (I64Ne x y)
208(NeqPtr x y) -> (I64Ne x y)
209(Neq(64|32)F x y) -> (F(64|32)Ne x y)
210
211// Lowering loads
212(Load <t> ptr mem) && is32BitFloat(t) -> (F32Load ptr mem)
213(Load <t> ptr mem) && is64BitFloat(t) -> (F64Load ptr mem)
214(Load <t> ptr mem) && t.Size() == 8 -> (I64Load ptr mem)
215(Load <t> ptr mem) && t.Size() == 4 && !t.IsSigned() -> (I64Load32U ptr mem)
216(Load <t> ptr mem) && t.Size() == 4 &&  t.IsSigned() -> (I64Load32S ptr mem)
217(Load <t> ptr mem) && t.Size() == 2 && !t.IsSigned() -> (I64Load16U ptr mem)
218(Load <t> ptr mem) && t.Size() == 2 &&  t.IsSigned() -> (I64Load16S ptr mem)
219(Load <t> ptr mem) && t.Size() == 1 && !t.IsSigned() -> (I64Load8U ptr mem)
220(Load <t> ptr mem) && t.Size() == 1 &&  t.IsSigned() -> (I64Load8S ptr mem)
221
222// Lowering stores
223(Store {t} ptr val mem) && is64BitFloat(t.(*types.Type)) -> (F64Store ptr val mem)
224(Store {t} ptr val mem) && is32BitFloat(t.(*types.Type)) -> (F32Store ptr val mem)
225(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 -> (I64Store ptr val mem)
226(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 -> (I64Store32 ptr val mem)
227(Store {t} ptr val mem) && t.(*types.Type).Size() == 2 -> (I64Store16 ptr val mem)
228(Store {t} ptr val mem) && t.(*types.Type).Size() == 1 -> (I64Store8 ptr val mem)
229
230// Lowering moves
231(Move [0] _ _ mem) -> mem
232(Move [1] dst src mem) -> (I64Store8 dst (I64Load8U src mem) mem)
233(Move [2] dst src mem) -> (I64Store16 dst (I64Load16U src mem) mem)
234(Move [4] dst src mem) -> (I64Store32 dst (I64Load32U src mem) mem)
235(Move [8] dst src mem) -> (I64Store dst (I64Load src mem) mem)
236(Move [16] dst src mem) ->
237	(I64Store [8] dst (I64Load [8] src mem)
238		(I64Store dst (I64Load src mem) mem))
239(Move [3] dst src mem) ->
240	(I64Store8 [2] dst (I64Load8U [2] src mem)
241		(I64Store16 dst (I64Load16U src mem) mem))
242(Move [5] dst src mem) ->
243	(I64Store8 [4] dst (I64Load8U [4] src mem)
244		(I64Store32 dst (I64Load32U src mem) mem))
245(Move [6] dst src mem) ->
246	(I64Store16 [4] dst (I64Load16U [4] src mem)
247		(I64Store32 dst (I64Load32U src mem) mem))
248(Move [7] dst src mem) ->
249	(I64Store32 [3] dst (I64Load32U [3] src mem)
250		(I64Store32 dst (I64Load32U src mem) mem))
251(Move [s] dst src mem) && s > 8 && s < 16 ->
252	(I64Store [s-8] dst (I64Load [s-8] src mem)
253		(I64Store dst (I64Load src mem) mem))
254
255// Adjust moves to be a multiple of 16 bytes.
256(Move [s] dst src mem)
257	&& s > 16 && s%16 != 0 && s%16 <= 8 ->
258	(Move [s-s%16]
259		(OffPtr <dst.Type> dst [s%16])
260		(OffPtr <src.Type> src [s%16])
261		(I64Store dst (I64Load src mem) mem))
262(Move [s] dst src mem)
263	&& s > 16 && s%16 != 0 && s%16 > 8 ->
264	(Move [s-s%16]
265		(OffPtr <dst.Type> dst [s%16])
266		(OffPtr <src.Type> src [s%16])
267		(I64Store [8] dst (I64Load [8] src mem)
268			(I64Store dst (I64Load src mem) mem)))
269
270// Large copying uses helper.
271(Move [s] dst src mem) && s%8 == 0 ->
272	(LoweredMove [s/8] dst src mem)
273
274// Lowering Zero instructions
275(Zero [0] _ mem) -> mem
276(Zero [1] destptr mem) -> (I64Store8 destptr (I64Const [0]) mem)
277(Zero [2] destptr mem) -> (I64Store16 destptr (I64Const [0]) mem)
278(Zero [4] destptr mem) -> (I64Store32 destptr (I64Const [0]) mem)
279(Zero [8] destptr mem) -> (I64Store destptr (I64Const [0]) mem)
280
281(Zero [3] destptr mem) ->
282	(I64Store8 [2] destptr (I64Const [0])
283		(I64Store16 destptr (I64Const [0]) mem))
284(Zero [5] destptr mem) ->
285	(I64Store8 [4] destptr (I64Const [0])
286		(I64Store32 destptr (I64Const [0]) mem))
287(Zero [6] destptr mem) ->
288	(I64Store16 [4] destptr (I64Const [0])
289		(I64Store32 destptr (I64Const [0]) mem))
290(Zero [7] destptr mem) ->
291	(I64Store32 [3] destptr (I64Const [0])
292		(I64Store32 destptr (I64Const [0]) mem))
293
294// Strip off any fractional word zeroing.
295(Zero [s] destptr mem) && s%8 != 0 && s > 8 ->
296	(Zero [s-s%8] (OffPtr <destptr.Type> destptr [s%8])
297		(I64Store destptr (I64Const [0]) mem))
298
299// Zero small numbers of words directly.
300(Zero [16] destptr mem) ->
301	(I64Store [8] destptr (I64Const [0])
302		(I64Store destptr (I64Const [0]) mem))
303(Zero [24] destptr mem) ->
304	(I64Store [16] destptr (I64Const [0])
305		(I64Store [8] destptr (I64Const [0])
306			(I64Store destptr (I64Const [0]) mem)))
307(Zero [32] destptr mem) ->
308	(I64Store [24] destptr (I64Const [0])
309		(I64Store [16] destptr (I64Const [0])
310			(I64Store [8] destptr (I64Const [0])
311				(I64Store destptr (I64Const [0]) mem))))
312
313// Large zeroing uses helper.
314(Zero [s] destptr mem) && s%8 == 0 && s > 32 ->
315	(LoweredZero [s/8] destptr mem)
316
317// Lowering constants
318(Const(64|32|16|8) [val]) -> (I64Const [val])
319(Const(64|32)F [val]) -> (F(64|32)Const [val])
320(ConstNil) -> (I64Const [0])
321(ConstBool [b]) -> (I64Const [b])
322
323// Lowering calls
324(StaticCall [argwid] {target} mem) -> (LoweredStaticCall [argwid] {target} mem)
325(ClosureCall [argwid] entry closure mem) -> (LoweredClosureCall [argwid] entry closure mem)
326(InterCall [argwid] entry mem) -> (LoweredInterCall [argwid] entry mem)
327
328// Miscellaneous
329(Convert <t> x mem) -> (LoweredConvert <t> x mem)
330(IsNonNil p) -> (I64Eqz (I64Eqz p))
331(IsInBounds idx len) -> (I64LtU idx len)
332(IsSliceInBounds idx len) -> (I64LeU idx len)
333(NilCheck ptr mem) -> (LoweredNilCheck ptr mem)
334(GetClosurePtr) -> (LoweredGetClosurePtr)
335(GetCallerPC) -> (LoweredGetCallerPC)
336(GetCallerSP) -> (LoweredGetCallerSP)
337(Addr {sym} base) -> (LoweredAddr {sym} base)
338(LocalAddr {sym} base _) -> (LoweredAddr {sym} base)
339
340// Write barrier.
341(WB {fn} destptr srcptr mem) -> (LoweredWB {fn} destptr srcptr mem)
342
343// --- Intrinsics ---
344(Sqrt x) -> (F64Sqrt x)
345(Trunc x) -> (F64Trunc x)
346(Ceil x) -> (F64Ceil x)
347(Floor x) -> (F64Floor x)
348(RoundToEven x) -> (F64Nearest x)
349(Abs x) -> (F64Abs x)
350(Copysign x y) -> (F64Copysign x y)
351
352(Ctz64 x) -> (I64Ctz x)
353(Ctz32 x) -> (I64Ctz (I64Or x (I64Const [0x100000000])))
354(Ctz16 x) -> (I64Ctz (I64Or x (I64Const [0x10000])))
355(Ctz8  x) -> (I64Ctz (I64Or x (I64Const [0x100])))
356
357(Ctz(64|32|16|8)NonZero x) -> (I64Ctz x)
358
359(BitLen64 x) -> (I64Sub (I64Const [64]) (I64Clz x))
360
361(PopCount64 x) -> (I64Popcnt x)
362(PopCount32 x) -> (I64Popcnt (ZeroExt32to64 x))
363(PopCount16 x) -> (I64Popcnt (ZeroExt16to64 x))
364(PopCount8  x) -> (I64Popcnt (ZeroExt8to64  x))
365
366(CondSelect <t> x y cond) -> (Select <t> x y cond)
367
368// --- Optimizations ---
369(I64Add (I64Const [x]) (I64Const [y])) -> (I64Const [x + y])
370(I64Mul (I64Const [x]) (I64Const [y])) -> (I64Const [x * y])
371(I64And (I64Const [x]) (I64Const [y])) -> (I64Const [x & y])
372(I64Or  (I64Const [x]) (I64Const [y])) -> (I64Const [x | y])
373(I64Xor (I64Const [x]) (I64Const [y])) -> (I64Const [x ^ y])
374(F64Add (F64Const [x]) (F64Const [y])) -> (F64Const [auxFrom64F(auxTo64F(x) + auxTo64F(y))])
375(F64Mul (F64Const [x]) (F64Const [y])) -> (F64Const [auxFrom64F(auxTo64F(x) * auxTo64F(y))])
376(I64Eq  (I64Const [x]) (I64Const [y])) && x == y -> (I64Const [1])
377(I64Eq  (I64Const [x]) (I64Const [y])) && x != y -> (I64Const [0])
378(I64Ne  (I64Const [x]) (I64Const [y])) && x == y -> (I64Const [0])
379(I64Ne  (I64Const [x]) (I64Const [y])) && x != y -> (I64Const [1])
380
381(I64Shl (I64Const [x]) (I64Const [y])) -> (I64Const [x << uint64(y)])
382(I64ShrU (I64Const [x]) (I64Const [y])) -> (I64Const [int64(uint64(x) >> uint64(y))])
383(I64ShrS (I64Const [x]) (I64Const [y])) -> (I64Const [x >> uint64(y)])
384
385(I64Add (I64Const [x]) y) -> (I64Add y (I64Const [x]))
386(I64Mul (I64Const [x]) y) -> (I64Mul y (I64Const [x]))
387(I64And (I64Const [x]) y) -> (I64And y (I64Const [x]))
388(I64Or  (I64Const [x]) y) -> (I64Or  y (I64Const [x]))
389(I64Xor (I64Const [x]) y) -> (I64Xor y (I64Const [x]))
390(F64Add (F64Const [x]) y) -> (F64Add y (F64Const [x]))
391(F64Mul (F64Const [x]) y) -> (F64Mul y (F64Const [x]))
392(I64Eq  (I64Const [x]) y) -> (I64Eq y  (I64Const [x]))
393(I64Ne  (I64Const [x]) y) -> (I64Ne y  (I64Const [x]))
394
395(I64Eq x (I64Const [0])) -> (I64Eqz x)
396(I64Ne x (I64Const [0])) -> (I64Eqz (I64Eqz x))
397
398(I64Add x (I64Const [y])) -> (I64AddConst [y] x)
399(I64AddConst [0] x) -> x
400(I64Eqz (I64Eqz (I64Eqz x))) -> (I64Eqz x)
401
402// folding offset into load/store
403((I64Load|I64Load32U|I64Load32S|I64Load16U|I64Load16S|I64Load8U|I64Load8S) [off] (I64AddConst [off2] ptr) mem)
404	&& isU32Bit(off+off2) ->
405	((I64Load|I64Load32U|I64Load32S|I64Load16U|I64Load16S|I64Load8U|I64Load8S) [off+off2] ptr mem)
406
407((I64Store|I64Store32|I64Store16|I64Store8) [off] (I64AddConst [off2] ptr) val mem)
408	&& isU32Bit(off+off2) ->
409	((I64Store|I64Store32|I64Store16|I64Store8) [off+off2] ptr val mem)
410
411// folding offset into address
412(I64AddConst [off] (LoweredAddr {sym} [off2] base)) && isU32Bit(off+off2) ->
413	(LoweredAddr {sym} [off+off2] base)
414
415// transforming readonly globals into constants
416(I64Load [off] (LoweredAddr {sym} [off2] (SB)) _) && symIsRO(sym) && isU32Bit(off+off2) -> (I64Const [int64(read64(sym, off+off2, config.BigEndian))])
417(I64Load32U [off] (LoweredAddr {sym} [off2] (SB)) _) && symIsRO(sym) && isU32Bit(off+off2) -> (I64Const [int64(read32(sym, off+off2, config.BigEndian))])
418(I64Load16U [off] (LoweredAddr {sym} [off2] (SB)) _) && symIsRO(sym) && isU32Bit(off+off2) -> (I64Const [int64(read16(sym, off+off2, config.BigEndian))])
419(I64Load8U [off] (LoweredAddr {sym} [off2] (SB)) _) && symIsRO(sym) && isU32Bit(off+off2) -> (I64Const [int64(read8(sym, off+off2))])
420