1// Copyright 2016 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(Add(Ptr|64|32|16|8) x y) -> (ADDV x y)
6(Add(32|64)F x y) -> (ADD(F|D) x y)
7
8(Sub(Ptr|64|32|16|8) x y) -> (SUBV x y)
9(Sub(32|64)F x y) -> (SUB(F|D) x y)
10
11(Mul(64|32|16|8) x y) -> (Select1 (MULVU x y))
12(Mul(32|64)F x y) -> (MUL(F|D) x y)
13(Mul64uhilo x y) -> (MULVU x y)
14
15(Hmul64 x y) -> (Select0 (MULV x y))
16(Hmul64u x y) -> (Select0 (MULVU x y))
17(Hmul32 x y) -> (SRAVconst (Select1 <typ.Int64> (MULV (SignExt32to64 x) (SignExt32to64 y))) [32])
18(Hmul32u x y) -> (SRLVconst (Select1 <typ.UInt64> (MULVU (ZeroExt32to64 x) (ZeroExt32to64 y))) [32])
19
20(Div64 x y) -> (Select1 (DIVV x y))
21(Div64u x y) -> (Select1 (DIVVU x y))
22(Div32 x y) -> (Select1 (DIVV (SignExt32to64 x) (SignExt32to64 y)))
23(Div32u x y) -> (Select1 (DIVVU (ZeroExt32to64 x) (ZeroExt32to64 y)))
24(Div16 x y) -> (Select1 (DIVV (SignExt16to64 x) (SignExt16to64 y)))
25(Div16u x y) -> (Select1 (DIVVU (ZeroExt16to64 x) (ZeroExt16to64 y)))
26(Div8 x y) -> (Select1 (DIVV (SignExt8to64 x) (SignExt8to64 y)))
27(Div8u x y) -> (Select1 (DIVVU (ZeroExt8to64 x) (ZeroExt8to64 y)))
28(Div(32|64)F x y) -> (DIV(F|D) x y)
29
30(Mod64 x y) -> (Select0 (DIVV x y))
31(Mod64u x y) -> (Select0 (DIVVU x y))
32(Mod32 x y) -> (Select0 (DIVV (SignExt32to64 x) (SignExt32to64 y)))
33(Mod32u x y) -> (Select0 (DIVVU (ZeroExt32to64 x) (ZeroExt32to64 y)))
34(Mod16 x y) -> (Select0 (DIVV (SignExt16to64 x) (SignExt16to64 y)))
35(Mod16u x y) -> (Select0 (DIVVU (ZeroExt16to64 x) (ZeroExt16to64 y)))
36(Mod8 x y) -> (Select0 (DIVV (SignExt8to64 x) (SignExt8to64 y)))
37(Mod8u x y) -> (Select0 (DIVVU (ZeroExt8to64 x) (ZeroExt8to64 y)))
38
39// (x + y) / 2 with x>=y -> (x - y) / 2 + y
40(Avg64u <t> x y) -> (ADDV (SRLVconst <t> (SUBV <t> x y) [1]) y)
41
42(And(64|32|16|8) x y) -> (AND x y)
43(Or(64|32|16|8) x y) -> (OR x y)
44(Xor(64|32|16|8) x y) -> (XOR x y)
45
46// shifts
47// hardware instruction uses only the low 6 bits of the shift
48// we compare to 64 to ensure Go semantics for large shifts
49(Lsh64x64 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) y)) (SLLV <t> x y))
50(Lsh64x32 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
51(Lsh64x16 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
52(Lsh64x8  <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
53
54(Lsh32x64 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) y)) (SLLV <t> x y))
55(Lsh32x32 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
56(Lsh32x16 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
57(Lsh32x8  <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
58
59(Lsh16x64 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) y)) (SLLV <t> x y))
60(Lsh16x32 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
61(Lsh16x16 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
62(Lsh16x8  <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
63
64(Lsh8x64 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) y)) (SLLV <t> x y))
65(Lsh8x32 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
66(Lsh8x16 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
67(Lsh8x8  <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt8to64  y))) (SLLV <t> x (ZeroExt8to64  y)))
68
69(Rsh64Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) y)) (SRLV <t> x y))
70(Rsh64Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt32to64 y))) (SRLV <t> x (ZeroExt32to64 y)))
71(Rsh64Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt16to64 y))) (SRLV <t> x (ZeroExt16to64 y)))
72(Rsh64Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt8to64  y))) (SRLV <t> x (ZeroExt8to64  y)))
73
74(Rsh32Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) y)) (SRLV <t> (ZeroExt32to64 x) y))
75(Rsh32Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt32to64 y)))
76(Rsh32Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt16to64 y)))
77(Rsh32Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt8to64  y)))
78
79(Rsh16Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) y)) (SRLV <t> (ZeroExt16to64 x) y))
80(Rsh16Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt32to64 y)))
81(Rsh16Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt16to64 y)))
82(Rsh16Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt8to64  y)))
83
84(Rsh8Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) y)) (SRLV <t> (ZeroExt8to64 x) y))
85(Rsh8Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt32to64 y)))
86(Rsh8Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt16to64 y)))
87(Rsh8Ux8  <t> x y) -> (AND (NEGV <t> (SGTU (MOVVconst <typ.UInt64> [64]) (ZeroExt8to64  y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt8to64  y)))
88
89(Rsh64x64 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU y (MOVVconst <typ.UInt64> [63]))) y))
90(Rsh64x32 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt32to64 y)))
91(Rsh64x16 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt16to64 y)))
92(Rsh64x8  <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt8to64  y)))
93
94(Rsh32x64 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU y (MOVVconst <typ.UInt64> [63]))) y))
95(Rsh32x32 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt32to64 y)))
96(Rsh32x16 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt16to64 y)))
97(Rsh32x8  <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt8to64  y)))
98
99(Rsh16x64 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU y (MOVVconst <typ.UInt64> [63]))) y))
100(Rsh16x32 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt32to64 y)))
101(Rsh16x16 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt16to64 y)))
102(Rsh16x8  <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt8to64  y)))
103
104(Rsh8x64 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU y (MOVVconst <typ.UInt64> [63]))) y))
105(Rsh8x32 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt32to64 y)))
106(Rsh8x16 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt16to64 y)))
107(Rsh8x8  <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64  y) (MOVVconst <typ.UInt64> [63]))) (ZeroExt8to64  y)))
108
109// rotates
110(RotateLeft8 <t> x (MOVVconst [c])) -> (Or8 (Lsh8x64 <t> x (MOVVconst [c&7])) (Rsh8Ux64 <t> x (MOVVconst [-c&7])))
111(RotateLeft16 <t> x (MOVVconst [c])) -> (Or16 (Lsh16x64 <t> x (MOVVconst [c&15])) (Rsh16Ux64 <t> x (MOVVconst [-c&15])))
112(RotateLeft32 <t> x (MOVVconst [c])) -> (Or32 (Lsh32x64 <t> x (MOVVconst [c&31])) (Rsh32Ux64 <t> x (MOVVconst [-c&31])))
113(RotateLeft64 <t> x (MOVVconst [c])) -> (Or64 (Lsh64x64 <t> x (MOVVconst [c&63])) (Rsh64Ux64 <t> x (MOVVconst [-c&63])))
114
115// unary ops
116(Neg(64|32|16|8) x) -> (NEGV x)
117(Neg(32|64)F x) -> (NEG(F|D) x)
118
119(Com(64|32|16|8) x) -> (NOR (MOVVconst [0]) x)
120
121(Sqrt x) -> (SQRTD x)
122
123// boolean ops -- booleans are represented with 0=false, 1=true
124(AndB x y) -> (AND x y)
125(OrB x y) -> (OR x y)
126(EqB x y) -> (XOR (MOVVconst [1]) (XOR <typ.Bool> x y))
127(NeqB x y) -> (XOR x y)
128(Not x) -> (XORconst [1] x)
129
130// constants
131(Const(64|32|16|8) [val]) -> (MOVVconst [val])
132(Const(32|64)F [val]) -> (MOV(F|D)const [val])
133(ConstNil) -> (MOVVconst [0])
134(ConstBool [b]) -> (MOVVconst [b])
135
136(Slicemask <t> x) -> (SRAVconst (NEGV <t> x) [63])
137
138// truncations
139// Because we ignore high parts of registers, truncates are just copies.
140(Trunc16to8 x) -> x
141(Trunc32to8 x) -> x
142(Trunc32to16 x) -> x
143(Trunc64to8 x) -> x
144(Trunc64to16 x) -> x
145(Trunc64to32 x) -> x
146
147// Zero-/Sign-extensions
148(ZeroExt8to16 x) -> (MOVBUreg x)
149(ZeroExt8to32 x) -> (MOVBUreg x)
150(ZeroExt16to32 x) -> (MOVHUreg x)
151(ZeroExt8to64 x) -> (MOVBUreg x)
152(ZeroExt16to64 x) -> (MOVHUreg x)
153(ZeroExt32to64 x) -> (MOVWUreg x)
154
155(SignExt8to16 x) -> (MOVBreg x)
156(SignExt8to32 x) -> (MOVBreg x)
157(SignExt16to32 x) -> (MOVHreg x)
158(SignExt8to64 x) -> (MOVBreg x)
159(SignExt16to64 x) -> (MOVHreg x)
160(SignExt32to64 x) -> (MOVWreg x)
161
162// float <-> int conversion
163(Cvt32to32F x) -> (MOVWF x)
164(Cvt32to64F x) -> (MOVWD x)
165(Cvt64to32F x) -> (MOVVF x)
166(Cvt64to64F x) -> (MOVVD x)
167(Cvt32Fto32 x) -> (TRUNCFW x)
168(Cvt64Fto32 x) -> (TRUNCDW x)
169(Cvt32Fto64 x) -> (TRUNCFV x)
170(Cvt64Fto64 x) -> (TRUNCDV x)
171(Cvt32Fto64F x) -> (MOVFD x)
172(Cvt64Fto32F x) -> (MOVDF x)
173
174(Round(32|64)F x) -> x
175
176// comparisons
177(Eq8 x y)  -> (SGTU (MOVVconst [1]) (XOR (ZeroExt8to64 x) (ZeroExt8to64 y)))
178(Eq16 x y) -> (SGTU (MOVVconst [1]) (XOR (ZeroExt16to64 x) (ZeroExt16to64 y)))
179(Eq32 x y) -> (SGTU (MOVVconst [1]) (XOR (ZeroExt32to64 x) (ZeroExt32to64 y)))
180(Eq64 x y) -> (SGTU (MOVVconst [1]) (XOR x y))
181(EqPtr x y) -> (SGTU (MOVVconst [1]) (XOR x y))
182(Eq(32|64)F x y) -> (FPFlagTrue (CMPEQ(F|D) x y))
183
184(Neq8 x y)  -> (SGTU (XOR (ZeroExt8to64 x) (ZeroExt8to64 y)) (MOVVconst [0]))
185(Neq16 x y) -> (SGTU (XOR (ZeroExt16to32 x) (ZeroExt16to64 y)) (MOVVconst [0]))
186(Neq32 x y) -> (SGTU (XOR (ZeroExt32to64 x) (ZeroExt32to64 y)) (MOVVconst [0]))
187(Neq64 x y) -> (SGTU (XOR x y) (MOVVconst [0]))
188(NeqPtr x y) -> (SGTU (XOR x y) (MOVVconst [0]))
189(Neq(32|64)F x y) -> (FPFlagFalse (CMPEQ(F|D) x y))
190
191(Less8 x y)  -> (SGT (SignExt8to64 y) (SignExt8to64 x))
192(Less16 x y) -> (SGT (SignExt16to64 y) (SignExt16to64 x))
193(Less32 x y) -> (SGT (SignExt32to64 y) (SignExt32to64 x))
194(Less64 x y) -> (SGT y x)
195(Less(32|64)F x y) -> (FPFlagTrue (CMPGT(F|D) y x)) // reverse operands to work around NaN
196
197(Less8U x y)  -> (SGTU (ZeroExt8to64 y) (ZeroExt8to64 x))
198(Less16U x y) -> (SGTU (ZeroExt16to64 y) (ZeroExt16to64 x))
199(Less32U x y) -> (SGTU (ZeroExt32to64 y) (ZeroExt32to64 x))
200(Less64U x y) -> (SGTU y x)
201
202(Leq8 x y)  -> (XOR (MOVVconst [1]) (SGT (SignExt8to64 x) (SignExt8to64 y)))
203(Leq16 x y) -> (XOR (MOVVconst [1]) (SGT (SignExt16to64 x) (SignExt16to64 y)))
204(Leq32 x y) -> (XOR (MOVVconst [1]) (SGT (SignExt32to64 x) (SignExt32to64 y)))
205(Leq64 x y) -> (XOR (MOVVconst [1]) (SGT x y))
206(Leq(32|64)F x y) -> (FPFlagTrue (CMPGE(F|D) y x)) // reverse operands to work around NaN
207
208(Leq8U x y)  -> (XOR (MOVVconst [1]) (SGTU (ZeroExt8to64 x) (ZeroExt8to64 y)))
209(Leq16U x y) -> (XOR (MOVVconst [1]) (SGTU (ZeroExt16to64 x) (ZeroExt16to64 y)))
210(Leq32U x y) -> (XOR (MOVVconst [1]) (SGTU (ZeroExt32to64 x) (ZeroExt32to64 y)))
211(Leq64U x y) -> (XOR (MOVVconst [1]) (SGTU x y))
212
213(Greater8 x y)  -> (SGT (SignExt8to64 x) (SignExt8to64 y))
214(Greater16 x y) -> (SGT (SignExt16to64 x) (SignExt16to64 y))
215(Greater32 x y) -> (SGT (SignExt32to64 x) (SignExt32to64 y))
216(Greater64 x y) -> (SGT x y)
217(Greater(32|64)F x y) -> (FPFlagTrue (CMPGT(F|D) x y))
218
219(Greater8U x y)  -> (SGTU (ZeroExt8to64 x) (ZeroExt8to64 y))
220(Greater16U x y) -> (SGTU (ZeroExt16to64 x) (ZeroExt16to64 y))
221(Greater32U x y) -> (SGTU (ZeroExt32to64 x) (ZeroExt32to64 y))
222(Greater64U x y) -> (SGTU x y)
223
224(Geq8 x y)  -> (XOR (MOVVconst [1]) (SGT (SignExt8to64 y) (SignExt8to64 x)))
225(Geq16 x y) -> (XOR (MOVVconst [1]) (SGT (SignExt16to64 y) (SignExt16to64 x)))
226(Geq32 x y) -> (XOR (MOVVconst [1]) (SGT (SignExt32to64 y) (SignExt32to64 x)))
227(Geq64 x y) -> (XOR (MOVVconst [1]) (SGT y x))
228(Geq(32|64)F x y) -> (FPFlagTrue (CMPGE(F|D) x y))
229
230(Geq8U x y)  -> (XOR (MOVVconst [1]) (SGTU (ZeroExt8to64 y) (ZeroExt8to64 x)))
231(Geq16U x y) -> (XOR (MOVVconst [1]) (SGTU (ZeroExt16to64 y) (ZeroExt16to64 x)))
232(Geq32U x y) -> (XOR (MOVVconst [1]) (SGTU (ZeroExt32to64 y) (ZeroExt32to64 x)))
233(Geq64U x y) -> (XOR (MOVVconst [1]) (SGTU y x))
234
235(OffPtr [off] ptr:(SP)) -> (MOVVaddr [off] ptr)
236(OffPtr [off] ptr) -> (ADDVconst [off] ptr)
237
238(Addr {sym} base) -> (MOVVaddr {sym} base)
239(LocalAddr {sym} base _) -> (MOVVaddr {sym} base)
240
241// loads
242(Load <t> ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem)
243(Load <t> ptr mem) && (is8BitInt(t) && isSigned(t)) -> (MOVBload ptr mem)
244(Load <t> ptr mem) && (is8BitInt(t) && !isSigned(t)) -> (MOVBUload ptr mem)
245(Load <t> ptr mem) && (is16BitInt(t) && isSigned(t)) -> (MOVHload ptr mem)
246(Load <t> ptr mem) && (is16BitInt(t) && !isSigned(t)) -> (MOVHUload ptr mem)
247(Load <t> ptr mem) && (is32BitInt(t) && isSigned(t)) -> (MOVWload ptr mem)
248(Load <t> ptr mem) && (is32BitInt(t) && !isSigned(t)) -> (MOVWUload ptr mem)
249(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVVload ptr mem)
250(Load <t> ptr mem) && is32BitFloat(t) -> (MOVFload ptr mem)
251(Load <t> ptr mem) && is64BitFloat(t) -> (MOVDload ptr mem)
252
253// stores
254(Store {t} ptr val mem) && t.(*types.Type).Size() == 1 -> (MOVBstore ptr val mem)
255(Store {t} ptr val mem) && t.(*types.Type).Size() == 2 -> (MOVHstore ptr val mem)
256(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && !is32BitFloat(val.Type) -> (MOVWstore ptr val mem)
257(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 && !is64BitFloat(val.Type) -> (MOVVstore ptr val mem)
258(Store {t} ptr val mem) && t.(*types.Type).Size() == 4 && is32BitFloat(val.Type) -> (MOVFstore ptr val mem)
259(Store {t} ptr val mem) && t.(*types.Type).Size() == 8 && is64BitFloat(val.Type) -> (MOVDstore ptr val mem)
260
261// zeroing
262(Zero [0] _ mem) -> mem
263(Zero [1] ptr mem) -> (MOVBstore ptr (MOVVconst [0]) mem)
264(Zero [2] {t} ptr mem) && t.(*types.Type).Alignment()%2 == 0 ->
265	(MOVHstore ptr (MOVVconst [0]) mem)
266(Zero [2] ptr mem) ->
267	(MOVBstore [1] ptr (MOVVconst [0])
268		(MOVBstore [0] ptr (MOVVconst [0]) mem))
269(Zero [4] {t} ptr mem) && t.(*types.Type).Alignment()%4 == 0 ->
270	(MOVWstore ptr (MOVVconst [0]) mem)
271(Zero [4] {t} ptr mem) && t.(*types.Type).Alignment()%2 == 0 ->
272	(MOVHstore [2] ptr (MOVVconst [0])
273		(MOVHstore [0] ptr (MOVVconst [0]) mem))
274(Zero [4] ptr mem) ->
275	(MOVBstore [3] ptr (MOVVconst [0])
276		(MOVBstore [2] ptr (MOVVconst [0])
277			(MOVBstore [1] ptr (MOVVconst [0])
278				(MOVBstore [0] ptr (MOVVconst [0]) mem))))
279(Zero [8] {t} ptr mem) && t.(*types.Type).Alignment()%8 == 0 ->
280	(MOVVstore ptr (MOVVconst [0]) mem)
281(Zero [8] {t} ptr mem) && t.(*types.Type).Alignment()%4 == 0 ->
282	(MOVWstore [4] ptr (MOVVconst [0])
283		(MOVWstore [0] ptr (MOVVconst [0]) mem))
284(Zero [8] {t} ptr mem) && t.(*types.Type).Alignment()%2 == 0 ->
285	(MOVHstore [6] ptr (MOVVconst [0])
286		(MOVHstore [4] ptr (MOVVconst [0])
287			(MOVHstore [2] ptr (MOVVconst [0])
288				(MOVHstore [0] ptr (MOVVconst [0]) mem))))
289
290(Zero [3] ptr mem) ->
291	(MOVBstore [2] ptr (MOVVconst [0])
292		(MOVBstore [1] ptr (MOVVconst [0])
293			(MOVBstore [0] ptr (MOVVconst [0]) mem)))
294(Zero [6] {t} ptr mem) && t.(*types.Type).Alignment()%2 == 0 ->
295	(MOVHstore [4] ptr (MOVVconst [0])
296		(MOVHstore [2] ptr (MOVVconst [0])
297			(MOVHstore [0] ptr (MOVVconst [0]) mem)))
298(Zero [12] {t} ptr mem) && t.(*types.Type).Alignment()%4 == 0 ->
299	(MOVWstore [8] ptr (MOVVconst [0])
300		(MOVWstore [4] ptr (MOVVconst [0])
301			(MOVWstore [0] ptr (MOVVconst [0]) mem)))
302(Zero [16] {t} ptr mem) && t.(*types.Type).Alignment()%8 == 0 ->
303	(MOVVstore [8] ptr (MOVVconst [0])
304		(MOVVstore [0] ptr (MOVVconst [0]) mem))
305(Zero [24] {t} ptr mem) && t.(*types.Type).Alignment()%8 == 0 ->
306	(MOVVstore [16] ptr (MOVVconst [0])
307		(MOVVstore [8] ptr (MOVVconst [0])
308			(MOVVstore [0] ptr (MOVVconst [0]) mem)))
309
310// medium zeroing uses a duff device
311// 8, and 128 are magic constants, see runtime/mkduff.go
312(Zero [s] {t} ptr mem)
313	&& s%8 == 0 && s > 24 && s <= 8*128
314	&& t.(*types.Type).Alignment()%8 == 0 && !config.noDuffDevice ->
315	(DUFFZERO [8 * (128 - s/8)] ptr mem)
316
317// large or unaligned zeroing uses a loop
318(Zero [s] {t} ptr mem)
319	&& (s > 8*128 || config.noDuffDevice) || t.(*types.Type).Alignment()%8 != 0 ->
320	(LoweredZero [t.(*types.Type).Alignment()]
321		ptr
322		(ADDVconst <ptr.Type> ptr [s-moveSize(t.(*types.Type).Alignment(), config)])
323		mem)
324
325// moves
326(Move [0] _ _ mem) -> mem
327(Move [1] dst src mem) -> (MOVBstore dst (MOVBload src mem) mem)
328(Move [2] {t} dst src mem) && t.(*types.Type).Alignment()%2 == 0 ->
329	(MOVHstore dst (MOVHload src mem) mem)
330(Move [2] dst src mem) ->
331	(MOVBstore [1] dst (MOVBload [1] src mem)
332		(MOVBstore dst (MOVBload src mem) mem))
333(Move [4] {t} dst src mem) && t.(*types.Type).Alignment()%4 == 0 ->
334	(MOVWstore dst (MOVWload src mem) mem)
335(Move [4] {t} dst src mem) && t.(*types.Type).Alignment()%2 == 0 ->
336	(MOVHstore [2] dst (MOVHload [2] src mem)
337		(MOVHstore dst (MOVHload src mem) mem))
338(Move [4] dst src mem) ->
339	(MOVBstore [3] dst (MOVBload [3] src mem)
340		(MOVBstore [2] dst (MOVBload [2] src mem)
341			(MOVBstore [1] dst (MOVBload [1] src mem)
342				(MOVBstore dst (MOVBload src mem) mem))))
343(Move [8] {t} dst src mem) && t.(*types.Type).Alignment()%8 == 0 ->
344	(MOVVstore dst (MOVVload src mem) mem)
345(Move [8] {t} dst src mem) && t.(*types.Type).Alignment()%4 == 0 ->
346	(MOVWstore [4] dst (MOVWload [4] src mem)
347		(MOVWstore dst (MOVWload src mem) mem))
348(Move [8] {t} dst src mem) && t.(*types.Type).Alignment()%2 == 0 ->
349	(MOVHstore [6] dst (MOVHload [6] src mem)
350		(MOVHstore [4] dst (MOVHload [4] src mem)
351			(MOVHstore [2] dst (MOVHload [2] src mem)
352				(MOVHstore dst (MOVHload src mem) mem))))
353
354(Move [3] dst src mem) ->
355	(MOVBstore [2] dst (MOVBload [2] src mem)
356		(MOVBstore [1] dst (MOVBload [1] src mem)
357			(MOVBstore dst (MOVBload src mem) mem)))
358(Move [6] {t} dst src mem) && t.(*types.Type).Alignment()%2 == 0 ->
359	(MOVHstore [4] dst (MOVHload [4] src mem)
360		(MOVHstore [2] dst (MOVHload [2] src mem)
361			(MOVHstore dst (MOVHload src mem) mem)))
362(Move [12] {t} dst src mem) && t.(*types.Type).Alignment()%4 == 0 ->
363	(MOVWstore [8] dst (MOVWload [8] src mem)
364		(MOVWstore [4] dst (MOVWload [4] src mem)
365			(MOVWstore dst (MOVWload src mem) mem)))
366(Move [16] {t} dst src mem) && t.(*types.Type).Alignment()%8 == 0 ->
367	(MOVVstore [8] dst (MOVVload [8] src mem)
368		(MOVVstore dst (MOVVload src mem) mem))
369(Move [24] {t} dst src mem) && t.(*types.Type).Alignment()%8 == 0 ->
370	(MOVVstore [16] dst (MOVVload [16] src mem)
371		(MOVVstore [8] dst (MOVVload [8] src mem)
372			(MOVVstore dst (MOVVload src mem) mem)))
373
374// medium move uses a duff device
375(Move [s] {t} dst src mem)
376	&& s%8 == 0 && s >= 24 && s <= 8*128 && t.(*types.Type).Alignment()%8 == 0
377	&& !config.noDuffDevice ->
378	(DUFFCOPY [16 * (128 - s/8)] dst src mem)
379// 16 and 128 are magic constants.  16 is the number of bytes to encode:
380//	MOVV	(R1), R23
381//	ADDV	$8, R1
382//	MOVV	R23, (R2)
383//	ADDV	$8, R2
384// and 128 is the number of such blocks. See runtime/duff_mips64.s:duffcopy.
385
386// large or unaligned move uses a loop
387(Move [s] {t} dst src mem)
388	&& s > 24 || t.(*types.Type).Alignment()%8 != 0 ->
389	(LoweredMove [t.(*types.Type).Alignment()]
390		dst
391		src
392		(ADDVconst <src.Type> src [s-moveSize(t.(*types.Type).Alignment(), config)])
393		mem)
394
395// calls
396(StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem)
397(ClosureCall [argwid] entry closure mem) -> (CALLclosure [argwid] entry closure mem)
398(InterCall [argwid] entry mem) -> (CALLinter [argwid] entry mem)
399
400// atomic intrinsics
401(AtomicLoad8   ptr mem) -> (LoweredAtomicLoad8  ptr mem)
402(AtomicLoad32  ptr mem) -> (LoweredAtomicLoad32 ptr mem)
403(AtomicLoad64  ptr mem) -> (LoweredAtomicLoad64 ptr mem)
404(AtomicLoadPtr ptr mem) -> (LoweredAtomicLoad64 ptr mem)
405
406(AtomicStore8       ptr val mem) -> (LoweredAtomicStore8  ptr val mem)
407(AtomicStore32      ptr val mem) -> (LoweredAtomicStore32 ptr val mem)
408(AtomicStore64      ptr val mem) -> (LoweredAtomicStore64 ptr val mem)
409(AtomicStorePtrNoWB ptr val mem) -> (LoweredAtomicStore64 ptr val mem)
410
411(AtomicExchange32 ptr val mem) -> (LoweredAtomicExchange32 ptr val mem)
412(AtomicExchange64 ptr val mem) -> (LoweredAtomicExchange64 ptr val mem)
413
414(AtomicAdd32 ptr val mem) -> (LoweredAtomicAdd32 ptr val mem)
415(AtomicAdd64 ptr val mem) -> (LoweredAtomicAdd64 ptr val mem)
416
417(AtomicCompareAndSwap32 ptr old new_ mem) -> (LoweredAtomicCas32 ptr old new_ mem)
418(AtomicCompareAndSwap64 ptr old new_ mem) -> (LoweredAtomicCas64 ptr old new_ mem)
419
420// checks
421(NilCheck ptr mem) -> (LoweredNilCheck ptr mem)
422(IsNonNil ptr) -> (SGTU ptr (MOVVconst [0]))
423(IsInBounds idx len) -> (SGTU len idx)
424(IsSliceInBounds idx len) -> (XOR (MOVVconst [1]) (SGTU idx len))
425
426// pseudo-ops
427(GetClosurePtr) -> (LoweredGetClosurePtr)
428(GetCallerSP) -> (LoweredGetCallerSP)
429(GetCallerPC) -> (LoweredGetCallerPC)
430
431(If cond yes no) -> (NE cond yes no)
432
433// Write barrier.
434(WB {fn} destptr srcptr mem) -> (LoweredWB {fn} destptr srcptr mem)
435
436(PanicBounds [kind] x y mem) && boundsABI(kind) == 0 -> (LoweredPanicBoundsA [kind] x y mem)
437(PanicBounds [kind] x y mem) && boundsABI(kind) == 1 -> (LoweredPanicBoundsB [kind] x y mem)
438(PanicBounds [kind] x y mem) && boundsABI(kind) == 2 -> (LoweredPanicBoundsC [kind] x y mem)
439
440// Optimizations
441
442// Absorb boolean tests into block
443(NE (FPFlagTrue cmp) yes no) -> (FPT cmp yes no)
444(NE (FPFlagFalse cmp) yes no) -> (FPF cmp yes no)
445(EQ (FPFlagTrue cmp) yes no) -> (FPF cmp yes no)
446(EQ (FPFlagFalse cmp) yes no) -> (FPT cmp yes no)
447(NE (XORconst [1] cmp:(SGT _ _)) yes no) -> (EQ cmp yes no)
448(NE (XORconst [1] cmp:(SGTU _ _)) yes no) -> (EQ cmp yes no)
449(NE (XORconst [1] cmp:(SGTconst _)) yes no) -> (EQ cmp yes no)
450(NE (XORconst [1] cmp:(SGTUconst _)) yes no) -> (EQ cmp yes no)
451(EQ (XORconst [1] cmp:(SGT _ _)) yes no) -> (NE cmp yes no)
452(EQ (XORconst [1] cmp:(SGTU _ _)) yes no) -> (NE cmp yes no)
453(EQ (XORconst [1] cmp:(SGTconst _)) yes no) -> (NE cmp yes no)
454(EQ (XORconst [1] cmp:(SGTUconst _)) yes no) -> (NE cmp yes no)
455(NE (SGTUconst [1] x) yes no) -> (EQ x yes no)
456(EQ (SGTUconst [1] x) yes no) -> (NE x yes no)
457(NE (SGTU x (MOVVconst [0])) yes no) -> (NE x yes no)
458(EQ (SGTU x (MOVVconst [0])) yes no) -> (EQ x yes no)
459(NE (SGTconst [0] x) yes no) -> (LTZ x yes no)
460(EQ (SGTconst [0] x) yes no) -> (GEZ x yes no)
461(NE (SGT x (MOVVconst [0])) yes no) -> (GTZ x yes no)
462(EQ (SGT x (MOVVconst [0])) yes no) -> (LEZ x yes no)
463
464// fold offset into address
465(ADDVconst [off1] (MOVVaddr [off2] {sym} ptr)) -> (MOVVaddr [off1+off2] {sym} ptr)
466
467// fold address into load/store
468(MOVBload  [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVBload  [off1+off2] {sym} ptr mem)
469(MOVBUload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVBUload [off1+off2] {sym} ptr mem)
470(MOVHload  [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVHload  [off1+off2] {sym} ptr mem)
471(MOVHUload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVHUload [off1+off2] {sym} ptr mem)
472(MOVWload  [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVWload  [off1+off2] {sym} ptr mem)
473(MOVWUload [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVWUload [off1+off2] {sym} ptr mem)
474(MOVVload  [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVVload  [off1+off2] {sym} ptr mem)
475(MOVFload  [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVFload  [off1+off2] {sym} ptr mem)
476(MOVDload  [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVDload  [off1+off2] {sym} ptr mem)
477
478(MOVBstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVBstore [off1+off2] {sym} ptr val mem)
479(MOVHstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVHstore [off1+off2] {sym} ptr val mem)
480(MOVWstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVWstore [off1+off2] {sym} ptr val mem)
481(MOVVstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVVstore [off1+off2] {sym} ptr val mem)
482(MOVFstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVFstore [off1+off2] {sym} ptr val mem)
483(MOVDstore [off1] {sym} (ADDVconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVDstore [off1+off2] {sym} ptr val mem)
484(MOVBstorezero [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVBstorezero [off1+off2] {sym} ptr mem)
485(MOVHstorezero [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVHstorezero [off1+off2] {sym} ptr mem)
486(MOVWstorezero [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVWstorezero [off1+off2] {sym} ptr mem)
487(MOVVstorezero [off1] {sym} (ADDVconst [off2] ptr) mem) && is32Bit(off1+off2) -> (MOVVstorezero [off1+off2] {sym} ptr mem)
488
489(MOVBload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
490	(MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
491(MOVBUload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
492	(MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
493(MOVHload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
494	(MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
495(MOVHUload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
496	(MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
497(MOVWload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
498	(MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
499(MOVWUload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
500	(MOVWUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
501(MOVVload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
502	(MOVVload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
503(MOVFload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
504	(MOVFload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
505(MOVDload [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
506	(MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
507
508(MOVBstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
509	(MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
510(MOVHstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
511	(MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
512(MOVWstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
513	(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
514(MOVVstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
515	(MOVVstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
516(MOVFstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
517	(MOVFstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
518(MOVDstore [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
519	(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
520(MOVBstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
521	(MOVBstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
522(MOVHstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
523	(MOVHstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
524(MOVWstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
525	(MOVWstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
526(MOVVstorezero [off1] {sym1} (MOVVaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) && is32Bit(off1+off2) ->
527	(MOVVstorezero [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
528
529// store zero
530(MOVBstore [off] {sym} ptr (MOVVconst [0]) mem) -> (MOVBstorezero [off] {sym} ptr mem)
531(MOVHstore [off] {sym} ptr (MOVVconst [0]) mem) -> (MOVHstorezero [off] {sym} ptr mem)
532(MOVWstore [off] {sym} ptr (MOVVconst [0]) mem) -> (MOVWstorezero [off] {sym} ptr mem)
533(MOVVstore [off] {sym} ptr (MOVVconst [0]) mem) -> (MOVVstorezero [off] {sym} ptr mem)
534
535// don't extend after proper load
536(MOVBreg x:(MOVBload _ _)) -> (MOVVreg x)
537(MOVBUreg x:(MOVBUload _ _)) -> (MOVVreg x)
538(MOVHreg x:(MOVBload _ _)) -> (MOVVreg x)
539(MOVHreg x:(MOVBUload _ _)) -> (MOVVreg x)
540(MOVHreg x:(MOVHload _ _)) -> (MOVVreg x)
541(MOVHUreg x:(MOVBUload _ _)) -> (MOVVreg x)
542(MOVHUreg x:(MOVHUload _ _)) -> (MOVVreg x)
543(MOVWreg x:(MOVBload _ _)) -> (MOVVreg x)
544(MOVWreg x:(MOVBUload _ _)) -> (MOVVreg x)
545(MOVWreg x:(MOVHload _ _)) -> (MOVVreg x)
546(MOVWreg x:(MOVHUload _ _)) -> (MOVVreg x)
547(MOVWreg x:(MOVWload _ _)) -> (MOVVreg x)
548(MOVWUreg x:(MOVBUload _ _)) -> (MOVVreg x)
549(MOVWUreg x:(MOVHUload _ _)) -> (MOVVreg x)
550(MOVWUreg x:(MOVWUload _ _)) -> (MOVVreg x)
551
552// fold double extensions
553(MOVBreg x:(MOVBreg _)) -> (MOVVreg x)
554(MOVBUreg x:(MOVBUreg _)) -> (MOVVreg x)
555(MOVHreg x:(MOVBreg _)) -> (MOVVreg x)
556(MOVHreg x:(MOVBUreg _)) -> (MOVVreg x)
557(MOVHreg x:(MOVHreg _)) -> (MOVVreg x)
558(MOVHUreg x:(MOVBUreg _)) -> (MOVVreg x)
559(MOVHUreg x:(MOVHUreg _)) -> (MOVVreg x)
560(MOVWreg x:(MOVBreg _)) -> (MOVVreg x)
561(MOVWreg x:(MOVBUreg _)) -> (MOVVreg x)
562(MOVWreg x:(MOVHreg _)) -> (MOVVreg x)
563(MOVWreg x:(MOVHreg _)) -> (MOVVreg x)
564(MOVWreg x:(MOVWreg _)) -> (MOVVreg x)
565(MOVWUreg x:(MOVBUreg _)) -> (MOVVreg x)
566(MOVWUreg x:(MOVHUreg _)) -> (MOVVreg x)
567(MOVWUreg x:(MOVWUreg _)) -> (MOVVreg x)
568
569// don't extend before store
570(MOVBstore [off] {sym} ptr (MOVBreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
571(MOVBstore [off] {sym} ptr (MOVBUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
572(MOVBstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
573(MOVBstore [off] {sym} ptr (MOVHUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
574(MOVBstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
575(MOVBstore [off] {sym} ptr (MOVWUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
576(MOVHstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
577(MOVHstore [off] {sym} ptr (MOVHUreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
578(MOVHstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
579(MOVHstore [off] {sym} ptr (MOVWUreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
580(MOVWstore [off] {sym} ptr (MOVWreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
581(MOVWstore [off] {sym} ptr (MOVWUreg x) mem) -> (MOVWstore [off] {sym} ptr x mem)
582
583// if a register move has only 1 use, just use the same register without emitting instruction
584// MOVVnop doesn't emit instruction, only for ensuring the type.
585(MOVVreg x) && x.Uses == 1 -> (MOVVnop x)
586
587// fold constant into arithmatic ops
588(ADDV x (MOVVconst [c])) && is32Bit(c) -> (ADDVconst [c] x)
589(SUBV x (MOVVconst [c])) && is32Bit(c) -> (SUBVconst [c] x)
590(AND x (MOVVconst [c])) && is32Bit(c) -> (ANDconst [c] x)
591(OR  x (MOVVconst [c])) && is32Bit(c) -> (ORconst  [c] x)
592(XOR x (MOVVconst [c])) && is32Bit(c) -> (XORconst [c] x)
593(NOR x (MOVVconst [c])) && is32Bit(c) -> (NORconst [c] x)
594
595(SLLV _ (MOVVconst [c])) && uint64(c)>=64 -> (MOVVconst [0])
596(SRLV _ (MOVVconst [c])) && uint64(c)>=64 -> (MOVVconst [0])
597(SRAV x (MOVVconst [c])) && uint64(c)>=64 -> (SRAVconst x [63])
598(SLLV x (MOVVconst [c])) -> (SLLVconst x [c])
599(SRLV x (MOVVconst [c])) -> (SRLVconst x [c])
600(SRAV x (MOVVconst [c])) -> (SRAVconst x [c])
601
602(SGT  (MOVVconst [c]) x) && is32Bit(c) -> (SGTconst  [c] x)
603(SGTU (MOVVconst [c]) x) && is32Bit(c) -> (SGTUconst [c] x)
604
605// mul by constant
606(Select1 (MULVU x (MOVVconst [-1]))) -> (NEGV x)
607(Select1 (MULVU _ (MOVVconst [0]))) -> (MOVVconst [0])
608(Select1 (MULVU x (MOVVconst [1]))) -> x
609(Select1 (MULVU x (MOVVconst [c]))) && isPowerOfTwo(c) -> (SLLVconst [log2(c)] x)
610
611(Select1 (MULVU (MOVVconst [-1]) x)) -> (NEGV x)
612(Select1 (MULVU (MOVVconst [0]) _)) -> (MOVVconst [0])
613(Select1 (MULVU (MOVVconst [1]) x)) -> x
614(Select1 (MULVU (MOVVconst [c]) x)) && isPowerOfTwo(c) -> (SLLVconst [log2(c)] x)
615
616// div by constant
617(Select1 (DIVVU x (MOVVconst [1]))) -> x
618(Select1 (DIVVU x (MOVVconst [c]))) && isPowerOfTwo(c) -> (SRLVconst [log2(c)] x)
619(Select0 (DIVVU _ (MOVVconst [1]))) -> (MOVVconst [0])                       // mod
620(Select0 (DIVVU x (MOVVconst [c]))) && isPowerOfTwo(c) -> (ANDconst [c-1] x) // mod
621
622// generic simplifications
623(ADDV x (NEGV y)) -> (SUBV x y)
624(SUBV x x) -> (MOVVconst [0])
625(SUBV (MOVVconst [0]) x) -> (NEGV x)
626(AND x x) -> x
627(OR  x x) -> x
628(XOR x x) -> (MOVVconst [0])
629
630// remove redundant *const ops
631(ADDVconst [0]  x) -> x
632(SUBVconst [0]  x) -> x
633(ANDconst [0]  _) -> (MOVVconst [0])
634(ANDconst [-1] x) -> x
635(ORconst  [0]  x) -> x
636(ORconst  [-1] _) -> (MOVVconst [-1])
637(XORconst [0]  x) -> x
638(XORconst [-1] x) -> (NORconst [0] x)
639
640// generic constant folding
641(ADDVconst [c] (MOVVconst [d]))  -> (MOVVconst [c+d])
642(ADDVconst [c] (ADDVconst [d] x)) && is32Bit(c+d) -> (ADDVconst [c+d] x)
643(ADDVconst [c] (SUBVconst [d] x)) && is32Bit(c-d) -> (ADDVconst [c-d] x)
644(SUBVconst [c] (MOVVconst [d]))  -> (MOVVconst [d-c])
645(SUBVconst [c] (SUBVconst [d] x)) && is32Bit(-c-d) -> (ADDVconst [-c-d] x)
646(SUBVconst [c] (ADDVconst [d] x)) && is32Bit(-c+d) -> (ADDVconst [-c+d] x)
647(SLLVconst [c] (MOVVconst [d]))  -> (MOVVconst [d<<uint64(c)])
648(SRLVconst [c] (MOVVconst [d]))  -> (MOVVconst [int64(uint64(d)>>uint64(c))])
649(SRAVconst [c] (MOVVconst [d]))  -> (MOVVconst [d>>uint64(c)])
650(Select1 (MULVU (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [c*d])
651(Select1 (DIVV  (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [c/d])
652(Select1 (DIVVU (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [int64(uint64(c)/uint64(d))])
653(Select0 (DIVV  (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [c%d])   // mod
654(Select0 (DIVVU (MOVVconst [c]) (MOVVconst [d]))) -> (MOVVconst [int64(uint64(c)%uint64(d))]) // mod
655(ANDconst [c] (MOVVconst [d])) -> (MOVVconst [c&d])
656(ANDconst [c] (ANDconst [d] x)) -> (ANDconst [c&d] x)
657(ORconst [c] (MOVVconst [d])) -> (MOVVconst [c|d])
658(ORconst [c] (ORconst [d] x)) && is32Bit(c|d) -> (ORconst [c|d] x)
659(XORconst [c] (MOVVconst [d])) -> (MOVVconst [c^d])
660(XORconst [c] (XORconst [d] x)) && is32Bit(c^d) -> (XORconst [c^d] x)
661(NORconst [c] (MOVVconst [d])) -> (MOVVconst [^(c|d)])
662(NEGV (MOVVconst [c])) -> (MOVVconst [-c])
663(MOVBreg  (MOVVconst [c])) -> (MOVVconst [int64(int8(c))])
664(MOVBUreg (MOVVconst [c])) -> (MOVVconst [int64(uint8(c))])
665(MOVHreg  (MOVVconst [c])) -> (MOVVconst [int64(int16(c))])
666(MOVHUreg (MOVVconst [c])) -> (MOVVconst [int64(uint16(c))])
667(MOVWreg  (MOVVconst [c])) -> (MOVVconst [int64(int32(c))])
668(MOVWUreg (MOVVconst [c])) -> (MOVVconst [int64(uint32(c))])
669(MOVVreg  (MOVVconst [c])) -> (MOVVconst [c])
670(LoweredAtomicStore32 ptr (MOVVconst [0]) mem) -> (LoweredAtomicStorezero32 ptr mem)
671(LoweredAtomicStore64 ptr (MOVVconst [0]) mem) -> (LoweredAtomicStorezero64 ptr mem)
672(LoweredAtomicAdd32 ptr (MOVVconst [c]) mem) && is32Bit(c) -> (LoweredAtomicAddconst32 [c] ptr mem)
673(LoweredAtomicAdd64 ptr (MOVVconst [c]) mem) && is32Bit(c) -> (LoweredAtomicAddconst64 [c] ptr mem)
674
675// constant comparisons
676(SGTconst [c] (MOVVconst [d])) && c>d -> (MOVVconst [1])
677(SGTconst [c] (MOVVconst [d])) && c<=d -> (MOVVconst [0])
678(SGTUconst [c] (MOVVconst [d])) && uint64(c)>uint64(d) -> (MOVVconst [1])
679(SGTUconst [c] (MOVVconst [d])) && uint64(c)<=uint64(d) -> (MOVVconst [0])
680
681// other known comparisons
682(SGTconst [c] (MOVBreg _)) && 0x7f < c -> (MOVVconst [1])
683(SGTconst [c] (MOVBreg _)) && c <= -0x80 -> (MOVVconst [0])
684(SGTconst [c] (MOVBUreg _)) && 0xff < c -> (MOVVconst [1])
685(SGTconst [c] (MOVBUreg _)) && c < 0 -> (MOVVconst [0])
686(SGTUconst [c] (MOVBUreg _)) && 0xff < uint64(c) -> (MOVVconst [1])
687(SGTconst [c] (MOVHreg _)) && 0x7fff < c -> (MOVVconst [1])
688(SGTconst [c] (MOVHreg _)) && c <= -0x8000 -> (MOVVconst [0])
689(SGTconst [c] (MOVHUreg _)) && 0xffff < c -> (MOVVconst [1])
690(SGTconst [c] (MOVHUreg _)) && c < 0 -> (MOVVconst [0])
691(SGTUconst [c] (MOVHUreg _)) && 0xffff < uint64(c) -> (MOVVconst [1])
692(SGTconst [c] (MOVWUreg _)) && c < 0 -> (MOVVconst [0])
693(SGTconst [c] (ANDconst [m] _)) && 0 <= m && m < c -> (MOVVconst [1])
694(SGTUconst [c] (ANDconst [m] _)) && uint64(m) < uint64(c) -> (MOVVconst [1])
695(SGTconst [c] (SRLVconst _ [d])) && 0 <= c && 0 < d && d <= 63 && 0xffffffffffffffff>>uint64(d) < uint64(c) -> (MOVVconst [1])
696(SGTUconst [c] (SRLVconst _ [d])) && 0 < d && d <= 63 && 0xffffffffffffffff>>uint64(d) < uint64(c) -> (MOVVconst [1])
697
698// absorb constants into branches
699(EQ  (MOVVconst [0]) yes no) -> (First yes no)
700(EQ  (MOVVconst [c]) yes no) && c != 0 -> (First no yes)
701(NE  (MOVVconst [0]) yes no) -> (First no yes)
702(NE  (MOVVconst [c]) yes no) && c != 0 -> (First yes no)
703(LTZ (MOVVconst [c]) yes no) && c <  0 -> (First yes no)
704(LTZ (MOVVconst [c]) yes no) && c >= 0 -> (First no yes)
705(LEZ (MOVVconst [c]) yes no) && c <= 0 -> (First yes no)
706(LEZ (MOVVconst [c]) yes no) && c >  0 -> (First no yes)
707(GTZ (MOVVconst [c]) yes no) && c >  0 -> (First yes no)
708(GTZ (MOVVconst [c]) yes no) && c <= 0 -> (First no yes)
709(GEZ (MOVVconst [c]) yes no) && c >= 0 -> (First yes no)
710(GEZ (MOVVconst [c]) yes no) && c <  0 -> (First no yes)
711