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 (Last ___) => v.Args[len(v.Args)-1]
6
7 // Lowering arithmetic
8 (Add(64|32|16|8|Ptr) ...) => (I64Add ...)
9 (Add(64|32)F ...) => (F(64|32)Add ...)
10
11 (Sub(64|32|16|8|Ptr) ...) => (I64Sub ...)
12 (Sub(64|32)F ...) => (F(64|32)Sub ...)
13
14 (Mul(64|32|16|8) ...) => (I64Mul ...)
15 (Mul(64|32)F ...) => (F(64|32)Mul ...)
16
17 (Div64 [false] x y) => (I64DivS x y)
18 (Div32 [false] x y) => (I64DivS (SignExt32to64 x) (SignExt32to64 y))
19 (Div16 [false] x y) => (I64DivS (SignExt16to64 x) (SignExt16to64 y))
20 (Div8 x y) => (I64DivS (SignExt8to64 x) (SignExt8to64 y))
21 (Div64u ...) => (I64DivU ...)
22 (Div32u x y) => (I64DivU (ZeroExt32to64 x) (ZeroExt32to64 y))
23 (Div16u x y) => (I64DivU (ZeroExt16to64 x) (ZeroExt16to64 y))
24 (Div8u x y) => (I64DivU (ZeroExt8to64 x) (ZeroExt8to64 y))
25 (Div(64|32)F ...) => (F(64|32)Div ...)
26
27 (Min(64|32)F ...) => (F(64|32)Min ...)
28 (Max(64|32)F ...) => (F(64|32)Max ...)
29
30 (Mod64 [false] x y) => (I64RemS x y)
31 (Mod32 [false] x y) => (I64RemS (SignExt32to64 x) (SignExt32to64 y))
32 (Mod16 [false] x y) => (I64RemS (SignExt16to64 x) (SignExt16to64 y))
33 (Mod8 x y) => (I64RemS (SignExt8to64 x) (SignExt8to64 y))
34 (Mod64u ...) => (I64RemU ...)
35 (Mod32u x y) => (I64RemU (ZeroExt32to64 x) (ZeroExt32to64 y))
36 (Mod16u x y) => (I64RemU (ZeroExt16to64 x) (ZeroExt16to64 y))
37 (Mod8u x y) => (I64RemU (ZeroExt8to64 x) (ZeroExt8to64 y))
38
39 (And(64|32|16|8|B) ...) => (I64And ...)
40
41 (Or(64|32|16|8|B) ...) => (I64Or ...)
42
43 (Xor(64|32|16|8) ...) => (I64Xor ...)
44
45 (Neg(64|32|16|8) x) => (I64Sub (I64Const [0]) x)
46 (Neg(64|32)F ...) => (F(64|32)Neg ...)
47
48 (Com(64|32|16|8) x) => (I64Xor x (I64Const [-1]))
49
50 (Not ...) => (I64Eqz ...)
51
52 (Avg64u x y) => (I64Add (I64ShrU (I64Sub x y) (I64Const [1])) y)
53
54 // High word of multiply without carry bits; see Hacker's Delight, 2nd. ed, Figure 8-2, p. 174.
55 (Hmul64 <t> x y) =>
56 (Last <t>
57 x0: (ZeroExt32to64 x)
58 x1: (I64ShrS x (I64Const [32]))
59 y0: (ZeroExt32to64 y)
60 y1: (I64ShrS y (I64Const [32]))
61 x0y0: (I64Mul x0 y0)
62 tt: (I64Add (I64Mul x1 y0) (I64ShrU x0y0 (I64Const [32])))
63 w1: (I64Add (I64Mul x0 y1) (ZeroExt32to64 tt))
64 w2: (I64ShrS tt (I64Const [32]))
65 (I64Add (I64Add (I64Mul x1 y1) w2) (I64ShrS w1 (I64Const [32]))))
66
67 // Same as Hmul64 but signed shifts now unsigned.
68 (Hmul64u <t> x y) =>
69 (Last <t>
70 x0: (ZeroExt32to64 x)
71 x1: (I64ShrU x (I64Const [32]))
72 y0: (ZeroExt32to64 y)
73 y1: (I64ShrU y (I64Const [32]))
74 w0: (I64Mul x0 y0)
75 tt: (I64Add (I64Mul x1 y0) (I64ShrU w0 (I64Const [32])))
76 w1: (I64Add (I64Mul x0 y1) (ZeroExt32to64 tt))
77 w2: (I64ShrU tt (I64Const [32]))
78 hi: (I64Add (I64Add (I64Mul x1 y1) w2) (I64ShrU w1 (I64Const [32]))))
79
80 (Select0 <t> (Mul64uhilo x y)) => (Hmul64u <t> x y)
81 (Select1 <t> (Mul64uhilo x y)) => (I64Mul x y)
82
83 // Lowering pointer arithmetic
84 (OffPtr ...) => (I64AddConst ...)
85
86 // Lowering extension
87 // It is unnecessary to extend loads
88 (SignExt32to64 x:(I64Load32S _ _)) => x
89 (SignExt16to(64|32) x:(I64Load16S _ _)) => x
90 (SignExt8to(64|32|16) x:(I64Load8S _ _)) => x
91 (ZeroExt32to64 x:(I64Load32U _ _)) => x
92 (ZeroExt16to(64|32) x:(I64Load16U _ _)) => x
93 (ZeroExt8to(64|32|16) x:(I64Load8U _ _)) => x
94 (SignExt32to64 x) => (I64Extend32S x)
95 (SignExt8to(64|32|16) x) => (I64Extend8S x)
96 (SignExt16to(64|32) x) => (I64Extend16S x)
97 (ZeroExt32to64 x) => (I64And x (I64Const [0xffffffff]))
98 (ZeroExt16to(64|32) x) => (I64And x (I64Const [0xffff]))
99 (ZeroExt8to(64|32|16) x) => (I64And x (I64Const [0xff]))
100
101 (Slicemask x) => (I64ShrS (I64Sub (I64Const [0]) x) (I64Const [63]))
102
103 // Lowering truncation
104 // Because we ignore the high parts, truncates are just copies.
105 (Trunc64to(32|16|8) ...) => (Copy ...)
106 (Trunc32to(16|8) ...) => (Copy ...)
107 (Trunc16to8 ...) => (Copy ...)
108
109 // Lowering float <=> int
110 (Cvt32to(64|32)F x) => (F(64|32)ConvertI64S (SignExt32to64 x))
111 (Cvt64to(64|32)F ...) => (F(64|32)ConvertI64S ...)
112 (Cvt32Uto(64|32)F x) => (F(64|32)ConvertI64U (ZeroExt32to64 x))
113 (Cvt64Uto(64|32)F ...) => (F(64|32)ConvertI64U ...)
114
115 (Cvt32Fto32 ...) => (I64TruncSatF32S ...)
116 (Cvt32Fto64 ...) => (I64TruncSatF32S ...)
117 (Cvt64Fto32 ...) => (I64TruncSatF64S ...)
118 (Cvt64Fto64 ...) => (I64TruncSatF64S ...)
119 (Cvt32Fto32U ...) => (I64TruncSatF32U ...)
120 (Cvt32Fto64U ...) => (I64TruncSatF32U ...)
121 (Cvt64Fto32U ...) => (I64TruncSatF64U ...)
122 (Cvt64Fto64U ...) => (I64TruncSatF64U ...)
123
124 (Cvt32Fto64F ...) => (F64PromoteF32 ...)
125 (Cvt64Fto32F ...) => (F32DemoteF64 ...)
126
127 (CvtBoolToUint8 ...) => (Copy ...)
128
129 (Round32F ...) => (Copy ...)
130 (Round64F ...) => (Copy ...)
131
132 // Lowering shifts
133 // Unsigned shifts need to return 0 if shift amount is >= width of shifted value.
134
135 (Lsh64x64 x y) && ssa.ShiftIsBounded(v) => (I64Shl x y)
136 (Lsh64x64 x (I64Const [c])) && uint64(c) < 64 => (I64Shl x (I64Const [c]))
137 (Lsh64x64 x (I64Const [c])) && uint64(c) >= 64 => (I64Const [0])
138 (Lsh64x64 x y) => (Select (I64Shl x y) (I64Const [0]) (I64LtU y (I64Const [64])))
139 (Lsh64x(32|16|8) [c] x y) => (Lsh64x64 [c] x (ZeroExt(32|16|8)to64 y))
140
141 (Lsh32x64 ...) => (Lsh64x64 ...)
142 (Lsh32x(32|16|8) [c] x y) => (Lsh64x64 [c] x (ZeroExt(32|16|8)to64 y))
143
144 (Lsh16x64 ...) => (Lsh64x64 ...)
145 (Lsh16x(32|16|8) [c] x y) => (Lsh64x64 [c] x (ZeroExt(32|16|8)to64 y))
146
147 (Lsh8x64 ...) => (Lsh64x64 ...)
148 (Lsh8x(32|16|8) [c] x y) => (Lsh64x64 [c] x (ZeroExt(32|16|8)to64 y))
149
150 (Rsh64Ux64 x y) && ssa.ShiftIsBounded(v) => (I64ShrU x y)
151 (Rsh64Ux64 x (I64Const [c])) && uint64(c) < 64 => (I64ShrU x (I64Const [c]))
152 (Rsh64Ux64 x (I64Const [c])) && uint64(c) >= 64 => (I64Const [0])
153 (Rsh64Ux64 x y) => (Select (I64ShrU x y) (I64Const [0]) (I64LtU y (I64Const [64])))
154 (Rsh64Ux(32|16|8) [c] x y) => (Rsh64Ux64 [c] x (ZeroExt(32|16|8)to64 y))
155
156 (Rsh32Ux64 [c] x y) => (Rsh64Ux64 [c] (ZeroExt32to64 x) y)
157 (Rsh32Ux(32|16|8) [c] x y) => (Rsh64Ux64 [c] (ZeroExt32to64 x) (ZeroExt(32|16|8)to64 y))
158
159 (Rsh16Ux64 [c] x y) => (Rsh64Ux64 [c] (ZeroExt16to64 x) y)
160 (Rsh16Ux(32|16|8) [c] x y) => (Rsh64Ux64 [c] (ZeroExt16to64 x) (ZeroExt(32|16|8)to64 y))
161
162 (Rsh8Ux64 [c] x y) => (Rsh64Ux64 [c] (ZeroExt8to64 x) y)
163 (Rsh8Ux(32|16|8) [c] x y) => (Rsh64Ux64 [c] (ZeroExt8to64 x) (ZeroExt(32|16|8)to64 y))
164
165 // Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value.
166 // We implement this by setting the shift value to (width - 1) if the shift value is >= width.
167
168 (Rsh64x64 x y) && ssa.ShiftIsBounded(v) => (I64ShrS x y)
169 (Rsh64x64 x (I64Const [c])) && uint64(c) < 64 => (I64ShrS x (I64Const [c]))
170 (Rsh64x64 x (I64Const [c])) && uint64(c) >= 64 => (I64ShrS x (I64Const [63]))
171 (Rsh64x64 x y) => (I64ShrS x (Select <typ.Int64> y (I64Const [63]) (I64LtU y (I64Const [64]))))
172 (Rsh64x(32|16|8) [c] x y) => (Rsh64x64 [c] x (ZeroExt(32|16|8)to64 y))
173
174 (Rsh32x64 [c] x y) => (Rsh64x64 [c] (SignExt32to64 x) y)
175 (Rsh32x(32|16|8) [c] x y) => (Rsh64x64 [c] (SignExt32to64 x) (ZeroExt(32|16|8)to64 y))
176
177 (Rsh16x64 [c] x y) => (Rsh64x64 [c] (SignExt16to64 x) y)
178 (Rsh16x(32|16|8) [c] x y) => (Rsh64x64 [c] (SignExt16to64 x) (ZeroExt(32|16|8)to64 y))
179
180 (Rsh8x64 [c] x y) => (Rsh64x64 [c] (SignExt8to64 x) y)
181 (Rsh8x(32|16|8) [c] x y) => (Rsh64x64 [c] (SignExt8to64 x) (ZeroExt(32|16|8)to64 y))
182
183 // Lowering rotates
184 (RotateLeft8 <t> x (I64Const [c])) => (Or8 (Lsh8x64 <t> x (I64Const [c&7])) (Rsh8Ux64 <t> x (I64Const [-c&7])))
185 (RotateLeft16 <t> x (I64Const [c])) => (Or16 (Lsh16x64 <t> x (I64Const [c&15])) (Rsh16Ux64 <t> x (I64Const [-c&15])))
186 (RotateLeft32 ...) => (I32Rotl ...)
187 (RotateLeft64 ...) => (I64Rotl ...)
188
189 // Lowering comparisons
190 (Less64 ...) => (I64LtS ...)
191 (Less32 x y) => (I64LtS (SignExt32to64 x) (SignExt32to64 y))
192 (Less16 x y) => (I64LtS (SignExt16to64 x) (SignExt16to64 y))
193 (Less8 x y) => (I64LtS (SignExt8to64 x) (SignExt8to64 y))
194 (Less64U ...) => (I64LtU ...)
195 (Less32U x y) => (I64LtU (ZeroExt32to64 x) (ZeroExt32to64 y))
196 (Less16U x y) => (I64LtU (ZeroExt16to64 x) (ZeroExt16to64 y))
197 (Less8U x y) => (I64LtU (ZeroExt8to64 x) (ZeroExt8to64 y))
198 (Less(64|32)F ...) => (F(64|32)Lt ...)
199
200 (Leq64 ...) => (I64LeS ...)
201 (Leq32 x y) => (I64LeS (SignExt32to64 x) (SignExt32to64 y))
202 (Leq16 x y) => (I64LeS (SignExt16to64 x) (SignExt16to64 y))
203 (Leq8 x y) => (I64LeS (SignExt8to64 x) (SignExt8to64 y))
204 (Leq64U ...) => (I64LeU ...)
205 (Leq32U x y) => (I64LeU (ZeroExt32to64 x) (ZeroExt32to64 y))
206 (Leq16U x y) => (I64LeU (ZeroExt16to64 x) (ZeroExt16to64 y))
207 (Leq8U x y) => (I64LeU (ZeroExt8to64 x) (ZeroExt8to64 y))
208 (Leq(64|32)F ...) => (F(64|32)Le ...)
209
210 (Eq64 ...) => (I64Eq ...)
211 (Eq32 x y) => (I64Eq (ZeroExt32to64 x) (ZeroExt32to64 y))
212 (Eq16 x y) => (I64Eq (ZeroExt16to64 x) (ZeroExt16to64 y))
213 (Eq8 x y) => (I64Eq (ZeroExt8to64 x) (ZeroExt8to64 y))
214 (EqB ...) => (I64Eq ...)
215 (EqPtr ...) => (I64Eq ...)
216 (Eq(64|32)F ...) => (F(64|32)Eq ...)
217
218 (Neq64 ...) => (I64Ne ...)
219 (Neq32 x y) => (I64Ne (ZeroExt32to64 x) (ZeroExt32to64 y))
220 (Neq16 x y) => (I64Ne (ZeroExt16to64 x) (ZeroExt16to64 y))
221 (Neq8 x y) => (I64Ne (ZeroExt8to64 x) (ZeroExt8to64 y))
222 (NeqB ...) => (I64Ne ...)
223 (NeqPtr ...) => (I64Ne ...)
224 (Neq(64|32)F ...) => (F(64|32)Ne ...)
225
226 // Lowering loads
227 (Load <t> ptr mem) && ssa.Is32BitFloat(t) => (F32Load ptr mem)
228 (Load <t> ptr mem) && ssa.Is64BitFloat(t) => (F64Load ptr mem)
229 (Load <t> ptr mem) && t.Size() == 16 => (V128Load ptr mem)
230 (Load <t> ptr mem) && t.Size() == 8 => (I64Load ptr mem)
231 (Load <t> ptr mem) && t.Size() == 4 && !t.IsSigned() => (I64Load32U ptr mem)
232 (Load <t> ptr mem) && t.Size() == 4 && t.IsSigned() => (I64Load32S ptr mem)
233 (Load <t> ptr mem) && t.Size() == 2 && !t.IsSigned() => (I64Load16U ptr mem)
234 (Load <t> ptr mem) && t.Size() == 2 && t.IsSigned() => (I64Load16S ptr mem)
235 (Load <t> ptr mem) && t.Size() == 1 && !t.IsSigned() => (I64Load8U ptr mem)
236 (Load <t> ptr mem) && t.Size() == 1 && t.IsSigned() => (I64Load8S ptr mem)
237
238 // Lowering stores
239 (Store {t} ptr val mem) && ssa.Is64BitFloat(t) => (F64Store ptr val mem)
240 (Store {t} ptr val mem) && ssa.Is32BitFloat(t) => (F32Store ptr val mem)
241 (Store {t} ptr val mem) && t.Size() == 16 => (V128Store ptr val mem)
242 (Store {t} ptr val mem) && t.Size() == 8 => (I64Store ptr val mem)
243 (Store {t} ptr val mem) && t.Size() == 4 => (I64Store32 ptr val mem)
244 (Store {t} ptr val mem) && t.Size() == 2 => (I64Store16 ptr val mem)
245 (Store {t} ptr val mem) && t.Size() == 1 => (I64Store8 ptr val mem)
246
247 (ZeroSIMD ...) => (V128Zero ...)
248
249 // Lowering moves
250 (Move [0] _ _ mem) => mem
251 (Move [1] dst src mem) => (I64Store8 dst (I64Load8U src mem) mem)
252 (Move [2] dst src mem) => (I64Store16 dst (I64Load16U src mem) mem)
253 (Move [4] dst src mem) => (I64Store32 dst (I64Load32U src mem) mem)
254 (Move [8] dst src mem) => (I64Store dst (I64Load src mem) mem)
255 (Move [16] dst src mem) =>
256 (I64Store [8] dst (I64Load [8] src mem)
257 (I64Store dst (I64Load src mem) mem))
258 (Move [3] dst src mem) =>
259 (I64Store8 [2] dst (I64Load8U [2] src mem)
260 (I64Store16 dst (I64Load16U src mem) mem))
261 (Move [5] dst src mem) =>
262 (I64Store8 [4] dst (I64Load8U [4] src mem)
263 (I64Store32 dst (I64Load32U src mem) mem))
264 (Move [6] dst src mem) =>
265 (I64Store16 [4] dst (I64Load16U [4] src mem)
266 (I64Store32 dst (I64Load32U src mem) mem))
267 (Move [7] dst src mem) =>
268 (I64Store32 [3] dst (I64Load32U [3] src mem)
269 (I64Store32 dst (I64Load32U src mem) mem))
270 (Move [s] dst src mem) && s > 8 && s < 16 =>
271 (I64Store [s-8] dst (I64Load [s-8] src mem)
272 (I64Store dst (I64Load src mem) mem))
273
274 // Large copying uses helper.
275 (Move [s] dst src mem) && ssa.LogLargeCopyValue(v, s) =>
276 (LoweredMove [s] dst src mem)
277
278 // Lowering Zero instructions
279 (Zero [0] _ mem) => mem
280 (Zero [1] destptr mem) => (I64Store8 destptr (I64Const [0]) mem)
281 (Zero [2] destptr mem) => (I64Store16 destptr (I64Const [0]) mem)
282 (Zero [4] destptr mem) => (I64Store32 destptr (I64Const [0]) mem)
283 (Zero [8] destptr mem) => (I64Store destptr (I64Const [0]) mem)
284
285 (Zero [3] destptr mem) =>
286 (I64Store8 [2] destptr (I64Const [0])
287 (I64Store16 destptr (I64Const [0]) mem))
288 (Zero [5] destptr mem) =>
289 (I64Store8 [4] destptr (I64Const [0])
290 (I64Store32 destptr (I64Const [0]) mem))
291 (Zero [6] destptr mem) =>
292 (I64Store16 [4] destptr (I64Const [0])
293 (I64Store32 destptr (I64Const [0]) mem))
294 (Zero [7] destptr mem) =>
295 (I64Store32 [3] destptr (I64Const [0])
296 (I64Store32 destptr (I64Const [0]) mem))
297
298 // Strip off any fractional word zeroing.
299 (Zero [s] destptr mem) && s%8 != 0 && s > 8 && s < 32 =>
300 (Zero [s-s%8] (OffPtr <destptr.Type> destptr [s%8])
301 (I64Store destptr (I64Const [0]) mem))
302
303 // Zero small numbers of words directly.
304 (Zero [16] destptr mem) =>
305 (I64Store [8] destptr (I64Const [0])
306 (I64Store destptr (I64Const [0]) mem))
307 (Zero [24] destptr mem) =>
308 (I64Store [16] destptr (I64Const [0])
309 (I64Store [8] destptr (I64Const [0])
310 (I64Store destptr (I64Const [0]) mem)))
311 (Zero [32] destptr mem) =>
312 (I64Store [24] destptr (I64Const [0])
313 (I64Store [16] destptr (I64Const [0])
314 (I64Store [8] destptr (I64Const [0])
315 (I64Store destptr (I64Const [0]) mem))))
316
317 // Large zeroing uses helper.
318 (Zero [s] destptr mem) =>
319 (LoweredZero [s] destptr mem)
320
321 // Lowering constants
322 (Const64 ...) => (I64Const ...)
323 (Const(32|16|8) [c]) => (I64Const [int64(c)])
324 (Const(64|32)F ...) => (F(64|32)Const ...)
325 (ConstNil) => (I64Const [0])
326 (ConstBool [c]) => (I64Const [ssa.B2i(c)])
327
328 // Lowering calls
329 (StaticCall ...) => (LoweredStaticCall ...)
330 (ClosureCall ...) => (LoweredClosureCall ...)
331 (InterCall ...) => (LoweredInterCall ...)
332 (TailCall ...) => (LoweredTailCall ...)
333 (TailCallInter ...) => (LoweredTailCallInter ...)
334
335 // Miscellaneous
336 (Convert ...) => (LoweredConvert ...)
337 (IsNonNil p) => (I64Eqz (I64Eqz p))
338 (IsInBounds ...) => (I64LtU ...)
339 (IsSliceInBounds ...) => (I64LeU ...)
340 (NilCheck ...) => (LoweredNilCheck ...)
341 (GetClosurePtr ...) => (LoweredGetClosurePtr ...)
342 (GetCallerPC ...) => (LoweredGetCallerPC ...)
343 (GetCallerSP ...) => (LoweredGetCallerSP ...)
344 (Addr {sym} base) => (LoweredAddr {sym} [0] base)
345 (LocalAddr <t> {sym} base mem) && t.Elem().HasPointers() => (LoweredAddr {sym} (SPanchored base mem))
346 (LocalAddr <t> {sym} base _) && !t.Elem().HasPointers() => (LoweredAddr {sym} base)
347
348 // Write barrier.
349 (WB ...) => (LoweredWB ...)
350
351 // --- Intrinsics ---
352 (Sqrt ...) => (F64Sqrt ...)
353 (Trunc ...) => (F64Trunc ...)
354 (Ceil ...) => (F64Ceil ...)
355 (Floor ...) => (F64Floor ...)
356 (RoundToEven ...) => (F64Nearest ...)
357 (Abs ...) => (F64Abs ...)
358 (Copysign ...) => (F64Copysign ...)
359
360 (F32DemoteF64 (F64(Sqrt|Trunc|Ceil|Floor|Nearest|Abs) (F64PromoteF32 x))) => (F32(Sqrt|Trunc|Ceil|Floor|Nearest|Abs) x)
361 (F32DemoteF64 (F64Copysign (F64PromoteF32 x) (F64PromoteF32 y))) => (F32Copysign x y)
362
363 (Sqrt32 ...) => (F32Sqrt ...)
364
365 (Ctz64 ...) => (I64Ctz ...)
366 (Ctz32 x) => (I64Ctz (I64Or x (I64Const [0x100000000])))
367 (Ctz16 x) => (I64Ctz (I64Or x (I64Const [0x10000])))
368 (Ctz8 x) => (I64Ctz (I64Or x (I64Const [0x100])))
369
370 (Ctz(64|32|16|8)NonZero ...) => (I64Ctz ...)
371
372 (BitLen64 x) => (I64Sub (I64Const [64]) (I64Clz x))
373 (BitLen(32|16|8) x) => (BitLen64 (ZeroExt(32|16|8)to64 x))
374
375 (PopCount64 ...) => (I64Popcnt ...)
376 (PopCount32 x) => (I64Popcnt (ZeroExt32to64 x))
377 (PopCount16 x) => (I64Popcnt (ZeroExt16to64 x))
378 (PopCount8 x) => (I64Popcnt (ZeroExt8to64 x))
379
380 (CondSelect ...) => (Select ...)
381
382 // --- Optimizations ---
383 (I64Add (I64Const [x]) (I64Const [y])) => (I64Const [x + y])
384 (I64Sub (I64Const [x]) (I64Const [y])) => (I64Const [x - y])
385 (I64Mul (I64Const [x]) (I64Const [y])) => (I64Const [x * y])
386 (I64And (I64Const [x]) (I64Const [y])) => (I64Const [x & y])
387 (I64Or (I64Const [x]) (I64Const [y])) => (I64Const [x | y])
388 (I64Xor (I64Const [x]) (I64Const [y])) => (I64Const [x ^ y])
389 (F64Add (F64Const [x]) (F64Const [y])) => (F64Const [x + y])
390 (F64Mul (F64Const [x]) (F64Const [y])) && !math.IsNaN(x * y) => (F64Const [x * y])
391 (I64Eq (I64Const [x]) (I64Const [y])) && x == y => (I64Const [1])
392 (I64Eq (I64Const [x]) (I64Const [y])) && x != y => (I64Const [0])
393 (I64Ne (I64Const [x]) (I64Const [y])) && x == y => (I64Const [0])
394 (I64Ne (I64Const [x]) (I64Const [y])) && x != y => (I64Const [1])
395
396 (I64Shl (I64Const [x]) (I64Const [y])) => (I64Const [x << uint64(y)])
397 (I64ShrU (I64Const [x]) (I64Const [y])) => (I64Const [int64(uint64(x) >> uint64(y))])
398 (I64ShrS (I64Const [x]) (I64Const [y])) => (I64Const [x >> uint64(y)])
399
400 // Identity and absorption rules for AND/OR/XOR/MUL.
401 // These fire on nodes created during or after lowering.
402 (I64And x (I64Const [-1])) => x
403 (I64And x (I64Const [0])) => (I64Const [0])
404 (I64Or x (I64Const [0])) => x
405 (I64Or x (I64Const [-1])) => (I64Const [-1])
406 (I64Xor x (I64Const [0])) => x
407 (I64Mul x (I64Const [0])) => (I64Const [0])
408 (I64Mul x (I64Const [1])) => x
409
410 // Double-mask elimination: cascaded zero-extensions produce
411 // (I64And (I64And x C1) C2) which can be collapsed to a single mask.
412 (I64And (I64And x (I64Const [c1])) (I64Const [c2])) => (I64And x (I64Const [c1 & c2]))
413
414 // Redundant sign-extensions: idempotent and narrower-subsumes-wider.
415 (I64Extend32S (I64Extend32S x)) => (I64Extend32S x)
416 (I64Extend16S (I64Extend16S x)) => (I64Extend16S x)
417 (I64Extend8S (I64Extend8S x)) => (I64Extend8S x)
418 (I64Extend32S (I64Extend16S x)) => (I64Extend16S x)
419 (I64Extend32S (I64Extend8S x)) => (I64Extend8S x)
420 (I64Extend16S (I64Extend8S x)) => (I64Extend8S x)
421
422 // Sign-extend of a value already zero-extended from fewer bits is a no-op.
423 // E.g. (I64Extend32S (I64And x (I64Const [0xff]))) — top 33 bits are already
424 // zero, so sign-extending from 32 is identity.
425 (I64Extend32S x:(I64And _ (I64Const [c]))) && c >= 0 && int64(int32(c)) == c => x
426 (I64Extend16S x:(I64And _ (I64Const [c]))) && c >= 0 && int64(int16(c)) == c => x
427 (I64Extend8S x:(I64And _ (I64Const [c]))) && c >= 0 && int64(int8(c)) == c => x
428
429 // Narrow loads already extend their results.
430 (I64Extend32S x:(I64Load32S _ _)) => x
431 (I64Extend16S x:(I64Load16S _ _)) => x
432 (I64Extend8S x:(I64Load8S _ _)) => x
433 (I64And x:(I64Load32U _ _) (I64Const [0xffffffff])) => x
434 (I64And x:(I64Load16U _ _) (I64Const [0xffff])) => x
435 (I64And x:(I64Load8U _ _) (I64Const [0xff])) => x
436
437 // genssa sign-extends signed arguments of 32 bits or less.
438 (I64Extend32S x:(Arg <t>)) && t.Size() == 4 && t.IsSigned() => x
439 (I64Extend16S x:(Arg <t>)) && t.Size() == 2 && t.IsSigned() => x
440 (I64Extend8S x:(Arg <t>)) && t.Size() == 1 && t.IsSigned() => x
441
442 // Fold sign extensions of constants.
443 (I64Extend32S (I64Const [c])) => (I64Const [int64(int32(c))])
444 (I64Extend16S (I64Const [c])) => (I64Const [int64(int16(c))])
445 (I64Extend8S (I64Const [c])) => (I64Const [int64(int8(c))])
446
447 // TODO: declare these operations as commutative and get rid of these rules?
448 (I64Add (I64Const [x]) y) && y.Op != ssaop.OpWasmI64Const => (I64Add y (I64Const [x]))
449 (I64Mul (I64Const [x]) y) && y.Op != ssaop.OpWasmI64Const => (I64Mul y (I64Const [x]))
450 (I64And (I64Const [x]) y) && y.Op != ssaop.OpWasmI64Const => (I64And y (I64Const [x]))
451 (I64Or (I64Const [x]) y) && y.Op != ssaop.OpWasmI64Const => (I64Or y (I64Const [x]))
452 (I64Xor (I64Const [x]) y) && y.Op != ssaop.OpWasmI64Const => (I64Xor y (I64Const [x]))
453 (F64Add (F64Const [x]) y) && y.Op != ssaop.OpWasmF64Const => (F64Add y (F64Const [x]))
454 (F64Mul (F64Const [x]) y) && y.Op != ssaop.OpWasmF64Const => (F64Mul y (F64Const [x]))
455 (I64Eq (I64Const [x]) y) && y.Op != ssaop.OpWasmI64Const => (I64Eq y (I64Const [x]))
456 (I64Ne (I64Const [x]) y) && y.Op != ssaop.OpWasmI64Const => (I64Ne y (I64Const [x]))
457
458 (I64Eq x (I64Const [0])) => (I64Eqz x)
459 (I64LtU (I64Const [0]) x) => (I64Eqz (I64Eqz x))
460 (I64LeU x (I64Const [0])) => (I64Eqz x)
461 (I64LtU x (I64Const [1])) => (I64Eqz x)
462 (I64LeU (I64Const [1]) x) => (I64Eqz (I64Eqz x))
463 (I64Ne x (I64Const [0])) => (I64Eqz (I64Eqz x))
464
465 (I64Add x (I64Const <t> [y])) && !t.IsPtr() => (I64AddConst [y] x)
466 (I64AddConst [0] x) => x
467 (I64Eqz (I64Eqz (I64Eqz x))) => (I64Eqz x)
468
469 // folding offset into load/store
470 ((I64Load|I64Load32U|I64Load32S|I64Load16U|I64Load16S|I64Load8U|I64Load8S) [off] (I64AddConst [off2] ptr) mem)
471 && ssa.IsU32Bit(off+off2) =>
472 ((I64Load|I64Load32U|I64Load32S|I64Load16U|I64Load16S|I64Load8U|I64Load8S) [off+off2] ptr mem)
473
474 ((I64Store|I64Store32|I64Store16|I64Store8) [off] (I64AddConst [off2] ptr) val mem)
475 && ssa.IsU32Bit(off+off2) =>
476 ((I64Store|I64Store32|I64Store16|I64Store8) [off+off2] ptr val mem)
477
478 // folding offset into address
479 (I64AddConst [off] (LoweredAddr {sym} [off2] base)) && ssa.IsU32Bit(off+int64(off2)) =>
480 (LoweredAddr {sym} [int32(off)+off2] base)
481 (I64AddConst [off] x:(SP)) && ssa.IsU32Bit(off) => (LoweredAddr [int32(off)] x) // so it is rematerializeable
482
483 // transforming readonly globals into constants
484 (I64Load [off] (LoweredAddr {sym} [off2] (SB)) _) && ssa.SymIsRO(sym) && ssa.IsU32Bit(off+int64(off2)) => (I64Const [int64(ssa.Read64(sym, off+int64(off2), config.Ctxt.Arch.ByteOrder))])
485 (I64Load32U [off] (LoweredAddr {sym} [off2] (SB)) _) && ssa.SymIsRO(sym) && ssa.IsU32Bit(off+int64(off2)) => (I64Const [int64(ssa.Read32(sym, off+int64(off2), config.Ctxt.Arch.ByteOrder))])
486 (I64Load16U [off] (LoweredAddr {sym} [off2] (SB)) _) && ssa.SymIsRO(sym) && ssa.IsU32Bit(off+int64(off2)) => (I64Const [int64(ssa.Read16(sym, off+int64(off2), config.Ctxt.Arch.ByteOrder))])
487 (I64Load8U [off] (LoweredAddr {sym} [off2] (SB)) _) && ssa.SymIsRO(sym) && ssa.IsU32Bit(off+int64(off2)) => (I64Const [int64(ssa.Read8(sym, off+int64(off2)))])
488 (I64Load32S [off] (LoweredAddr {sym} [off2] (SB)) _) && ssa.SymIsRO(sym) && ssa.IsU32Bit(off+int64(off2)) => (I64Const [int64(int32(ssa.Read32(sym, off+int64(off2), config.Ctxt.Arch.ByteOrder)))])
489 (I64Load16S [off] (LoweredAddr {sym} [off2] (SB)) _) && ssa.SymIsRO(sym) && ssa.IsU32Bit(off+int64(off2)) => (I64Const [int64(int16(ssa.Read16(sym, off+int64(off2), config.Ctxt.Arch.ByteOrder)))])
490 (I64Load8S [off] (LoweredAddr {sym} [off2] (SB)) _) && ssa.SymIsRO(sym) && ssa.IsU32Bit(off+int64(off2)) => (I64Const [int64(int8(ssa.Read8(sym, off+int64(off2))))])
491
View as plain text