]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/ssa/gen/AMD64.rules
[dev.ssa] Merge remote-tracking branch 'origin/master' into mergebranch
[gostls13.git] / src / cmd / compile / internal / ssa / gen / AMD64.rules
1 // Copyright 2015 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 // x86 register conventions:
6 //  - Integer types live in the low portion of registers.  Upper portions are junk.
7 //  - Boolean types use the low-order byte of a register.  Upper bytes are junk.
8 //  - We do not use AH,BH,CH,DH registers.
9 //  - Floating-point types will live in the low natural slot of an sse2 register.
10 //    Unused portions are junk.
11
12 // Lowering arithmetic
13 (Add64 x y) -> (ADDQ x y)
14 (AddPtr x y) -> (ADDQ x y)
15 (Add32 x y) -> (ADDL x y)
16 (Add16 x y) -> (ADDW x y)
17 (Add8 x y) -> (ADDB x y)
18 (Add32F x y) -> (ADDSS x y)
19 (Add64F x y) -> (ADDSD x y)
20
21 (Sub64 x y) -> (SUBQ x y)
22 (SubPtr x y) -> (SUBQ x y)
23 (Sub32 x y) -> (SUBL x y)
24 (Sub16 x y) -> (SUBW x y)
25 (Sub8 x y) -> (SUBB x y)
26 (Sub32F x y) -> (SUBSS x y)
27 (Sub64F x y) -> (SUBSD x y)
28
29 (Mul64 x y) -> (MULQ x y)
30 (MulPtr x y) -> (MULQ x y)
31 (Mul32 x y) -> (MULL x y)
32 (Mul16 x y) -> (MULW x y)
33 (Mul8 x y) -> (MULB x y)
34 (Mul32F x y) -> (MULSS x y)
35 (Mul64F x y) -> (MULSD x y)
36
37 (Div32F x y) -> (DIVSS x y)
38 (Div64F x y) -> (DIVSD x y)
39
40 (Div64 x y) -> (DIVQ x y)
41 (Div64u x y) -> (DIVQU x y)
42 (Div32 x y) -> (DIVL x y)
43 (Div32u x y) -> (DIVLU x y)
44 (Div16 x y) -> (DIVW x y)
45 (Div16u x y) -> (DIVWU x y)
46 (Div8 x y) ->  (DIVW (SignExt8to16 x) (SignExt8to16 y))
47 (Div8u x y) ->  (DIVWU (ZeroExt8to16 x) (ZeroExt8to16 y))
48
49 (Hmul32 x y) -> (HMULL x y)
50 (Hmul32u x y) -> (HMULLU x y)
51 (Hmul16 x y) -> (HMULW x y)
52 (Hmul16u x y) -> (HMULWU x y)
53 (Hmul8 x y) ->  (HMULB x y)
54 (Hmul8u x y) ->  (HMULBU x y)
55
56 (Mod64 x y) -> (MODQ x y)
57 (Mod64u x y) -> (MODQU x y)
58 (Mod32 x y) -> (MODL x y)
59 (Mod32u x y) -> (MODLU x y)
60 (Mod16 x y) -> (MODW x y)
61 (Mod16u x y) -> (MODWU x y)
62 (Mod8 x y) ->  (MODW (SignExt8to16 x) (SignExt8to16 y))
63 (Mod8u x y) ->  (MODWU (ZeroExt8to16 x) (ZeroExt8to16 y))
64
65 (And64 x y) -> (ANDQ x y)
66 (And32 x y) -> (ANDL x y)
67 (And16 x y) -> (ANDW x y)
68 (And8 x y) -> (ANDB x y)
69
70 (Or64 x y) -> (ORQ x y)
71 (Or32 x y) -> (ORL x y)
72 (Or16 x y) -> (ORW x y)
73 (Or8 x y) -> (ORB x y)
74
75 (Xor64 x y) -> (XORQ x y)
76 (Xor32 x y) -> (XORL x y)
77 (Xor16 x y) -> (XORW x y)
78 (Xor8 x y) -> (XORB x y)
79
80 (Neg64 x) -> (NEGQ x)
81 (Neg32 x) -> (NEGL x)
82 (Neg16 x) -> (NEGW x)
83 (Neg8 x) -> (NEGB x)
84 (Neg32F x) -> (PXOR x (MOVSSconst <config.Frontend().TypeFloat32()> [f2i(math.Copysign(0, -1))]))
85 (Neg64F x) -> (PXOR x (MOVSDconst <config.Frontend().TypeFloat64()> [f2i(math.Copysign(0, -1))]))
86
87 (Com64 x) -> (NOTQ x)
88 (Com32 x) -> (NOTL x)
89 (Com16 x) -> (NOTW x)
90 (Com8 x) -> (NOTB x)
91
92 (Sqrt x) -> (SQRTSD x)
93
94 // Note: we always extend to 64 bits even though some ops don't need that many result bits.
95 (SignExt8to16 x) -> (MOVBQSX x)
96 (SignExt8to32 x) -> (MOVBQSX x)
97 (SignExt8to64 x) -> (MOVBQSX x)
98 (SignExt16to32 x) -> (MOVWQSX x)
99 (SignExt16to64 x) -> (MOVWQSX x)
100 (SignExt32to64 x) -> (MOVLQSX x)
101
102 (ZeroExt8to16 x) -> (MOVBQZX x)
103 (ZeroExt8to32 x) -> (MOVBQZX x)
104 (ZeroExt8to64 x) -> (MOVBQZX x)
105 (ZeroExt16to32 x) -> (MOVWQZX x)
106 (ZeroExt16to64 x) -> (MOVWQZX x)
107 (ZeroExt32to64 x) -> (MOVLQZX x)
108
109 (Cvt32to32F x) -> (CVTSL2SS x)
110 (Cvt32to64F x) -> (CVTSL2SD x)
111 (Cvt64to32F x) -> (CVTSQ2SS x)
112 (Cvt64to64F x) -> (CVTSQ2SD x)
113
114 (Cvt32Fto32 x) -> (CVTTSS2SL x)
115 (Cvt32Fto64 x) -> (CVTTSS2SQ x)
116 (Cvt64Fto32 x) -> (CVTTSD2SL x)
117 (Cvt64Fto64 x) -> (CVTTSD2SQ x)
118
119 (Cvt32Fto64F x) -> (CVTSS2SD x)
120 (Cvt64Fto32F x) -> (CVTSD2SS x)
121
122 // Because we ignore high parts of registers, truncates are just copies.
123 (Trunc16to8 x) -> x
124 (Trunc32to8 x) -> x
125 (Trunc32to16 x) -> x
126 (Trunc64to8 x) -> x
127 (Trunc64to16 x) -> x
128 (Trunc64to32 x) -> x
129
130 // Lowering shifts
131 // Unsigned shifts need to return 0 if shift amount is >= width of shifted value.
132 //   result = (arg << shift) & (shift >= argbits ? 0 : 0xffffffffffffffff)
133 // Note: for small shifts we generate 32 bits of mask even when we don't need it all.
134 (Lsh64x64 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPQconst [64] y)))
135 (Lsh64x32 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPLconst [64] y)))
136 (Lsh64x16 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPWconst [64] y)))
137 (Lsh64x8 <t> x y)  -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPBconst [64] y)))
138
139 (Lsh32x64 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst [32] y)))
140 (Lsh32x32 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst [32] y)))
141 (Lsh32x16 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst [32] y)))
142 (Lsh32x8 <t> x y)  -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst [32] y)))
143
144 (Lsh16x64 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPQconst [16] y)))
145 (Lsh16x32 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPLconst [16] y)))
146 (Lsh16x16 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPWconst [16] y)))
147 (Lsh16x8 <t> x y)  -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPBconst [16] y)))
148
149 (Lsh8x64 <t> x y)  -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPQconst [8] y)))
150 (Lsh8x32 <t> x y)  -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPLconst [8] y)))
151 (Lsh8x16 <t> x y)  -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPWconst [8] y)))
152 (Lsh8x8 <t> x y)   -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPBconst [8] y)))
153
154 (Lrot64 <t> x [c]) -> (ROLQconst <t> [c&63] x)
155 (Lrot32 <t> x [c]) -> (ROLLconst <t> [c&31] x)
156 (Lrot16 <t> x [c]) -> (ROLWconst <t> [c&15] x)
157 (Lrot8 <t> x [c])  -> (ROLBconst <t> [c&7] x)
158
159 (Rsh64Ux64 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPQconst [64] y)))
160 (Rsh64Ux32 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPLconst [64] y)))
161 (Rsh64Ux16 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPWconst [64] y)))
162 (Rsh64Ux8 <t> x y)  -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPBconst [64] y)))
163
164 (Rsh32Ux64 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPQconst [32] y)))
165 (Rsh32Ux32 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPLconst [32] y)))
166 (Rsh32Ux16 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPWconst [32] y)))
167 (Rsh32Ux8 <t> x y)  -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPBconst [32] y)))
168
169 (Rsh16Ux64 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPQconst [16] y)))
170 (Rsh16Ux32 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst [16] y)))
171 (Rsh16Ux16 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPWconst [16] y)))
172 (Rsh16Ux8 <t> x y)  -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst [16] y)))
173
174 (Rsh8Ux64 <t> x y)  -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPQconst [8] y)))
175 (Rsh8Ux32 <t> x y)  -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst [8] y)))
176 (Rsh8Ux16 <t> x y)  -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst [8] y)))
177 (Rsh8Ux8 <t> x y)   -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst [8] y)))
178
179 // Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value.
180 // We implement this by setting the shift value to -1 (all ones) if the shift value is >= width.
181 // Note: for small shift widths we generate 32 bits of mask even when we don't need it all.
182 (Rsh64x64 <t> x y) -> (SARQ <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst [64] y)))))
183 (Rsh64x32 <t> x y) -> (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst [64] y)))))
184 (Rsh64x16 <t> x y) -> (SARQ <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst [64] y)))))
185 (Rsh64x8 <t> x y)  -> (SARQ <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst [64] y)))))
186
187 (Rsh32x64 <t> x y) -> (SARL <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst [32] y)))))
188 (Rsh32x32 <t> x y) -> (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst [32] y)))))
189 (Rsh32x16 <t> x y) -> (SARL <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst [32] y)))))
190 (Rsh32x8 <t> x y)  -> (SARL <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst [32] y)))))
191
192 (Rsh16x64 <t> x y) -> (SARW <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst [16] y)))))
193 (Rsh16x32 <t> x y) -> (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst [16] y)))))
194 (Rsh16x16 <t> x y) -> (SARW <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst [16] y)))))
195 (Rsh16x8 <t> x y)  -> (SARW <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst [16] y)))))
196
197 (Rsh8x64 <t> x y)  -> (SARB <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst [8] y)))))
198 (Rsh8x32 <t> x y)  -> (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst [8] y)))))
199 (Rsh8x16 <t> x y)  -> (SARB <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst [8] y)))))
200 (Rsh8x8 <t> x y)   -> (SARB <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst [8] y)))))
201
202 (Less64 x y) -> (SETL (CMPQ x y))
203 (Less32 x y) -> (SETL (CMPL x y))
204 (Less16 x y) -> (SETL (CMPW x y))
205 (Less8  x y) -> (SETL (CMPB x y))
206 (Less64U x y) -> (SETB (CMPQ x y))
207 (Less32U x y) -> (SETB (CMPL x y))
208 (Less16U x y) -> (SETB (CMPW x y))
209 (Less8U  x y) -> (SETB (CMPB x y))
210 // Use SETGF with reversed operands to dodge NaN case
211 (Less64F x y) -> (SETGF (UCOMISD y x))
212 (Less32F x y) -> (SETGF (UCOMISS y x))
213
214 (Leq64 x y) -> (SETLE (CMPQ x y))
215 (Leq32 x y) -> (SETLE (CMPL x y))
216 (Leq16 x y) -> (SETLE (CMPW x y))
217 (Leq8  x y) -> (SETLE (CMPB x y))
218 (Leq64U x y) -> (SETBE (CMPQ x y))
219 (Leq32U x y) -> (SETBE (CMPL x y))
220 (Leq16U x y) -> (SETBE (CMPW x y))
221 (Leq8U  x y) -> (SETBE (CMPB x y))
222 // Use SETGEF with reversed operands to dodge NaN case
223 (Leq64F x y) -> (SETGEF (UCOMISD y x))
224 (Leq32F x y) -> (SETGEF (UCOMISS y x))
225
226 (Greater64 x y) -> (SETG (CMPQ x y))
227 (Greater32 x y) -> (SETG (CMPL x y))
228 (Greater16 x y) -> (SETG (CMPW x y))
229 (Greater8  x y) -> (SETG (CMPB x y))
230 (Greater64U x y) -> (SETA (CMPQ x y))
231 (Greater32U x y) -> (SETA (CMPL x y))
232 (Greater16U x y) -> (SETA (CMPW x y))
233 (Greater8U  x y) -> (SETA (CMPB x y))
234 // Note Go assembler gets UCOMISx operand order wrong, but it is right here
235 // Bug is accommodated at generation of assembly language.
236 (Greater64F x y) -> (SETGF (UCOMISD x y))
237 (Greater32F x y) -> (SETGF (UCOMISS x y))
238
239 (Geq64 x y) -> (SETGE (CMPQ x y))
240 (Geq32 x y) -> (SETGE (CMPL x y))
241 (Geq16 x y) -> (SETGE (CMPW x y))
242 (Geq8  x y) -> (SETGE (CMPB x y))
243 (Geq64U x y) -> (SETAE (CMPQ x y))
244 (Geq32U x y) -> (SETAE (CMPL x y))
245 (Geq16U x y) -> (SETAE (CMPW x y))
246 (Geq8U  x y) -> (SETAE (CMPB x y))
247 // Note Go assembler gets UCOMISx operand order wrong, but it is right here
248 // Bug is accommodated at generation of assembly language.
249 (Geq64F x y) -> (SETGEF (UCOMISD x y))
250 (Geq32F x y) -> (SETGEF (UCOMISS x y))
251
252 (Eq64 x y) -> (SETEQ (CMPQ x y))
253 (Eq32 x y) -> (SETEQ (CMPL x y))
254 (Eq16 x y) -> (SETEQ (CMPW x y))
255 (Eq8 x y) -> (SETEQ (CMPB x y))
256 (EqPtr x y) -> (SETEQ (CMPQ x y))
257 (Eq64F x y) -> (SETEQF (UCOMISD x y))
258 (Eq32F x y) -> (SETEQF (UCOMISS x y))
259
260 (Neq64 x y) -> (SETNE (CMPQ x y))
261 (Neq32 x y) -> (SETNE (CMPL x y))
262 (Neq16 x y) -> (SETNE (CMPW x y))
263 (Neq8 x y) -> (SETNE (CMPB x y))
264 (NeqPtr x y) -> (SETNE (CMPQ x y))
265 (Neq64F x y) -> (SETNEF (UCOMISD x y))
266 (Neq32F x y) -> (SETNEF (UCOMISS x y))
267
268 (Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVQload ptr mem)
269 (Load <t> ptr mem) && is32BitInt(t) -> (MOVLload ptr mem)
270 (Load <t> ptr mem) && is16BitInt(t) -> (MOVWload ptr mem)
271 (Load <t> ptr mem) && (t.IsBoolean() || is8BitInt(t)) -> (MOVBload ptr mem)
272 (Load <t> ptr mem) && is32BitFloat(t) -> (MOVSSload ptr mem)
273 (Load <t> ptr mem) && is64BitFloat(t) -> (MOVSDload ptr mem)
274
275 // These more-specific FP versions of Store pattern should come first.
276 (Store [8] ptr val mem) && is64BitFloat(val.Type) -> (MOVSDstore ptr val mem)
277 (Store [4] ptr val mem) && is32BitFloat(val.Type) -> (MOVSSstore ptr val mem)
278
279 (Store [8] ptr val mem) -> (MOVQstore ptr val mem)
280 (Store [4] ptr val mem) -> (MOVLstore ptr val mem)
281 (Store [2] ptr val mem) -> (MOVWstore ptr val mem)
282 (Store [1] ptr val mem) -> (MOVBstore ptr val mem)
283
284 // checks
285 (IsNonNil p) -> (SETNE (TESTQ p p))
286 (IsInBounds idx len) -> (SETB (CMPQ idx len))
287 (IsSliceInBounds idx len) -> (SETBE (CMPQ idx len))
288
289 (PanicNilCheck ptr mem) -> (LoweredPanicNilCheck ptr mem)
290 (GetG) -> (LoweredGetG)
291 (GetClosurePtr) -> (LoweredGetClosurePtr)
292
293 (Move [size] dst src mem) -> (REPMOVSB dst src (MOVQconst <config.Frontend().TypeUInt64()> [size]) mem)
294
295 (Not x) -> (XORBconst [1] x)
296
297 (OffPtr [off] ptr) -> (ADDQconst [off] ptr)
298
299 (Const8 [val]) -> (MOVBconst [val])
300 (Const16 [val]) -> (MOVWconst [val])
301 (Const32 [val]) -> (MOVLconst [val])
302 (Const64 [val]) -> (MOVQconst [val])
303 (Const32F [val]) -> (MOVSSconst [val])
304 (Const64F [val]) -> (MOVSDconst [val])
305 (ConstPtr [val]) -> (MOVQconst [val])
306 (ConstNil) -> (MOVQconst [0])
307 (ConstBool [b]) -> (MOVBconst [b])
308
309 (Addr {sym} base) -> (LEAQ {sym} base)
310
311 (ITab (Load ptr mem)) -> (MOVQload ptr mem)
312
313 // block rewrites
314 (If (SETL  cmp) yes no) -> (LT  cmp yes no)
315 (If (SETLE cmp) yes no) -> (LE  cmp yes no)
316 (If (SETG  cmp) yes no) -> (GT  cmp yes no)
317 (If (SETGE cmp) yes no) -> (GE  cmp yes no)
318 (If (SETEQ cmp) yes no) -> (EQ  cmp yes no)
319 (If (SETNE cmp) yes no) -> (NE  cmp yes no)
320 (If (SETB  cmp) yes no) -> (ULT cmp yes no)
321 (If (SETBE cmp) yes no) -> (ULE cmp yes no)
322 (If (SETA  cmp) yes no) -> (UGT cmp yes no)
323 (If (SETAE cmp) yes no) -> (UGE cmp yes no)
324
325 // Special case for floating point - LF/LEF not generated
326 (If (SETGF  cmp) yes no) -> (UGT  cmp yes no)
327 (If (SETGEF cmp) yes no) -> (UGE  cmp yes no)
328 (If (SETEQF cmp) yes no) -> (EQF  cmp yes no)
329 (If (SETNEF cmp) yes no) -> (EQF  cmp yes no)
330
331 (If cond yes no) -> (NE (TESTB cond cond) yes no)
332
333 (NE (TESTB (SETL  cmp)) yes no) -> (LT  cmp yes no)
334 (NE (TESTB (SETLE cmp)) yes no) -> (LE  cmp yes no)
335 (NE (TESTB (SETG  cmp)) yes no) -> (GT  cmp yes no)
336 (NE (TESTB (SETGE cmp)) yes no) -> (GE  cmp yes no)
337 (NE (TESTB (SETEQ cmp)) yes no) -> (EQ  cmp yes no)
338 (NE (TESTB (SETNE cmp)) yes no) -> (NE  cmp yes no)
339 (NE (TESTB (SETB  cmp)) yes no) -> (ULT cmp yes no)
340 (NE (TESTB (SETBE cmp)) yes no) -> (ULE cmp yes no)
341 (NE (TESTB (SETA  cmp)) yes no) -> (UGT cmp yes no)
342 (NE (TESTB (SETAE cmp)) yes no) -> (UGE cmp yes no)
343
344 // Special case for floating point - LF/LEF not generated
345 (NE (TESTB (SETGF  cmp)) yes no) -> (UGT  cmp yes no)
346 (NE (TESTB (SETGEF cmp)) yes no) -> (UGE  cmp yes no)
347 (NE (TESTB (SETEQF cmp)) yes no) -> (EQF  cmp yes no)
348 (NE (TESTB (SETNEF cmp)) yes no) -> (NEF  cmp yes no)
349
350 // Disabled because it interferes with the pattern match above and makes worse code.
351 // (SETNEF x) -> (ORQ (SETNE <config.Frontend().TypeInt8()> x) (SETNAN <config.Frontend().TypeInt8()> x))
352 // (SETEQF x) -> (ANDQ (SETEQ <config.Frontend().TypeInt8()> x) (SETORD <config.Frontend().TypeInt8()> x))
353
354 (StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem)
355 (ClosureCall [argwid] entry closure mem) -> (CALLclosure [argwid] entry closure mem)
356 (DeferCall [argwid] mem) -> (CALLdefer [argwid] mem)
357 (GoCall [argwid] mem) -> (CALLgo [argwid] mem)
358 (InterCall [argwid] entry mem) -> (CALLinter [argwid] entry mem)
359
360 // Rules below here apply some simple optimizations after lowering.
361 // TODO: Should this be a separate pass?
362
363 // fold constants into instructions
364 (ADDQ x (MOVQconst [c])) && is32Bit(c) -> (ADDQconst [c] x)
365 (ADDQ (MOVQconst [c]) x) && is32Bit(c) -> (ADDQconst [c] x)
366 (ADDL x (MOVLconst [c])) -> (ADDLconst [c] x)
367 (ADDL (MOVLconst [c]) x) -> (ADDLconst [c] x)
368 (ADDW x (MOVWconst [c])) -> (ADDWconst [c] x)
369 (ADDW (MOVWconst [c]) x) -> (ADDWconst [c] x)
370 (ADDB x (MOVBconst [c])) -> (ADDBconst [c] x)
371 (ADDB (MOVBconst [c]) x) -> (ADDBconst [c] x)
372
373 (SUBQ x (MOVQconst [c])) && is32Bit(c) -> (SUBQconst x [c])
374 (SUBQ (MOVQconst [c]) x) && is32Bit(c) -> (NEGQ (SUBQconst <v.Type> x [c]))
375 (SUBL x (MOVLconst [c])) -> (SUBLconst x [c])
376 (SUBL (MOVLconst [c]) x) -> (NEGL (SUBLconst <v.Type> x [c]))
377 (SUBW x (MOVWconst [c])) -> (SUBWconst x [c])
378 (SUBW (MOVWconst [c]) x) -> (NEGW (SUBWconst <v.Type> x [c]))
379 (SUBB x (MOVBconst [c])) -> (SUBBconst x [c])
380 (SUBB (MOVBconst [c]) x) -> (NEGB (SUBBconst <v.Type> x [c]))
381
382 (MULQ x (MOVQconst [c])) && is32Bit(c) -> (MULQconst [c] x)
383 (MULQ (MOVQconst [c]) x) && is32Bit(c) -> (MULQconst [c] x)
384 (MULL x (MOVLconst [c])) -> (MULLconst [c] x)
385 (MULL (MOVLconst [c]) x) -> (MULLconst [c] x)
386 (MULW x (MOVWconst [c])) -> (MULWconst [c] x)
387 (MULW (MOVWconst [c]) x) -> (MULWconst [c] x)
388 (MULB x (MOVBconst [c])) -> (MULBconst [c] x)
389 (MULB (MOVBconst [c]) x) -> (MULBconst [c] x)
390
391 (ANDQ x (MOVQconst [c])) && is32Bit(c) -> (ANDQconst [c] x)
392 (ANDQ (MOVQconst [c]) x) && is32Bit(c) -> (ANDQconst [c] x)
393 (ANDL x (MOVLconst [c])) -> (ANDLconst [c] x)
394 (ANDL (MOVLconst [c]) x) -> (ANDLconst [c] x)
395 (ANDW x (MOVLconst [c])) -> (ANDWconst [c] x)
396 (ANDW (MOVLconst [c]) x) -> (ANDWconst [c] x)
397 (ANDW x (MOVWconst [c])) -> (ANDWconst [c] x)
398 (ANDW (MOVWconst [c]) x) -> (ANDWconst [c] x)
399 (ANDB x (MOVLconst [c])) -> (ANDBconst [c] x)
400 (ANDB (MOVLconst [c]) x) -> (ANDBconst [c] x)
401 (ANDB x (MOVBconst [c])) -> (ANDBconst [c] x)
402 (ANDB (MOVBconst [c]) x) -> (ANDBconst [c] x)
403
404 (ORQ x (MOVQconst [c])) && is32Bit(c) -> (ORQconst [c] x)
405 (ORQ (MOVQconst [c]) x) && is32Bit(c) -> (ORQconst [c] x)
406 (ORL x (MOVLconst [c])) -> (ORLconst [c] x)
407 (ORL (MOVLconst [c]) x) -> (ORLconst [c] x)
408 (ORW x (MOVWconst [c])) -> (ORWconst [c] x)
409 (ORW (MOVWconst [c]) x) -> (ORWconst [c] x)
410 (ORB x (MOVBconst [c])) -> (ORBconst [c] x)
411 (ORB (MOVBconst [c]) x) -> (ORBconst [c] x)
412
413 (XORQ x (MOVQconst [c])) && is32Bit(c) -> (XORQconst [c] x)
414 (XORQ (MOVQconst [c]) x) && is32Bit(c) -> (XORQconst [c] x)
415 (XORL x (MOVLconst [c])) -> (XORLconst [c] x)
416 (XORL (MOVLconst [c]) x) -> (XORLconst [c] x)
417 (XORW x (MOVWconst [c])) -> (XORWconst [c] x)
418 (XORW (MOVWconst [c]) x) -> (XORWconst [c] x)
419 (XORB x (MOVBconst [c])) -> (XORBconst [c] x)
420 (XORB (MOVBconst [c]) x) -> (XORBconst [c] x)
421
422 (SHLQ x (MOVQconst [c])) -> (SHLQconst [c&63] x)
423 (SHLL x (MOVLconst [c])) -> (SHLLconst [c&31] x)
424 (SHLW x (MOVWconst [c])) -> (SHLWconst [c&31] x)
425 (SHLB x (MOVBconst [c])) -> (SHLBconst [c&31] x)
426
427 (SHRQ x (MOVQconst [c])) -> (SHRQconst [c&63] x)
428 (SHRL x (MOVLconst [c])) -> (SHRLconst [c&31] x)
429 (SHRW x (MOVWconst [c])) -> (SHRWconst [c&31] x)
430 (SHRB x (MOVBconst [c])) -> (SHRBconst [c&31] x)
431
432 (SARQ x (MOVQconst [c])) -> (SARQconst [c&63] x)
433 (SARL x (MOVLconst [c])) -> (SARLconst [c&31] x)
434 (SARW x (MOVWconst [c])) -> (SARWconst [c&31] x)
435 (SARB x (MOVBconst [c])) -> (SARBconst [c&31] x)
436
437 // Note: the word and byte shifts keep the low 5 bits (not the low 4 or 3 bits)
438 // because the x86 instructions are defined to use all 5 bits of the shift even
439 // for the small shifts.  I don't think we'll ever generate a weird shift (e.g.
440 // (SHLW x (MOVWconst [24])), but just in case.
441
442 (CMPQ x (MOVQconst [c])) && is32Bit(c) -> (CMPQconst x [c])
443 (CMPQ (MOVQconst [c]) x) && is32Bit(c) -> (InvertFlags (CMPQconst x [c]))
444 (CMPL x (MOVLconst [c])) -> (CMPLconst x [c])
445 (CMPL (MOVLconst [c]) x) -> (InvertFlags (CMPLconst x [c]))
446 (CMPW x (MOVWconst [c])) -> (CMPWconst x [c])
447 (CMPW (MOVWconst [c]) x) -> (InvertFlags (CMPWconst x [c]))
448 (CMPB x (MOVBconst [c])) -> (CMPBconst x [c])
449 (CMPB (MOVBconst [c]) x) -> (InvertFlags (CMPBconst x [c]))
450
451 // strength reduction
452 (MULQconst [-1] x) -> (NEGQ x)
453 (MULQconst [0] _) -> (MOVQconst [0])
454 (MULQconst [1] x) -> x
455 (MULQconst [3] x) -> (LEAQ2 x x)
456 (MULQconst [5] x) -> (LEAQ4 x x)
457 (MULQconst [9] x) -> (LEAQ8 x x)
458 (MULQconst [c] x) && isPowerOfTwo(c) -> (SHLQconst [log2(c)] x)
459
460 // fold add/shift into leaq
461 (ADDQ x (SHLQconst [3] y)) -> (LEAQ8 x y)
462 (ADDQconst [c] (LEAQ8 [d] x y)) -> (LEAQ8 [addOff(c, d)] x y)
463
464 // reverse ordering of compare instruction
465 (SETL (InvertFlags x)) -> (SETG x)
466 (SETG (InvertFlags x)) -> (SETL x)
467 (SETB (InvertFlags x)) -> (SETA x)
468 (SETA (InvertFlags x)) -> (SETB x)
469 (SETLE (InvertFlags x)) -> (SETGE x)
470 (SETGE (InvertFlags x)) -> (SETLE x)
471 (SETBE (InvertFlags x)) -> (SETAE x)
472 (SETAE (InvertFlags x)) -> (SETBE x)
473 (SETEQ (InvertFlags x)) -> (SETEQ x)
474 (SETNE (InvertFlags x)) -> (SETNE x)
475
476 // sign extended loads
477 // Note: The combined instruction must end up in the same block
478 // as the original load.  If not, we end up making a value with
479 // memory type live in two different blocks, which can lead to
480 // multiple memory values alive simultaneously.
481 (MOVBQSX (MOVBload [off] {sym} ptr mem)) -> @v.Args[0].Block (MOVBQSXload <v.Type> [off] {sym} ptr mem)
482 (MOVBQZX (MOVBload [off] {sym} ptr mem)) -> @v.Args[0].Block (MOVBQZXload <v.Type> [off] {sym} ptr mem)
483 // TODO: more
484
485 // Don't extend before storing
486 (MOVLstore [off] {sym} ptr (MOVLQSX x) mem) -> (MOVLstore [off] {sym} ptr x mem)
487 (MOVWstore [off] {sym} ptr (MOVWQSX x) mem) -> (MOVWstore [off] {sym} ptr x mem)
488 (MOVBstore [off] {sym} ptr (MOVBQSX x) mem) -> (MOVBstore [off] {sym} ptr x mem)
489 (MOVLstore [off] {sym} ptr (MOVLQZX x) mem) -> (MOVLstore [off] {sym} ptr x mem)
490 (MOVWstore [off] {sym} ptr (MOVWQZX x) mem) -> (MOVWstore [off] {sym} ptr x mem)
491 (MOVBstore [off] {sym} ptr (MOVBQZX x) mem) -> (MOVBstore [off] {sym} ptr x mem)
492
493 // fold constants into memory operations
494 // Note that this is not always a good idea because if not all the uses of
495 // the ADDQconst get eliminated, we still have to compute the ADDQconst and we now
496 // have potentially two live values (ptr and (ADDQconst [off] ptr)) instead of one.
497 // Nevertheless, let's do it!
498 (MOVQload  [off1] {sym} (ADDQconst [off2] ptr) mem) -> (MOVQload  [addOff(off1, off2)] {sym} ptr mem)
499 (MOVLload  [off1] {sym} (ADDQconst [off2] ptr) mem) -> (MOVLload  [addOff(off1, off2)] {sym} ptr mem)
500 (MOVWload  [off1] {sym} (ADDQconst [off2] ptr) mem) -> (MOVWload  [addOff(off1, off2)] {sym} ptr mem)
501 (MOVBload  [off1] {sym} (ADDQconst [off2] ptr) mem) -> (MOVBload  [addOff(off1, off2)] {sym} ptr mem)
502 (MOVSSload [off1] {sym} (ADDQconst [off2] ptr) mem) -> (MOVSSload [addOff(off1, off2)] {sym} ptr mem)
503 (MOVSDload [off1] {sym} (ADDQconst [off2] ptr) mem) -> (MOVSDload [addOff(off1, off2)] {sym} ptr mem)
504
505 (MOVQstore  [off1] {sym} (ADDQconst [off2] ptr) val mem) -> (MOVQstore  [addOff(off1, off2)] {sym} ptr val mem)
506 (MOVLstore  [off1] {sym} (ADDQconst [off2] ptr) val mem) -> (MOVLstore  [addOff(off1, off2)] {sym} ptr val mem)
507 (MOVWstore  [off1] {sym} (ADDQconst [off2] ptr) val mem) -> (MOVWstore  [addOff(off1, off2)] {sym} ptr val mem)
508 (MOVBstore  [off1] {sym} (ADDQconst [off2] ptr) val mem) -> (MOVBstore  [addOff(off1, off2)] {sym} ptr val mem)
509 (MOVSSstore [off1] {sym} (ADDQconst [off2] ptr) val mem) -> (MOVSSstore [addOff(off1, off2)] {sym} ptr val mem)
510 (MOVSDstore [off1] {sym} (ADDQconst [off2] ptr) val mem) -> (MOVSDstore [addOff(off1, off2)] {sym} ptr val mem)
511
512 // We need to fold LEAQ into the MOVx ops so that the live variable analysis knows
513 // what variables are being read/written by the ops.
514 (MOVQload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) ->
515         (MOVQload  [addOff(off1,off2)] {mergeSym(sym1,sym2)} base mem)
516 (MOVLload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) ->
517         (MOVLload  [addOff(off1,off2)] {mergeSym(sym1,sym2)} base mem)
518 (MOVWload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) ->
519         (MOVWload  [addOff(off1,off2)] {mergeSym(sym1,sym2)} base mem)
520 (MOVBload  [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) ->
521         (MOVBload  [addOff(off1,off2)] {mergeSym(sym1,sym2)} base mem)
522 (MOVSSload [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) ->
523         (MOVSSload [addOff(off1,off2)] {mergeSym(sym1,sym2)} base mem)
524 (MOVSDload [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) ->
525         (MOVSDload [addOff(off1,off2)] {mergeSym(sym1,sym2)} base mem)
526
527 (MOVQstore  [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) ->
528         (MOVQstore  [addOff(off1,off2)] {mergeSym(sym1,sym2)} base val mem)
529 (MOVLstore  [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) ->
530         (MOVLstore  [addOff(off1,off2)] {mergeSym(sym1,sym2)} base val mem)
531 (MOVWstore  [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) ->
532         (MOVWstore  [addOff(off1,off2)] {mergeSym(sym1,sym2)} base val mem)
533 (MOVBstore  [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) ->
534         (MOVBstore  [addOff(off1,off2)] {mergeSym(sym1,sym2)} base val mem)
535 (MOVSSstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) ->
536         (MOVSSstore [addOff(off1,off2)] {mergeSym(sym1,sym2)} base val mem)
537 (MOVSDstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) ->
538         (MOVSDstore [addOff(off1,off2)] {mergeSym(sym1,sym2)} base val mem)
539
540 // indexed loads and stores
541 (MOVQloadidx8 [off1] {sym} (ADDQconst [off2] ptr) idx mem) -> (MOVQloadidx8 [addOff(off1, off2)] {sym} ptr idx mem)
542 (MOVQstoreidx8 [off1] {sym} (ADDQconst [off2] ptr) idx val mem) -> (MOVQstoreidx8 [addOff(off1, off2)] {sym} ptr idx val mem)
543 (MOVSSloadidx4 [off1] {sym} (ADDQconst [off2] {sym} ptr) idx mem) -> (MOVSSloadidx4 [addOff(off1, off2)] {sym} ptr idx mem)
544 (MOVSSstoreidx4 [off1] {sym} (ADDQconst [off2] {sym} ptr) idx val mem) -> (MOVSSstoreidx4 [addOff(off1, off2)] {sym} ptr idx val mem)
545 (MOVSDloadidx8 [off1] {sym} (ADDQconst [off2] {sym} ptr) idx mem) -> (MOVSDloadidx8 [addOff(off1, off2)] {sym} ptr idx mem)
546 (MOVSDstoreidx8 [off1] {sym} (ADDQconst [off2] {sym} ptr) idx val mem) -> (MOVSDstoreidx8 [addOff(off1, off2)] {sym} ptr idx val mem)
547
548 (MOVQload [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
549         (MOVQloadidx8 [addOff(off1, off2)] {mergeSym(sym1,sym2)} ptr idx mem)
550 (MOVQstore [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) val mem) && canMergeSym(sym1, sym2) ->
551         (MOVQstoreidx8 [addOff(off1, off2)] {mergeSym(sym1,sym2)} ptr idx val mem)
552
553 (MOVSSload [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
554         (MOVSSloadidx4 [addOff(off1, off2)] {mergeSym(sym1,sym2)} ptr idx mem)
555 (MOVSSstore [off1] {sym1} (LEAQ4 [off2] {sym2} ptr idx) val mem) && canMergeSym(sym1, sym2) ->
556         (MOVSSstoreidx4 [addOff(off1, off2)] {mergeSym(sym1,sym2)} ptr idx val mem)
557
558 (MOVSDload [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) mem) && canMergeSym(sym1, sym2) ->
559         (MOVSDloadidx8 [addOff(off1, off2)] {mergeSym(sym1,sym2)} ptr idx mem)
560 (MOVSDstore [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) val mem) && canMergeSym(sym1, sym2) ->
561         (MOVSDstoreidx8 [addOff(off1, off2)] {mergeSym(sym1,sym2)} ptr idx val mem)
562
563 (ADDQconst [0] x) -> x
564
565 // lower Zero instructions with word sizes
566 (Zero [0] _ mem) -> mem
567 (Zero [1] destptr mem) -> (MOVBstore destptr (MOVBconst [0]) mem)
568 (Zero [2] destptr mem) -> (MOVWstore destptr (MOVWconst [0]) mem)
569 (Zero [4] destptr mem) -> (MOVLstore destptr (MOVLconst [0]) mem)
570 (Zero [8] destptr mem) -> (MOVQstore destptr (MOVQconst [0]) mem)
571
572 (Zero [3] destptr mem) ->
573         (MOVBstore (ADDQconst [2] destptr) (MOVBconst [0])
574                 (MOVWstore destptr (MOVWconst [0]) mem))
575 (Zero [5] destptr mem) ->
576         (MOVBstore (ADDQconst [4] destptr) (MOVBconst [0])
577                 (MOVLstore destptr (MOVLconst [0]) mem))
578 (Zero [6] destptr mem) ->
579         (MOVWstore (ADDQconst [4] destptr) (MOVWconst [0])
580                 (MOVLstore destptr (MOVLconst [0]) mem))
581 (Zero [7] destptr mem) ->
582         (MOVLstore (ADDQconst [3] destptr) (MOVLconst [0])
583                 (MOVLstore destptr (MOVLconst [0]) mem))
584
585 // Strip off any fractional word zeroing.
586 (Zero [size] destptr mem) && size%8 != 0 && size > 8 ->
587         (Zero [size-size%8] (ADDQconst destptr [size%8])
588                 (MOVQstore destptr (MOVQconst [0]) mem))
589
590 // Zero small numbers of words directly.
591 (Zero [16] destptr mem) ->
592         (MOVQstore (ADDQconst [8] destptr) (MOVQconst [0])
593                 (MOVQstore destptr (MOVQconst [0]) mem))
594 (Zero [24] destptr mem) ->
595         (MOVQstore (ADDQconst [16] destptr) (MOVQconst [0])
596                 (MOVQstore (ADDQconst [8] destptr) (MOVQconst [0])
597                         (MOVQstore destptr (MOVQconst [0]) mem)))
598 (Zero [32] destptr mem) ->
599         (MOVQstore (ADDQconst [24] destptr) (MOVQconst [0])
600                 (MOVQstore (ADDQconst [16] destptr) (MOVQconst [0])
601                         (MOVQstore (ADDQconst [8] destptr) (MOVQconst [0])
602                                 (MOVQstore destptr (MOVQconst [0]) mem))))
603
604 // Medium zeroing uses a duff device.
605 (Zero [size] destptr mem) && size <= 1024 && size%8 == 0 && size%16 != 0 ->
606         (Zero [size-8] (ADDQconst [8] destptr) (MOVQstore destptr (MOVQconst [0]) mem))
607 (Zero [size] destptr mem) && size <= 1024 && size%16 == 0 ->
608         (DUFFZERO [duffStart(size)] (ADDQconst [duffAdj(size)] destptr) (MOVOconst [0]) mem)
609
610 // Large zeroing uses REP STOSQ.
611 (Zero [size] destptr mem) && size > 1024 && size%8 == 0 ->
612         (REPSTOSQ destptr (MOVQconst [size/8]) (MOVQconst [0]) mem)
613
614 // Absorb InvertFlags into branches.
615 (LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
616 (GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
617 (LE (InvertFlags cmp) yes no) -> (GE cmp yes no)
618 (GE (InvertFlags cmp) yes no) -> (LE cmp yes no)
619 (ULT (InvertFlags cmp) yes no) -> (UGT cmp yes no)
620 (UGT (InvertFlags cmp) yes no) -> (ULT cmp yes no)
621 (ULE (InvertFlags cmp) yes no) -> (UGE cmp yes no)
622 (UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no)
623 (EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
624 (NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
625
626 // get rid of overflow code for constant shifts
627 (SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) &&  inBounds64(d, c) -> (MOVQconst [-1])
628 (SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds64(d, c) -> (MOVQconst [0])
629 (SBBQcarrymask (CMPLconst [c] (MOVLconst [d]))) &&  inBounds32(d, c) -> (MOVQconst [-1])
630 (SBBQcarrymask (CMPLconst [c] (MOVLconst [d]))) && !inBounds32(d, c) -> (MOVQconst [0])
631 (SBBQcarrymask (CMPWconst [c] (MOVWconst [d]))) &&  inBounds16(d, c) -> (MOVQconst [-1])
632 (SBBQcarrymask (CMPWconst [c] (MOVWconst [d]))) && !inBounds16(d, c) -> (MOVQconst [0])
633 (SBBQcarrymask (CMPBconst [c] (MOVBconst [d]))) &&  inBounds8(d, c)  -> (MOVQconst [-1])
634 (SBBQcarrymask (CMPBconst [c] (MOVBconst [d]))) && !inBounds8(d, c)  -> (MOVQconst [0])
635 (SBBLcarrymask (CMPQconst [c] (MOVQconst [d]))) &&  inBounds64(d, c) -> (MOVLconst [-1])
636 (SBBLcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds64(d, c) -> (MOVLconst [0])
637 (SBBLcarrymask (CMPLconst [c] (MOVLconst [d]))) &&  inBounds32(d, c) -> (MOVLconst [-1])
638 (SBBLcarrymask (CMPLconst [c] (MOVLconst [d]))) && !inBounds32(d, c) -> (MOVLconst [0])
639 (SBBLcarrymask (CMPWconst [c] (MOVWconst [d]))) &&  inBounds16(d, c) -> (MOVLconst [-1])
640 (SBBLcarrymask (CMPWconst [c] (MOVWconst [d]))) && !inBounds16(d, c) -> (MOVLconst [0])
641 (SBBLcarrymask (CMPBconst [c] (MOVBconst [d]))) &&  inBounds8(d, c)  -> (MOVLconst [-1])
642 (SBBLcarrymask (CMPBconst [c] (MOVBconst [d]))) && !inBounds8(d, c)  -> (MOVLconst [0])
643 (ANDQconst [0] _)                 -> (MOVQconst [0])
644 (ANDLconst [c] _) && int32(c)==0  -> (MOVLconst [0])
645 (ANDWconst [c] _) && int16(c)==0  -> (MOVWconst [0])
646 (ANDBconst [c] _) && int8(c)==0   -> (MOVBconst [0])
647 (ANDQconst [-1] x)                -> x
648 (ANDLconst [c] x) && int32(c)==-1 -> x
649 (ANDWconst [c] x) && int16(c)==-1 -> x
650 (ANDBconst [c] x) && int8(c)==-1  -> x
651 (ORQconst [0] x)                  -> x
652 (ORLconst [c] x) && int32(c)==0   -> x
653 (ORWconst [c] x) && int16(c)==0   -> x
654 (ORBconst [c] x) && int8(c)==0    -> x
655 (ORQconst [-1] _)                 -> (MOVQconst [-1])
656 (ORLconst [c] _) && int32(c)==-1  -> (MOVLconst [-1])
657 (ORWconst [c] _) && int16(c)==-1  -> (MOVWconst [-1])
658 (ORBconst [c] _) && int8(c)==-1   -> (MOVBconst [-1])
659
660 // generic constant folding
661 // TODO: more of this
662 (ADDQconst [c] (MOVQconst [d])) -> (MOVQconst [c+d])
663 (ADDLconst [c] (MOVLconst [d])) -> (MOVLconst [c+d])
664 (ADDWconst [c] (MOVWconst [d])) -> (MOVWconst [c+d])
665 (ADDBconst [c] (MOVBconst [d])) -> (MOVBconst [c+d])
666 (ADDQconst [c] (ADDQconst [d] x)) -> (ADDQconst [c+d] x)
667 (ADDLconst [c] (ADDLconst [d] x)) -> (ADDLconst [c+d] x)
668 (ADDWconst [c] (ADDWconst [d] x)) -> (ADDWconst [c+d] x)
669 (ADDBconst [c] (ADDBconst [d] x)) -> (ADDBconst [c+d] x)
670 (SUBQconst [c] (MOVQconst [d])) -> (MOVQconst [d-c])
671 (SUBLconst [c] (MOVLconst [d])) -> (MOVLconst [d-c])
672 (SUBWconst [c] (MOVWconst [d])) -> (MOVWconst [d-c])
673 (SUBBconst [c] (MOVBconst [d])) -> (MOVBconst [d-c])
674 (SUBQconst [c] (SUBQconst [d] x)) -> (ADDQconst [-c-d] x)
675 (SUBLconst [c] (SUBLconst [d] x)) -> (ADDLconst [-c-d] x)
676 (SUBWconst [c] (SUBWconst [d] x)) -> (ADDWconst [-c-d] x)
677 (SUBBconst [c] (SUBBconst [d] x)) -> (ADDBconst [-c-d] x)
678 (SARQconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
679 (SARLconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
680 (SARWconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
681 (SARBconst [c] (MOVQconst [d])) -> (MOVQconst [d>>uint64(c)])
682 (NEGQ (MOVQconst [c])) -> (MOVQconst [-c])
683 (NEGL (MOVLconst [c])) -> (MOVLconst [-c])
684 (NEGW (MOVWconst [c])) -> (MOVWconst [-c])
685 (NEGB (MOVBconst [c])) -> (MOVBconst [-c])
686 (MULQconst [c] (MOVQconst [d])) -> (MOVQconst [c*d])
687 (MULLconst [c] (MOVLconst [d])) -> (MOVLconst [c*d])
688 (MULWconst [c] (MOVWconst [d])) -> (MOVWconst [c*d])
689 (MULBconst [c] (MOVBconst [d])) -> (MOVBconst [c*d])
690 (ANDQconst [c] (MOVQconst [d])) -> (MOVQconst [c&d])
691 (ANDLconst [c] (MOVLconst [d])) -> (MOVLconst [c&d])
692 (ANDWconst [c] (MOVWconst [d])) -> (MOVWconst [c&d])
693 (ANDBconst [c] (MOVBconst [d])) -> (MOVBconst [c&d])
694 (ORQconst [c] (MOVQconst [d])) -> (MOVQconst [c|d])
695 (ORLconst [c] (MOVLconst [d])) -> (MOVLconst [c|d])
696 (ORWconst [c] (MOVWconst [d])) -> (MOVWconst [c|d])
697 (ORBconst [c] (MOVBconst [d])) -> (MOVBconst [c|d])
698 (XORQconst [c] (MOVQconst [d])) -> (MOVQconst [c^d])
699 (XORLconst [c] (MOVLconst [d])) -> (MOVLconst [c^d])
700 (XORWconst [c] (MOVWconst [d])) -> (MOVWconst [c^d])
701 (XORBconst [c] (MOVBconst [d])) -> (MOVBconst [c^d])
702 (NOTQ (MOVQconst [c])) -> (MOVQconst [^c])
703 (NOTL (MOVLconst [c])) -> (MOVLconst [^c])
704 (NOTW (MOVWconst [c])) -> (MOVWconst [^c])
705 (NOTB (MOVBconst [c])) -> (MOVBconst [^c])
706
707 // generic simplifications
708 // TODO: more of this
709 (ADDQ x (NEGQ y)) -> (SUBQ x y)
710 (ADDL x (NEGL y)) -> (SUBL x y)
711 (ADDW x (NEGW y)) -> (SUBW x y)
712 (ADDB x (NEGB y)) -> (SUBB x y)
713 (SUBQ x x) -> (MOVQconst [0])
714 (SUBL x x) -> (MOVLconst [0])
715 (SUBW x x) -> (MOVWconst [0])
716 (SUBB x x) -> (MOVBconst [0])
717 (ANDQ x x) -> x
718 (ANDL x x) -> x
719 (ANDW x x) -> x
720 (ANDB x x) -> x
721 (ORQ x x) -> x
722 (ORL x x) -> x
723 (ORW x x) -> x
724 (ORB x x) -> x
725 (XORQ x x) -> (MOVQconst [0])
726 (XORL x x) -> (MOVLconst [0])
727 (XORW x x) -> (MOVWconst [0])
728 (XORB x x) -> (MOVBconst [0])