2015-03-23 17:02:11 -07:00
|
|
|
// Copyright 2015 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
2016-08-20 22:05:47 -07:00
|
|
|
// Simplifications that apply to all backend architectures. As an example, this
|
|
|
|
|
// Go source code
|
|
|
|
|
//
|
|
|
|
|
// y := 0 * x
|
|
|
|
|
//
|
|
|
|
|
// can be translated into y := 0 without losing any information, which saves a
|
|
|
|
|
// pointless multiplication instruction. Other .rules files in this directory
|
|
|
|
|
// (for example AMD64.rules) contain rules specific to the architecture in the
|
|
|
|
|
// filename. The rules here apply to every architecture.
|
|
|
|
|
//
|
|
|
|
|
// The code for parsing this file lives in rulegen.go; this file generates
|
|
|
|
|
// ssa/rewritegeneric.go.
|
|
|
|
|
|
2015-05-28 16:45:33 -07:00
|
|
|
// values are specified using the following format:
|
2015-06-11 21:29:25 -07:00
|
|
|
// (op <type> [auxint] {aux} arg0 arg1 ...)
|
2016-03-29 16:39:53 -07:00
|
|
|
// the type, aux, and auxint fields are optional
|
2015-05-28 16:45:33 -07:00
|
|
|
// on the matching side
|
2015-06-11 21:29:25 -07:00
|
|
|
// - the type, aux, and auxint fields must match if they are specified.
|
2016-03-29 16:39:53 -07:00
|
|
|
// - the first occurrence of a variable defines that variable. Subsequent
|
|
|
|
|
// uses must match (be == to) the first use.
|
|
|
|
|
// - v is defined to be the value matched.
|
|
|
|
|
// - an additional conditional can be provided after the match pattern with "&&".
|
2015-05-28 16:45:33 -07:00
|
|
|
// on the generated side
|
|
|
|
|
// - the type of the top-level expression is the same as the one on the left-hand side.
|
2016-04-26 12:08:31 -07:00
|
|
|
// - the type of any subexpressions must be specified explicitly (or
|
|
|
|
|
// be specified in the op's type field).
|
2015-06-11 21:29:25 -07:00
|
|
|
// - auxint will be 0 if not specified.
|
2015-05-28 16:45:33 -07:00
|
|
|
// - aux will be nil if not specified.
|
|
|
|
|
|
|
|
|
|
// blocks are specified using the following format:
|
|
|
|
|
// (kind controlvalue succ0 succ1 ...)
|
|
|
|
|
// controlvalue must be "nil" or a value expression
|
|
|
|
|
// succ* fields must be variables
|
|
|
|
|
// For now, the generated successors must be a permutation of the matched successors.
|
|
|
|
|
|
2015-03-23 17:02:11 -07:00
|
|
|
// constant folding
|
2016-04-26 12:08:31 -07:00
|
|
|
(Trunc16to8 (Const16 [c])) -> (Const8 [int64(int8(c))])
|
|
|
|
|
(Trunc32to8 (Const32 [c])) -> (Const8 [int64(int8(c))])
|
|
|
|
|
(Trunc32to16 (Const32 [c])) -> (Const16 [int64(int16(c))])
|
|
|
|
|
(Trunc64to8 (Const64 [c])) -> (Const8 [int64(int8(c))])
|
|
|
|
|
(Trunc64to16 (Const64 [c])) -> (Const16 [int64(int16(c))])
|
|
|
|
|
(Trunc64to32 (Const64 [c])) -> (Const32 [int64(int32(c))])
|
2016-03-11 19:36:54 -06:00
|
|
|
(Cvt64Fto32F (Const64F [c])) -> (Const32F [f2i(float64(i2f32(c)))])
|
|
|
|
|
(Cvt32Fto64F (Const32F [c])) -> (Const64F [c]) // c is already a 64 bit float
|
2017-02-12 22:12:12 -05:00
|
|
|
(Round32F x:(Const32F)) -> x
|
|
|
|
|
(Round64F x:(Const64F)) -> x
|
2016-02-17 12:17:11 +01:00
|
|
|
|
2016-08-30 09:57:48 -07:00
|
|
|
(Trunc16to8 (ZeroExt8to16 x)) -> x
|
|
|
|
|
(Trunc32to8 (ZeroExt8to32 x)) -> x
|
|
|
|
|
(Trunc32to16 (ZeroExt8to32 x)) -> (ZeroExt8to16 x)
|
|
|
|
|
(Trunc32to16 (ZeroExt16to32 x)) -> x
|
|
|
|
|
(Trunc64to8 (ZeroExt8to64 x)) -> x
|
|
|
|
|
(Trunc64to16 (ZeroExt8to64 x)) -> (ZeroExt8to16 x)
|
|
|
|
|
(Trunc64to16 (ZeroExt16to64 x)) -> x
|
|
|
|
|
(Trunc64to32 (ZeroExt8to64 x)) -> (ZeroExt8to32 x)
|
|
|
|
|
(Trunc64to32 (ZeroExt16to64 x)) -> (ZeroExt16to32 x)
|
|
|
|
|
(Trunc64to32 (ZeroExt32to64 x)) -> x
|
|
|
|
|
(Trunc16to8 (SignExt8to16 x)) -> x
|
|
|
|
|
(Trunc32to8 (SignExt8to32 x)) -> x
|
|
|
|
|
(Trunc32to16 (SignExt8to32 x)) -> (SignExt8to16 x)
|
|
|
|
|
(Trunc32to16 (SignExt16to32 x)) -> x
|
|
|
|
|
(Trunc64to8 (SignExt8to64 x)) -> x
|
|
|
|
|
(Trunc64to16 (SignExt8to64 x)) -> (SignExt8to16 x)
|
|
|
|
|
(Trunc64to16 (SignExt16to64 x)) -> x
|
|
|
|
|
(Trunc64to32 (SignExt8to64 x)) -> (SignExt8to32 x)
|
|
|
|
|
(Trunc64to32 (SignExt16to64 x)) -> (SignExt16to32 x)
|
|
|
|
|
(Trunc64to32 (SignExt32to64 x)) -> x
|
|
|
|
|
|
2017-02-02 22:38:04 -08:00
|
|
|
(ZeroExt8to16 (Const8 [c])) -> (Const16 [int64( uint8(c))])
|
|
|
|
|
(ZeroExt8to32 (Const8 [c])) -> (Const32 [int64( uint8(c))])
|
|
|
|
|
(ZeroExt8to64 (Const8 [c])) -> (Const64 [int64( uint8(c))])
|
|
|
|
|
(ZeroExt16to32 (Const16 [c])) -> (Const32 [int64(uint16(c))])
|
|
|
|
|
(ZeroExt16to64 (Const16 [c])) -> (Const64 [int64(uint16(c))])
|
|
|
|
|
(ZeroExt32to64 (Const32 [c])) -> (Const64 [int64(uint32(c))])
|
|
|
|
|
(SignExt8to16 (Const8 [c])) -> (Const16 [int64( int8(c))])
|
|
|
|
|
(SignExt8to32 (Const8 [c])) -> (Const32 [int64( int8(c))])
|
|
|
|
|
(SignExt8to64 (Const8 [c])) -> (Const64 [int64( int8(c))])
|
|
|
|
|
(SignExt16to32 (Const16 [c])) -> (Const32 [int64( int16(c))])
|
|
|
|
|
(SignExt16to64 (Const16 [c])) -> (Const64 [int64( int16(c))])
|
|
|
|
|
(SignExt32to64 (Const32 [c])) -> (Const64 [int64( int32(c))])
|
|
|
|
|
|
2017-02-18 13:58:59 -08:00
|
|
|
(Neg8 (Const8 [c])) -> (Const8 [int64( -int8(c))])
|
|
|
|
|
(Neg16 (Const16 [c])) -> (Const16 [int64(-int16(c))])
|
|
|
|
|
(Neg32 (Const32 [c])) -> (Const32 [int64(-int32(c))])
|
|
|
|
|
(Neg64 (Const64 [c])) -> (Const64 [-c])
|
|
|
|
|
(Neg32F (Const32F [c])) && i2f(c) != 0 -> (Const32F [f2i(-i2f(c))])
|
|
|
|
|
(Neg64F (Const64F [c])) && i2f(c) != 0 -> (Const64F [f2i(-i2f(c))])
|
2016-02-08 18:55:56 +01:00
|
|
|
|
2016-04-26 12:08:31 -07:00
|
|
|
(Add8 (Const8 [c]) (Const8 [d])) -> (Const8 [int64(int8(c+d))])
|
|
|
|
|
(Add16 (Const16 [c]) (Const16 [d])) -> (Const16 [int64(int16(c+d))])
|
|
|
|
|
(Add32 (Const32 [c]) (Const32 [d])) -> (Const32 [int64(int32(c+d))])
|
|
|
|
|
(Add64 (Const64 [c]) (Const64 [d])) -> (Const64 [c+d])
|
2016-08-20 22:05:47 -07:00
|
|
|
(Add32F (Const32F [c]) (Const32F [d])) ->
|
2016-03-11 19:36:54 -06:00
|
|
|
(Const32F [f2i(float64(i2f32(c) + i2f32(d)))]) // ensure we combine the operands with 32 bit precision
|
|
|
|
|
(Add64F (Const64F [c]) (Const64F [d])) -> (Const64F [f2i(i2f(c) + i2f(d))])
|
2016-03-18 10:50:00 +01:00
|
|
|
(AddPtr <t> x (Const64 [c])) -> (OffPtr <t> x [c])
|
2015-11-02 21:28:13 -08:00
|
|
|
|
2016-04-26 12:08:31 -07:00
|
|
|
(Sub8 (Const8 [c]) (Const8 [d])) -> (Const8 [int64(int8(c-d))])
|
|
|
|
|
(Sub16 (Const16 [c]) (Const16 [d])) -> (Const16 [int64(int16(c-d))])
|
|
|
|
|
(Sub32 (Const32 [c]) (Const32 [d])) -> (Const32 [int64(int32(c-d))])
|
|
|
|
|
(Sub64 (Const64 [c]) (Const64 [d])) -> (Const64 [c-d])
|
2016-08-20 22:05:47 -07:00
|
|
|
(Sub32F (Const32F [c]) (Const32F [d])) ->
|
2016-03-11 19:36:54 -06:00
|
|
|
(Const32F [f2i(float64(i2f32(c) - i2f32(d)))])
|
|
|
|
|
(Sub64F (Const64F [c]) (Const64F [d])) -> (Const64F [f2i(i2f(c) - i2f(d))])
|
2015-11-02 21:28:13 -08:00
|
|
|
|
2016-04-26 12:08:31 -07:00
|
|
|
(Mul8 (Const8 [c]) (Const8 [d])) -> (Const8 [int64(int8(c*d))])
|
|
|
|
|
(Mul16 (Const16 [c]) (Const16 [d])) -> (Const16 [int64(int16(c*d))])
|
|
|
|
|
(Mul32 (Const32 [c]) (Const32 [d])) -> (Const32 [int64(int32(c*d))])
|
|
|
|
|
(Mul64 (Const64 [c]) (Const64 [d])) -> (Const64 [c*d])
|
2016-08-20 22:05:47 -07:00
|
|
|
(Mul32F (Const32F [c]) (Const32F [d])) ->
|
2016-03-11 19:36:54 -06:00
|
|
|
(Const32F [f2i(float64(i2f32(c) * i2f32(d)))])
|
|
|
|
|
(Mul64F (Const64F [c]) (Const64F [d])) -> (Const64F [f2i(i2f(c) * i2f(d))])
|
2015-11-02 21:28:13 -08:00
|
|
|
|
2017-02-20 08:43:54 -08:00
|
|
|
(And8 (Const8 [c]) (Const8 [d])) -> (Const8 [int64(int8(c&d))])
|
|
|
|
|
(And16 (Const16 [c]) (Const16 [d])) -> (Const16 [int64(int16(c&d))])
|
|
|
|
|
(And32 (Const32 [c]) (Const32 [d])) -> (Const32 [int64(int32(c&d))])
|
|
|
|
|
(And64 (Const64 [c]) (Const64 [d])) -> (Const64 [c&d])
|
|
|
|
|
|
|
|
|
|
(Or8 (Const8 [c]) (Const8 [d])) -> (Const8 [int64(int8(c|d))])
|
|
|
|
|
(Or16 (Const16 [c]) (Const16 [d])) -> (Const16 [int64(int16(c|d))])
|
|
|
|
|
(Or32 (Const32 [c]) (Const32 [d])) -> (Const32 [int64(int32(c|d))])
|
|
|
|
|
(Or64 (Const64 [c]) (Const64 [d])) -> (Const64 [c|d])
|
|
|
|
|
|
|
|
|
|
(Xor8 (Const8 [c]) (Const8 [d])) -> (Const8 [int64(int8(c^d))])
|
|
|
|
|
(Xor16 (Const16 [c]) (Const16 [d])) -> (Const16 [int64(int16(c^d))])
|
|
|
|
|
(Xor32 (Const32 [c]) (Const32 [d])) -> (Const32 [int64(int32(c^d))])
|
|
|
|
|
(Xor64 (Const64 [c]) (Const64 [d])) -> (Const64 [c^d])
|
|
|
|
|
|
2017-02-13 16:00:09 -08:00
|
|
|
(Div8 (Const8 [c]) (Const8 [d])) && d != 0 -> (Const8 [int64(int8(c)/int8(d))])
|
|
|
|
|
(Div16 (Const16 [c]) (Const16 [d])) && d != 0 -> (Const16 [int64(int16(c)/int16(d))])
|
|
|
|
|
(Div32 (Const32 [c]) (Const32 [d])) && d != 0 -> (Const32 [int64(int32(c)/int32(d))])
|
|
|
|
|
(Div64 (Const64 [c]) (Const64 [d])) && d != 0 -> (Const64 [c/d])
|
|
|
|
|
(Div8u (Const8 [c]) (Const8 [d])) && d != 0 -> (Const8 [int64(int8(uint8(c)/uint8(d)))])
|
|
|
|
|
(Div16u (Const16 [c]) (Const16 [d])) && d != 0 -> (Const16 [int64(int16(uint16(c)/uint16(d)))])
|
|
|
|
|
(Div32u (Const32 [c]) (Const32 [d])) && d != 0 -> (Const32 [int64(int32(uint32(c)/uint32(d)))])
|
|
|
|
|
(Div64u (Const64 [c]) (Const64 [d])) && d != 0 -> (Const64 [int64(uint64(c)/uint64(d))])
|
|
|
|
|
(Div32F (Const32F [c]) (Const32F [d])) -> (Const32F [f2i(float64(i2f32(c) / i2f32(d)))])
|
|
|
|
|
(Div64F (Const64F [c]) (Const64F [d])) -> (Const64F [f2i(i2f(c) / i2f(d))])
|
|
|
|
|
|
|
|
|
|
// Convert x * 1 to x.
|
|
|
|
|
(Mul8 (Const8 [1]) x) -> x
|
|
|
|
|
(Mul16 (Const16 [1]) x) -> x
|
|
|
|
|
(Mul32 (Const32 [1]) x) -> x
|
|
|
|
|
(Mul64 (Const64 [1]) x) -> x
|
|
|
|
|
|
|
|
|
|
// Convert x * -1 to -x.
|
2016-07-05 10:03:02 -07:00
|
|
|
(Mul8 (Const8 [-1]) x) -> (Neg8 x)
|
|
|
|
|
(Mul16 (Const16 [-1]) x) -> (Neg16 x)
|
|
|
|
|
(Mul32 (Const32 [-1]) x) -> (Neg32 x)
|
|
|
|
|
(Mul64 (Const64 [-1]) x) -> (Neg64 x)
|
|
|
|
|
|
2017-02-04 21:20:23 -08:00
|
|
|
// Convert multiplication by a power of two to a shift.
|
|
|
|
|
(Mul8 <t> n (Const8 [c])) && isPowerOfTwo(c) -> (Lsh8x64 <t> n (Const64 <config.fe.TypeUInt64()> [log2(c)]))
|
|
|
|
|
(Mul16 <t> n (Const16 [c])) && isPowerOfTwo(c) -> (Lsh16x64 <t> n (Const64 <config.fe.TypeUInt64()> [log2(c)]))
|
|
|
|
|
(Mul32 <t> n (Const32 [c])) && isPowerOfTwo(c) -> (Lsh32x64 <t> n (Const64 <config.fe.TypeUInt64()> [log2(c)]))
|
|
|
|
|
(Mul64 <t> n (Const64 [c])) && isPowerOfTwo(c) -> (Lsh64x64 <t> n (Const64 <config.fe.TypeUInt64()> [log2(c)]))
|
|
|
|
|
(Mul8 <t> n (Const8 [c])) && t.IsSigned() && isPowerOfTwo(-c) -> (Neg8 (Lsh8x64 <t> n (Const64 <config.fe.TypeUInt64()> [log2(-c)])))
|
|
|
|
|
(Mul16 <t> n (Const16 [c])) && t.IsSigned() && isPowerOfTwo(-c) -> (Neg16 (Lsh16x64 <t> n (Const64 <config.fe.TypeUInt64()> [log2(-c)])))
|
|
|
|
|
(Mul32 <t> n (Const32 [c])) && t.IsSigned() && isPowerOfTwo(-c) -> (Neg32 (Lsh32x64 <t> n (Const64 <config.fe.TypeUInt64()> [log2(-c)])))
|
|
|
|
|
(Mul64 <t> n (Const64 [c])) && t.IsSigned() && isPowerOfTwo(-c) -> (Neg64 (Lsh64x64 <t> n (Const64 <config.fe.TypeUInt64()> [log2(-c)])))
|
|
|
|
|
|
2016-04-26 12:08:31 -07:00
|
|
|
(Mod8 (Const8 [c]) (Const8 [d])) && d != 0 -> (Const8 [int64(int8(c % d))])
|
|
|
|
|
(Mod16 (Const16 [c]) (Const16 [d])) && d != 0 -> (Const16 [int64(int16(c % d))])
|
|
|
|
|
(Mod32 (Const32 [c]) (Const32 [d])) && d != 0 -> (Const32 [int64(int32(c % d))])
|
|
|
|
|
(Mod64 (Const64 [c]) (Const64 [d])) && d != 0 -> (Const64 [c % d])
|
2016-04-04 16:13:35 +02:00
|
|
|
|
2016-04-26 12:08:31 -07:00
|
|
|
(Mod8u (Const8 [c]) (Const8 [d])) && d != 0 -> (Const8 [int64(uint8(c) % uint8(d))])
|
|
|
|
|
(Mod16u (Const16 [c]) (Const16 [d])) && d != 0 -> (Const16 [int64(uint16(c) % uint16(d))])
|
|
|
|
|
(Mod32u (Const32 [c]) (Const32 [d])) && d != 0 -> (Const32 [int64(uint32(c) % uint32(d))])
|
|
|
|
|
(Mod64u (Const64 [c]) (Const64 [d])) && d != 0 -> (Const64 [int64(uint64(c) % uint64(d))])
|
2016-04-04 16:13:35 +02:00
|
|
|
|
2016-02-03 06:21:24 -05:00
|
|
|
(Lsh64x64 (Const64 [c]) (Const64 [d])) -> (Const64 [c << uint64(d)])
|
|
|
|
|
(Rsh64x64 (Const64 [c]) (Const64 [d])) -> (Const64 [c >> uint64(d)])
|
|
|
|
|
(Rsh64Ux64 (Const64 [c]) (Const64 [d])) -> (Const64 [int64(uint64(c) >> uint64(d))])
|
|
|
|
|
(Lsh32x64 (Const32 [c]) (Const64 [d])) -> (Const32 [int64(int32(c) << uint64(d))])
|
|
|
|
|
(Rsh32x64 (Const32 [c]) (Const64 [d])) -> (Const32 [int64(int32(c) >> uint64(d))])
|
2016-04-07 10:21:35 -07:00
|
|
|
(Rsh32Ux64 (Const32 [c]) (Const64 [d])) -> (Const32 [int64(int32(uint32(c) >> uint64(d)))])
|
2016-02-03 06:21:24 -05:00
|
|
|
(Lsh16x64 (Const16 [c]) (Const64 [d])) -> (Const16 [int64(int16(c) << uint64(d))])
|
|
|
|
|
(Rsh16x64 (Const16 [c]) (Const64 [d])) -> (Const16 [int64(int16(c) >> uint64(d))])
|
2016-04-07 10:21:35 -07:00
|
|
|
(Rsh16Ux64 (Const16 [c]) (Const64 [d])) -> (Const16 [int64(int16(uint16(c) >> uint64(d)))])
|
2016-02-03 06:21:24 -05:00
|
|
|
(Lsh8x64 (Const8 [c]) (Const64 [d])) -> (Const8 [int64(int8(c) << uint64(d))])
|
|
|
|
|
(Rsh8x64 (Const8 [c]) (Const64 [d])) -> (Const8 [int64(int8(c) >> uint64(d))])
|
2016-04-07 10:21:35 -07:00
|
|
|
(Rsh8Ux64 (Const8 [c]) (Const64 [d])) -> (Const8 [int64(int8(uint8(c) >> uint64(d)))])
|
2016-02-03 06:21:24 -05:00
|
|
|
|
2016-04-24 21:21:07 +02:00
|
|
|
// Fold IsInBounds when the range of the index cannot exceed the limit.
|
2016-04-26 12:08:31 -07:00
|
|
|
(IsInBounds (ZeroExt8to32 _) (Const32 [c])) && (1 << 8) <= c -> (ConstBool [1])
|
|
|
|
|
(IsInBounds (ZeroExt8to64 _) (Const64 [c])) && (1 << 8) <= c -> (ConstBool [1])
|
2016-03-29 16:39:53 -07:00
|
|
|
(IsInBounds (ZeroExt16to32 _) (Const32 [c])) && (1 << 16) <= c -> (ConstBool [1])
|
2016-03-20 22:15:27 +01:00
|
|
|
(IsInBounds (ZeroExt16to64 _) (Const64 [c])) && (1 << 16) <= c -> (ConstBool [1])
|
2016-03-07 18:36:16 +01:00
|
|
|
(IsInBounds x x) -> (ConstBool [0])
|
2016-03-29 16:39:53 -07:00
|
|
|
(IsInBounds (And32 (Const32 [c]) _) (Const32 [d])) && 0 <= c && c < d -> (ConstBool [1])
|
|
|
|
|
(IsInBounds (And64 (Const64 [c]) _) (Const64 [d])) && 0 <= c && c < d -> (ConstBool [1])
|
|
|
|
|
(IsInBounds (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(0 <= c && c < d)])
|
|
|
|
|
(IsInBounds (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(0 <= c && c < d)])
|
2016-04-04 16:38:26 +02:00
|
|
|
// (Mod64u x y) is always between 0 (inclusive) and y (exclusive).
|
|
|
|
|
(IsInBounds (Mod32u _ y) y) -> (ConstBool [1])
|
|
|
|
|
(IsInBounds (Mod64u _ y) y) -> (ConstBool [1])
|
|
|
|
|
|
2016-03-07 18:36:16 +01:00
|
|
|
(IsSliceInBounds x x) -> (ConstBool [1])
|
2016-03-29 16:39:53 -07:00
|
|
|
(IsSliceInBounds (And32 (Const32 [c]) _) (Const32 [d])) && 0 <= c && c <= d -> (ConstBool [1])
|
|
|
|
|
(IsSliceInBounds (And64 (Const64 [c]) _) (Const64 [d])) && 0 <= c && c <= d -> (ConstBool [1])
|
2016-03-07 18:36:16 +01:00
|
|
|
(IsSliceInBounds (Const32 [0]) _) -> (ConstBool [1])
|
|
|
|
|
(IsSliceInBounds (Const64 [0]) _) -> (ConstBool [1])
|
2016-03-29 16:39:53 -07:00
|
|
|
(IsSliceInBounds (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(0 <= c && c <= d)])
|
|
|
|
|
(IsSliceInBounds (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(0 <= c && c <= d)])
|
2016-03-07 18:36:16 +01:00
|
|
|
(IsSliceInBounds (SliceLen x) (SliceCap x)) -> (ConstBool [1])
|
2016-02-17 12:17:11 +01:00
|
|
|
|
2015-09-03 18:24:22 -05:00
|
|
|
(Eq64 x x) -> (ConstBool [1])
|
|
|
|
|
(Eq32 x x) -> (ConstBool [1])
|
|
|
|
|
(Eq16 x x) -> (ConstBool [1])
|
2016-04-26 12:08:31 -07:00
|
|
|
(Eq8 x x) -> (ConstBool [1])
|
2016-04-24 21:21:07 +02:00
|
|
|
(EqB (ConstBool [c]) (ConstBool [d])) -> (ConstBool [b2i(c == d)])
|
|
|
|
|
(EqB (ConstBool [0]) x) -> (Not x)
|
|
|
|
|
(EqB (ConstBool [1]) x) -> x
|
2016-02-17 12:17:11 +01:00
|
|
|
|
2015-09-03 18:24:22 -05:00
|
|
|
(Neq64 x x) -> (ConstBool [0])
|
|
|
|
|
(Neq32 x x) -> (ConstBool [0])
|
|
|
|
|
(Neq16 x x) -> (ConstBool [0])
|
2016-04-26 12:08:31 -07:00
|
|
|
(Neq8 x x) -> (ConstBool [0])
|
2016-04-24 21:21:07 +02:00
|
|
|
(NeqB (ConstBool [c]) (ConstBool [d])) -> (ConstBool [b2i(c != d)])
|
|
|
|
|
(NeqB (ConstBool [0]) x) -> x
|
|
|
|
|
(NeqB (ConstBool [1]) x) -> (Not x)
|
2015-03-23 17:02:11 -07:00
|
|
|
|
2016-02-03 19:43:46 +01:00
|
|
|
(Eq64 (Const64 <t> [c]) (Add64 (Const64 <t> [d]) x)) -> (Eq64 (Const64 <t> [c-d]) x)
|
2016-03-29 16:39:53 -07:00
|
|
|
(Eq32 (Const32 <t> [c]) (Add32 (Const32 <t> [d]) x)) -> (Eq32 (Const32 <t> [int64(int32(c-d))]) x)
|
|
|
|
|
(Eq16 (Const16 <t> [c]) (Add16 (Const16 <t> [d]) x)) -> (Eq16 (Const16 <t> [int64(int16(c-d))]) x)
|
2016-04-26 12:08:31 -07:00
|
|
|
(Eq8 (Const8 <t> [c]) (Add8 (Const8 <t> [d]) x)) -> (Eq8 (Const8 <t> [int64(int8(c-d))]) x)
|
2016-02-03 19:43:46 +01:00
|
|
|
|
|
|
|
|
(Neq64 (Const64 <t> [c]) (Add64 (Const64 <t> [d]) x)) -> (Neq64 (Const64 <t> [c-d]) x)
|
2016-03-29 16:39:53 -07:00
|
|
|
(Neq32 (Const32 <t> [c]) (Add32 (Const32 <t> [d]) x)) -> (Neq32 (Const32 <t> [int64(int32(c-d))]) x)
|
|
|
|
|
(Neq16 (Const16 <t> [c]) (Add16 (Const16 <t> [d]) x)) -> (Neq16 (Const16 <t> [int64(int16(c-d))]) x)
|
2016-04-26 12:08:31 -07:00
|
|
|
(Neq8 (Const8 <t> [c]) (Add8 (Const8 <t> [d]) x)) -> (Neq8 (Const8 <t> [int64(int8(c-d))]) x)
|
2016-02-03 19:43:46 +01:00
|
|
|
|
2016-02-09 19:13:43 +01:00
|
|
|
// canonicalize: swap arguments for commutative operations when one argument is a constant.
|
2016-02-03 19:43:46 +01:00
|
|
|
(Eq64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Eq64 (Const64 <t> [c]) x)
|
|
|
|
|
(Eq32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Eq32 (Const32 <t> [c]) x)
|
|
|
|
|
(Eq16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Eq16 (Const16 <t> [c]) x)
|
2016-04-26 12:08:31 -07:00
|
|
|
(Eq8 x (Const8 <t> [c])) && x.Op != OpConst8 -> (Eq8 (Const8 <t> [c]) x)
|
2016-02-03 19:43:46 +01:00
|
|
|
|
|
|
|
|
(Neq64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Neq64 (Const64 <t> [c]) x)
|
|
|
|
|
(Neq32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Neq32 (Const32 <t> [c]) x)
|
|
|
|
|
(Neq16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Neq16 (Const16 <t> [c]) x)
|
2016-04-26 12:08:31 -07:00
|
|
|
(Neq8 x (Const8 <t> [c])) && x.Op != OpConst8 -> (Neq8 (Const8 <t> [c]) x)
|
2016-02-03 19:43:46 +01:00
|
|
|
|
2016-03-18 10:50:00 +01:00
|
|
|
// AddPtr is not canonicalized because nilcheck ptr checks the first argument to be non-nil.
|
2016-02-03 19:43:46 +01:00
|
|
|
(Add64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Add64 (Const64 <t> [c]) x)
|
|
|
|
|
(Add32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Add32 (Const32 <t> [c]) x)
|
|
|
|
|
(Add16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Add16 (Const16 <t> [c]) x)
|
2016-04-26 12:08:31 -07:00
|
|
|
(Add8 x (Const8 <t> [c])) && x.Op != OpConst8 -> (Add8 (Const8 <t> [c]) x)
|
2016-02-03 19:43:46 +01:00
|
|
|
|
2016-02-09 19:13:43 +01:00
|
|
|
(Mul64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Mul64 (Const64 <t> [c]) x)
|
|
|
|
|
(Mul32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Mul32 (Const32 <t> [c]) x)
|
|
|
|
|
(Mul16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Mul16 (Const16 <t> [c]) x)
|
2016-04-26 12:08:31 -07:00
|
|
|
(Mul8 x (Const8 <t> [c])) && x.Op != OpConst8 -> (Mul8 (Const8 <t> [c]) x)
|
2016-02-09 19:13:43 +01:00
|
|
|
|
2016-02-03 19:43:46 +01:00
|
|
|
(Sub64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Add64 (Const64 <t> [-c]) x)
|
2016-03-29 16:39:53 -07:00
|
|
|
(Sub32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Add32 (Const32 <t> [int64(int32(-c))]) x)
|
|
|
|
|
(Sub16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Add16 (Const16 <t> [int64(int16(-c))]) x)
|
2016-04-26 12:08:31 -07:00
|
|
|
(Sub8 x (Const8 <t> [c])) && x.Op != OpConst8 -> (Add8 (Const8 <t> [int64(int8(-c))]) x)
|
2016-02-03 19:43:46 +01:00
|
|
|
|
2016-02-09 19:13:43 +01:00
|
|
|
(And64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (And64 (Const64 <t> [c]) x)
|
|
|
|
|
(And32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (And32 (Const32 <t> [c]) x)
|
|
|
|
|
(And16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (And16 (Const16 <t> [c]) x)
|
2016-04-26 12:08:31 -07:00
|
|
|
(And8 x (Const8 <t> [c])) && x.Op != OpConst8 -> (And8 (Const8 <t> [c]) x)
|
2016-02-09 19:13:43 +01:00
|
|
|
|
|
|
|
|
(Or64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Or64 (Const64 <t> [c]) x)
|
|
|
|
|
(Or32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Or32 (Const32 <t> [c]) x)
|
|
|
|
|
(Or16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Or16 (Const16 <t> [c]) x)
|
2016-04-26 12:08:31 -07:00
|
|
|
(Or8 x (Const8 <t> [c])) && x.Op != OpConst8 -> (Or8 (Const8 <t> [c]) x)
|
2016-02-09 19:13:43 +01:00
|
|
|
|
|
|
|
|
(Xor64 x (Const64 <t> [c])) && x.Op != OpConst64 -> (Xor64 (Const64 <t> [c]) x)
|
|
|
|
|
(Xor32 x (Const32 <t> [c])) && x.Op != OpConst32 -> (Xor32 (Const32 <t> [c]) x)
|
|
|
|
|
(Xor16 x (Const16 <t> [c])) && x.Op != OpConst16 -> (Xor16 (Const16 <t> [c]) x)
|
2016-04-26 12:08:31 -07:00
|
|
|
(Xor8 x (Const8 <t> [c])) && x.Op != OpConst8 -> (Xor8 (Const8 <t> [c]) x)
|
2016-02-09 19:13:43 +01:00
|
|
|
|
2016-08-31 12:37:19 +02:00
|
|
|
// fold negation into comparison operators
|
|
|
|
|
(Not (Eq64 x y)) -> (Neq64 x y)
|
|
|
|
|
(Not (Eq32 x y)) -> (Neq32 x y)
|
|
|
|
|
(Not (Eq16 x y)) -> (Neq16 x y)
|
|
|
|
|
(Not (Eq8 x y)) -> (Neq8 x y)
|
|
|
|
|
(Not (EqB x y)) -> (NeqB x y)
|
|
|
|
|
|
|
|
|
|
(Not (Neq64 x y)) -> (Eq64 x y)
|
|
|
|
|
(Not (Neq32 x y)) -> (Eq32 x y)
|
|
|
|
|
(Not (Neq16 x y)) -> (Eq16 x y)
|
|
|
|
|
(Not (Neq8 x y)) -> (Eq8 x y)
|
|
|
|
|
(Not (NeqB x y)) -> (EqB x y)
|
|
|
|
|
|
|
|
|
|
(Not (Greater64 x y)) -> (Leq64 x y)
|
|
|
|
|
(Not (Greater32 x y)) -> (Leq32 x y)
|
|
|
|
|
(Not (Greater16 x y)) -> (Leq16 x y)
|
|
|
|
|
(Not (Greater8 x y)) -> (Leq8 x y)
|
|
|
|
|
|
|
|
|
|
(Not (Greater64U x y)) -> (Leq64U x y)
|
|
|
|
|
(Not (Greater32U x y)) -> (Leq32U x y)
|
|
|
|
|
(Not (Greater16U x y)) -> (Leq16U x y)
|
|
|
|
|
(Not (Greater8U x y)) -> (Leq8U x y)
|
|
|
|
|
|
|
|
|
|
(Not (Geq64 x y)) -> (Less64 x y)
|
|
|
|
|
(Not (Geq32 x y)) -> (Less32 x y)
|
|
|
|
|
(Not (Geq16 x y)) -> (Less16 x y)
|
|
|
|
|
(Not (Geq8 x y)) -> (Less8 x y)
|
|
|
|
|
|
|
|
|
|
(Not (Geq64U x y)) -> (Less64U x y)
|
|
|
|
|
(Not (Geq32U x y)) -> (Less32U x y)
|
|
|
|
|
(Not (Geq16U x y)) -> (Less16U x y)
|
|
|
|
|
(Not (Geq8U x y)) -> (Less8U x y)
|
|
|
|
|
|
|
|
|
|
(Not (Less64 x y)) -> (Geq64 x y)
|
|
|
|
|
(Not (Less32 x y)) -> (Geq32 x y)
|
|
|
|
|
(Not (Less16 x y)) -> (Geq16 x y)
|
|
|
|
|
(Not (Less8 x y)) -> (Geq8 x y)
|
|
|
|
|
|
|
|
|
|
(Not (Less64U x y)) -> (Geq64U x y)
|
|
|
|
|
(Not (Less32U x y)) -> (Geq32U x y)
|
|
|
|
|
(Not (Less16U x y)) -> (Geq16U x y)
|
|
|
|
|
(Not (Less8U x y)) -> (Geq8U x y)
|
|
|
|
|
|
|
|
|
|
(Not (Leq64 x y)) -> (Greater64 x y)
|
|
|
|
|
(Not (Leq32 x y)) -> (Greater32 x y)
|
|
|
|
|
(Not (Leq16 x y)) -> (Greater16 x y)
|
|
|
|
|
(Not (Leq8 x y)) -> (Greater8 x y)
|
|
|
|
|
|
|
|
|
|
(Not (Leq64U x y)) -> (Greater64U x y)
|
|
|
|
|
(Not (Leq32U x y)) -> (Greater32U x y)
|
|
|
|
|
(Not (Leq16U x y)) -> (Greater16U x y)
|
|
|
|
|
(Not (Leq8U x y)) -> (Greater8U x y)
|
|
|
|
|
|
2016-03-01 13:39:47 +01:00
|
|
|
// Distribute multiplication c * (d+x) -> c*d + c*x. Useful for:
|
|
|
|
|
// a[i].b = ...; a[i+1].b = ...
|
2016-04-26 12:08:31 -07:00
|
|
|
(Mul64 (Const64 <t> [c]) (Add64 <t> (Const64 <t> [d]) x)) ->
|
|
|
|
|
(Add64 (Const64 <t> [c*d]) (Mul64 <t> (Const64 <t> [c]) x))
|
|
|
|
|
(Mul32 (Const32 <t> [c]) (Add32 <t> (Const32 <t> [d]) x)) ->
|
|
|
|
|
(Add32 (Const32 <t> [int64(int32(c*d))]) (Mul32 <t> (Const32 <t> [c]) x))
|
2016-03-01 13:39:47 +01:00
|
|
|
|
2016-02-03 06:21:24 -05:00
|
|
|
// rewrite shifts of 8/16/32 bit consts into 64 bit consts to reduce
|
|
|
|
|
// the number of the other rewrite rules for const shifts
|
|
|
|
|
(Lsh64x32 <t> x (Const32 [c])) -> (Lsh64x64 x (Const64 <t> [int64(uint32(c))]))
|
|
|
|
|
(Lsh64x16 <t> x (Const16 [c])) -> (Lsh64x64 x (Const64 <t> [int64(uint16(c))]))
|
2016-04-26 12:08:31 -07:00
|
|
|
(Lsh64x8 <t> x (Const8 [c])) -> (Lsh64x64 x (Const64 <t> [int64(uint8(c))]))
|
2016-02-03 06:21:24 -05:00
|
|
|
(Rsh64x32 <t> x (Const32 [c])) -> (Rsh64x64 x (Const64 <t> [int64(uint32(c))]))
|
|
|
|
|
(Rsh64x16 <t> x (Const16 [c])) -> (Rsh64x64 x (Const64 <t> [int64(uint16(c))]))
|
2016-04-26 12:08:31 -07:00
|
|
|
(Rsh64x8 <t> x (Const8 [c])) -> (Rsh64x64 x (Const64 <t> [int64(uint8(c))]))
|
2016-02-03 06:21:24 -05:00
|
|
|
(Rsh64Ux32 <t> x (Const32 [c])) -> (Rsh64Ux64 x (Const64 <t> [int64(uint32(c))]))
|
|
|
|
|
(Rsh64Ux16 <t> x (Const16 [c])) -> (Rsh64Ux64 x (Const64 <t> [int64(uint16(c))]))
|
2016-04-26 12:08:31 -07:00
|
|
|
(Rsh64Ux8 <t> x (Const8 [c])) -> (Rsh64Ux64 x (Const64 <t> [int64(uint8(c))]))
|
2016-02-03 06:21:24 -05:00
|
|
|
|
|
|
|
|
(Lsh32x32 <t> x (Const32 [c])) -> (Lsh32x64 x (Const64 <t> [int64(uint32(c))]))
|
|
|
|
|
(Lsh32x16 <t> x (Const16 [c])) -> (Lsh32x64 x (Const64 <t> [int64(uint16(c))]))
|
2016-04-26 12:08:31 -07:00
|
|
|
(Lsh32x8 <t> x (Const8 [c])) -> (Lsh32x64 x (Const64 <t> [int64(uint8(c))]))
|
2016-02-03 06:21:24 -05:00
|
|
|
(Rsh32x32 <t> x (Const32 [c])) -> (Rsh32x64 x (Const64 <t> [int64(uint32(c))]))
|
|
|
|
|
(Rsh32x16 <t> x (Const16 [c])) -> (Rsh32x64 x (Const64 <t> [int64(uint16(c))]))
|
2016-04-26 12:08:31 -07:00
|
|
|
(Rsh32x8 <t> x (Const8 [c])) -> (Rsh32x64 x (Const64 <t> [int64(uint8(c))]))
|
2016-02-03 06:21:24 -05:00
|
|
|
(Rsh32Ux32 <t> x (Const32 [c])) -> (Rsh32Ux64 x (Const64 <t> [int64(uint32(c))]))
|
|
|
|
|
(Rsh32Ux16 <t> x (Const16 [c])) -> (Rsh32Ux64 x (Const64 <t> [int64(uint16(c))]))
|
2016-04-26 12:08:31 -07:00
|
|
|
(Rsh32Ux8 <t> x (Const8 [c])) -> (Rsh32Ux64 x (Const64 <t> [int64(uint8(c))]))
|
2016-02-03 06:21:24 -05:00
|
|
|
|
|
|
|
|
(Lsh16x32 <t> x (Const32 [c])) -> (Lsh16x64 x (Const64 <t> [int64(uint32(c))]))
|
|
|
|
|
(Lsh16x16 <t> x (Const16 [c])) -> (Lsh16x64 x (Const64 <t> [int64(uint16(c))]))
|
2016-04-26 12:08:31 -07:00
|
|
|
(Lsh16x8 <t> x (Const8 [c])) -> (Lsh16x64 x (Const64 <t> [int64(uint8(c))]))
|
2016-02-03 06:21:24 -05:00
|
|
|
(Rsh16x32 <t> x (Const32 [c])) -> (Rsh16x64 x (Const64 <t> [int64(uint32(c))]))
|
|
|
|
|
(Rsh16x16 <t> x (Const16 [c])) -> (Rsh16x64 x (Const64 <t> [int64(uint16(c))]))
|
2016-04-26 12:08:31 -07:00
|
|
|
(Rsh16x8 <t> x (Const8 [c])) -> (Rsh16x64 x (Const64 <t> [int64(uint8(c))]))
|
2016-02-03 06:21:24 -05:00
|
|
|
(Rsh16Ux32 <t> x (Const32 [c])) -> (Rsh16Ux64 x (Const64 <t> [int64(uint32(c))]))
|
|
|
|
|
(Rsh16Ux16 <t> x (Const16 [c])) -> (Rsh16Ux64 x (Const64 <t> [int64(uint16(c))]))
|
2016-04-26 12:08:31 -07:00
|
|
|
(Rsh16Ux8 <t> x (Const8 [c])) -> (Rsh16Ux64 x (Const64 <t> [int64(uint8(c))]))
|
2016-02-03 06:21:24 -05:00
|
|
|
|
|
|
|
|
(Lsh8x32 <t> x (Const32 [c])) -> (Lsh8x64 x (Const64 <t> [int64(uint32(c))]))
|
|
|
|
|
(Lsh8x16 <t> x (Const16 [c])) -> (Lsh8x64 x (Const64 <t> [int64(uint16(c))]))
|
2016-04-26 12:08:31 -07:00
|
|
|
(Lsh8x8 <t> x (Const8 [c])) -> (Lsh8x64 x (Const64 <t> [int64(uint8(c))]))
|
2016-02-03 06:21:24 -05:00
|
|
|
(Rsh8x32 <t> x (Const32 [c])) -> (Rsh8x64 x (Const64 <t> [int64(uint32(c))]))
|
|
|
|
|
(Rsh8x16 <t> x (Const16 [c])) -> (Rsh8x64 x (Const64 <t> [int64(uint16(c))]))
|
2016-04-26 12:08:31 -07:00
|
|
|
(Rsh8x8 <t> x (Const8 [c])) -> (Rsh8x64 x (Const64 <t> [int64(uint8(c))]))
|
2016-02-03 06:21:24 -05:00
|
|
|
(Rsh8Ux32 <t> x (Const32 [c])) -> (Rsh8Ux64 x (Const64 <t> [int64(uint32(c))]))
|
|
|
|
|
(Rsh8Ux16 <t> x (Const16 [c])) -> (Rsh8Ux64 x (Const64 <t> [int64(uint16(c))]))
|
2016-04-26 12:08:31 -07:00
|
|
|
(Rsh8Ux8 <t> x (Const8 [c])) -> (Rsh8Ux64 x (Const64 <t> [int64(uint8(c))]))
|
2016-02-03 06:21:24 -05:00
|
|
|
|
|
|
|
|
// shifts by zero
|
|
|
|
|
(Lsh64x64 x (Const64 [0])) -> x
|
|
|
|
|
(Rsh64x64 x (Const64 [0])) -> x
|
|
|
|
|
(Rsh64Ux64 x (Const64 [0])) -> x
|
|
|
|
|
(Lsh32x64 x (Const64 [0])) -> x
|
|
|
|
|
(Rsh32x64 x (Const64 [0])) -> x
|
|
|
|
|
(Rsh32Ux64 x (Const64 [0])) -> x
|
|
|
|
|
(Lsh16x64 x (Const64 [0])) -> x
|
|
|
|
|
(Rsh16x64 x (Const64 [0])) -> x
|
|
|
|
|
(Rsh16Ux64 x (Const64 [0])) -> x
|
|
|
|
|
(Lsh8x64 x (Const64 [0])) -> x
|
|
|
|
|
(Rsh8x64 x (Const64 [0])) -> x
|
|
|
|
|
(Rsh8Ux64 x (Const64 [0])) -> x
|
|
|
|
|
|
2016-02-09 19:13:43 +01:00
|
|
|
// zero shifted.
|
|
|
|
|
(Lsh64x64 (Const64 [0]) _) -> (Const64 [0])
|
2016-05-28 21:15:24 -07:00
|
|
|
(Lsh64x32 (Const64 [0]) _) -> (Const64 [0])
|
|
|
|
|
(Lsh64x16 (Const64 [0]) _) -> (Const64 [0])
|
|
|
|
|
(Lsh64x8 (Const64 [0]) _) -> (Const64 [0])
|
2016-02-09 19:13:43 +01:00
|
|
|
(Rsh64x64 (Const64 [0]) _) -> (Const64 [0])
|
2016-05-28 21:15:24 -07:00
|
|
|
(Rsh64x32 (Const64 [0]) _) -> (Const64 [0])
|
|
|
|
|
(Rsh64x16 (Const64 [0]) _) -> (Const64 [0])
|
|
|
|
|
(Rsh64x8 (Const64 [0]) _) -> (Const64 [0])
|
2016-02-09 19:13:43 +01:00
|
|
|
(Rsh64Ux64 (Const64 [0]) _) -> (Const64 [0])
|
2016-05-28 21:15:24 -07:00
|
|
|
(Rsh64Ux32 (Const64 [0]) _) -> (Const64 [0])
|
|
|
|
|
(Rsh64Ux16 (Const64 [0]) _) -> (Const64 [0])
|
|
|
|
|
(Rsh64Ux8 (Const64 [0]) _) -> (Const64 [0])
|
|
|
|
|
(Lsh32x64 (Const32 [0]) _) -> (Const32 [0])
|
|
|
|
|
(Lsh32x32 (Const32 [0]) _) -> (Const32 [0])
|
|
|
|
|
(Lsh32x16 (Const32 [0]) _) -> (Const32 [0])
|
|
|
|
|
(Lsh32x8 (Const32 [0]) _) -> (Const32 [0])
|
|
|
|
|
(Rsh32x64 (Const32 [0]) _) -> (Const32 [0])
|
|
|
|
|
(Rsh32x32 (Const32 [0]) _) -> (Const32 [0])
|
|
|
|
|
(Rsh32x16 (Const32 [0]) _) -> (Const32 [0])
|
|
|
|
|
(Rsh32x8 (Const32 [0]) _) -> (Const32 [0])
|
|
|
|
|
(Rsh32Ux64 (Const32 [0]) _) -> (Const32 [0])
|
|
|
|
|
(Rsh32Ux32 (Const32 [0]) _) -> (Const32 [0])
|
|
|
|
|
(Rsh32Ux16 (Const32 [0]) _) -> (Const32 [0])
|
|
|
|
|
(Rsh32Ux8 (Const32 [0]) _) -> (Const32 [0])
|
|
|
|
|
(Lsh16x64 (Const16 [0]) _) -> (Const16 [0])
|
|
|
|
|
(Lsh16x32 (Const16 [0]) _) -> (Const16 [0])
|
|
|
|
|
(Lsh16x16 (Const16 [0]) _) -> (Const16 [0])
|
|
|
|
|
(Lsh16x8 (Const16 [0]) _) -> (Const16 [0])
|
|
|
|
|
(Rsh16x64 (Const16 [0]) _) -> (Const16 [0])
|
|
|
|
|
(Rsh16x32 (Const16 [0]) _) -> (Const16 [0])
|
|
|
|
|
(Rsh16x16 (Const16 [0]) _) -> (Const16 [0])
|
|
|
|
|
(Rsh16x8 (Const16 [0]) _) -> (Const16 [0])
|
|
|
|
|
(Rsh16Ux64 (Const16 [0]) _) -> (Const16 [0])
|
|
|
|
|
(Rsh16Ux32 (Const16 [0]) _) -> (Const16 [0])
|
|
|
|
|
(Rsh16Ux16 (Const16 [0]) _) -> (Const16 [0])
|
|
|
|
|
(Rsh16Ux8 (Const16 [0]) _) -> (Const16 [0])
|
|
|
|
|
(Lsh8x64 (Const8 [0]) _) -> (Const8 [0])
|
|
|
|
|
(Lsh8x32 (Const8 [0]) _) -> (Const8 [0])
|
|
|
|
|
(Lsh8x16 (Const8 [0]) _) -> (Const8 [0])
|
|
|
|
|
(Lsh8x8 (Const8 [0]) _) -> (Const8 [0])
|
|
|
|
|
(Rsh8x64 (Const8 [0]) _) -> (Const8 [0])
|
|
|
|
|
(Rsh8x32 (Const8 [0]) _) -> (Const8 [0])
|
|
|
|
|
(Rsh8x16 (Const8 [0]) _) -> (Const8 [0])
|
|
|
|
|
(Rsh8x8 (Const8 [0]) _) -> (Const8 [0])
|
|
|
|
|
(Rsh8Ux64 (Const8 [0]) _) -> (Const8 [0])
|
|
|
|
|
(Rsh8Ux32 (Const8 [0]) _) -> (Const8 [0])
|
|
|
|
|
(Rsh8Ux16 (Const8 [0]) _) -> (Const8 [0])
|
|
|
|
|
(Rsh8Ux8 (Const8 [0]) _) -> (Const8 [0])
|
2016-02-09 19:13:43 +01:00
|
|
|
|
2016-02-03 06:21:24 -05:00
|
|
|
// large left shifts of all values, and right shifts of unsigned values
|
|
|
|
|
(Lsh64x64 _ (Const64 [c])) && uint64(c) >= 64 -> (Const64 [0])
|
|
|
|
|
(Rsh64Ux64 _ (Const64 [c])) && uint64(c) >= 64 -> (Const64 [0])
|
2016-02-17 14:08:36 +01:00
|
|
|
(Lsh32x64 _ (Const64 [c])) && uint64(c) >= 32 -> (Const32 [0])
|
|
|
|
|
(Rsh32Ux64 _ (Const64 [c])) && uint64(c) >= 32 -> (Const32 [0])
|
|
|
|
|
(Lsh16x64 _ (Const64 [c])) && uint64(c) >= 16 -> (Const16 [0])
|
|
|
|
|
(Rsh16Ux64 _ (Const64 [c])) && uint64(c) >= 16 -> (Const16 [0])
|
2016-04-26 12:08:31 -07:00
|
|
|
(Lsh8x64 _ (Const64 [c])) && uint64(c) >= 8 -> (Const8 [0])
|
|
|
|
|
(Rsh8Ux64 _ (Const64 [c])) && uint64(c) >= 8 -> (Const8 [0])
|
2016-02-03 06:21:24 -05:00
|
|
|
|
|
|
|
|
// combine const shifts
|
|
|
|
|
(Lsh64x64 <t> (Lsh64x64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Lsh64x64 x (Const64 <t> [c+d]))
|
|
|
|
|
(Lsh32x64 <t> (Lsh32x64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Lsh32x64 x (Const64 <t> [c+d]))
|
|
|
|
|
(Lsh16x64 <t> (Lsh16x64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Lsh16x64 x (Const64 <t> [c+d]))
|
|
|
|
|
(Lsh8x64 <t> (Lsh8x64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Lsh8x64 x (Const64 <t> [c+d]))
|
|
|
|
|
|
|
|
|
|
(Rsh64x64 <t> (Rsh64x64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh64x64 x (Const64 <t> [c+d]))
|
|
|
|
|
(Rsh32x64 <t> (Rsh32x64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh32x64 x (Const64 <t> [c+d]))
|
|
|
|
|
(Rsh16x64 <t> (Rsh16x64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh16x64 x (Const64 <t> [c+d]))
|
|
|
|
|
(Rsh8x64 <t> (Rsh8x64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh8x64 x (Const64 <t> [c+d]))
|
|
|
|
|
|
|
|
|
|
(Rsh64Ux64 <t> (Rsh64Ux64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh64Ux64 x (Const64 <t> [c+d]))
|
|
|
|
|
(Rsh32Ux64 <t> (Rsh32Ux64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh32Ux64 x (Const64 <t> [c+d]))
|
|
|
|
|
(Rsh16Ux64 <t> (Rsh16Ux64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh16Ux64 x (Const64 <t> [c+d]))
|
|
|
|
|
(Rsh8Ux64 <t> (Rsh8Ux64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh8Ux64 x (Const64 <t> [c+d]))
|
|
|
|
|
|
2016-04-26 12:08:31 -07:00
|
|
|
// ((x >> c1) << c2) >> c3
|
|
|
|
|
(Rsh64Ux64 (Lsh64x64 (Rsh64Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
2016-05-28 21:15:24 -07:00
|
|
|
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
2016-04-26 12:08:31 -07:00
|
|
|
-> (Rsh64Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
2016-05-28 21:15:24 -07:00
|
|
|
(Rsh32Ux64 (Lsh32x64 (Rsh32Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
|
|
|
|
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
|
|
|
|
-> (Rsh32Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
|
|
|
|
(Rsh16Ux64 (Lsh16x64 (Rsh16Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
|
|
|
|
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
|
|
|
|
-> (Rsh16Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
|
|
|
|
(Rsh8Ux64 (Lsh8x64 (Rsh8Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
|
|
|
|
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
|
|
|
|
-> (Rsh8Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
2016-04-26 12:08:31 -07:00
|
|
|
|
|
|
|
|
// ((x << c1) >> c2) << c3
|
|
|
|
|
(Lsh64x64 (Rsh64Ux64 (Lsh64x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
2016-05-28 21:15:24 -07:00
|
|
|
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
2016-04-26 12:08:31 -07:00
|
|
|
-> (Lsh64x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
2016-05-28 21:15:24 -07:00
|
|
|
(Lsh32x64 (Rsh32Ux64 (Lsh32x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
|
|
|
|
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
|
|
|
|
-> (Lsh32x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
|
|
|
|
(Lsh16x64 (Rsh16Ux64 (Lsh16x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
|
|
|
|
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
|
|
|
|
-> (Lsh16x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
|
|
|
|
(Lsh8x64 (Rsh8Ux64 (Lsh8x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
|
|
|
|
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
|
|
|
|
-> (Lsh8x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
2016-04-26 12:08:31 -07:00
|
|
|
|
2017-02-20 15:54:43 -05:00
|
|
|
// replace shifts with zero extensions
|
|
|
|
|
(Rsh16Ux64 (Lsh16x64 x (Const64 [8])) (Const64 [8])) -> (ZeroExt8to16 (Trunc16to8 <config.fe.TypeUInt8()> x))
|
|
|
|
|
(Rsh32Ux64 (Lsh32x64 x (Const64 [24])) (Const64 [24])) -> (ZeroExt8to32 (Trunc32to8 <config.fe.TypeUInt8()> x))
|
|
|
|
|
(Rsh64Ux64 (Lsh64x64 x (Const64 [56])) (Const64 [56])) -> (ZeroExt8to64 (Trunc64to8 <config.fe.TypeUInt8()> x))
|
|
|
|
|
(Rsh32Ux64 (Lsh32x64 x (Const64 [16])) (Const64 [16])) -> (ZeroExt16to32 (Trunc32to16 <config.fe.TypeUInt16()> x))
|
|
|
|
|
(Rsh64Ux64 (Lsh64x64 x (Const64 [48])) (Const64 [48])) -> (ZeroExt16to64 (Trunc64to16 <config.fe.TypeUInt16()> x))
|
|
|
|
|
(Rsh64Ux64 (Lsh64x64 x (Const64 [32])) (Const64 [32])) -> (ZeroExt32to64 (Trunc64to32 <config.fe.TypeUInt32()> x))
|
|
|
|
|
|
|
|
|
|
// replace shifts with sign extensions
|
|
|
|
|
(Rsh16x64 (Lsh16x64 x (Const64 [8])) (Const64 [8])) -> (SignExt8to16 (Trunc16to8 <config.fe.TypeInt8()> x))
|
|
|
|
|
(Rsh32x64 (Lsh32x64 x (Const64 [24])) (Const64 [24])) -> (SignExt8to32 (Trunc32to8 <config.fe.TypeInt8()> x))
|
|
|
|
|
(Rsh64x64 (Lsh64x64 x (Const64 [56])) (Const64 [56])) -> (SignExt8to64 (Trunc64to8 <config.fe.TypeInt8()> x))
|
|
|
|
|
(Rsh32x64 (Lsh32x64 x (Const64 [16])) (Const64 [16])) -> (SignExt16to32 (Trunc32to16 <config.fe.TypeInt16()> x))
|
|
|
|
|
(Rsh64x64 (Lsh64x64 x (Const64 [48])) (Const64 [48])) -> (SignExt16to64 (Trunc64to16 <config.fe.TypeInt16()> x))
|
|
|
|
|
(Rsh64x64 (Lsh64x64 x (Const64 [32])) (Const64 [32])) -> (SignExt32to64 (Trunc64to32 <config.fe.TypeInt32()> x))
|
|
|
|
|
|
2015-10-27 17:46:53 -05:00
|
|
|
// constant comparisons
|
2016-03-29 16:39:53 -07:00
|
|
|
(Eq64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c == d)])
|
|
|
|
|
(Eq32 (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(c == d)])
|
|
|
|
|
(Eq16 (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(c == d)])
|
|
|
|
|
(Eq8 (Const8 [c]) (Const8 [d])) -> (ConstBool [b2i(c == d)])
|
2015-10-27 17:46:53 -05:00
|
|
|
|
2016-03-29 16:39:53 -07:00
|
|
|
(Neq64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c != d)])
|
|
|
|
|
(Neq32 (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(c != d)])
|
|
|
|
|
(Neq16 (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(c != d)])
|
|
|
|
|
(Neq8 (Const8 [c]) (Const8 [d])) -> (ConstBool [b2i(c != d)])
|
2015-10-27 17:46:53 -05:00
|
|
|
|
2016-03-29 16:39:53 -07:00
|
|
|
(Greater64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c > d)])
|
|
|
|
|
(Greater32 (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(c > d)])
|
|
|
|
|
(Greater16 (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(c > d)])
|
|
|
|
|
(Greater8 (Const8 [c]) (Const8 [d])) -> (ConstBool [b2i(c > d)])
|
2015-10-27 17:46:53 -05:00
|
|
|
|
|
|
|
|
(Greater64U (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(uint64(c) > uint64(d))])
|
|
|
|
|
(Greater32U (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(uint32(c) > uint32(d))])
|
|
|
|
|
(Greater16U (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(uint16(c) > uint16(d))])
|
|
|
|
|
(Greater8U (Const8 [c]) (Const8 [d])) -> (ConstBool [b2i(uint8(c) > uint8(d))])
|
|
|
|
|
|
2016-03-29 16:39:53 -07:00
|
|
|
(Geq64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c >= d)])
|
|
|
|
|
(Geq32 (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(c >= d)])
|
|
|
|
|
(Geq16 (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(c >= d)])
|
|
|
|
|
(Geq8 (Const8 [c]) (Const8 [d])) -> (ConstBool [b2i(c >= d)])
|
2015-10-27 17:46:53 -05:00
|
|
|
|
|
|
|
|
(Geq64U (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(uint64(c) >= uint64(d))])
|
|
|
|
|
(Geq32U (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(uint32(c) >= uint32(d))])
|
|
|
|
|
(Geq16U (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(uint16(c) >= uint16(d))])
|
|
|
|
|
(Geq8U (Const8 [c]) (Const8 [d])) -> (ConstBool [b2i(uint8(c) >= uint8(d))])
|
|
|
|
|
|
2016-03-29 16:39:53 -07:00
|
|
|
(Less64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c < d)])
|
|
|
|
|
(Less32 (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(c < d)])
|
|
|
|
|
(Less16 (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(c < d)])
|
|
|
|
|
(Less8 (Const8 [c]) (Const8 [d])) -> (ConstBool [b2i(c < d)])
|
2015-10-27 17:46:53 -05:00
|
|
|
|
|
|
|
|
(Less64U (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(uint64(c) < uint64(d))])
|
|
|
|
|
(Less32U (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(uint32(c) < uint32(d))])
|
|
|
|
|
(Less16U (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(uint16(c) < uint16(d))])
|
|
|
|
|
(Less8U (Const8 [c]) (Const8 [d])) -> (ConstBool [b2i(uint8(c) < uint8(d))])
|
|
|
|
|
|
2016-03-29 16:39:53 -07:00
|
|
|
(Leq64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c <= d)])
|
|
|
|
|
(Leq32 (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(c <= d)])
|
|
|
|
|
(Leq16 (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(c <= d)])
|
|
|
|
|
(Leq8 (Const8 [c]) (Const8 [d])) -> (ConstBool [b2i(c <= d)])
|
2015-10-27 17:46:53 -05:00
|
|
|
|
|
|
|
|
(Leq64U (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(uint64(c) <= uint64(d))])
|
|
|
|
|
(Leq32U (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(uint32(c) <= uint32(d))])
|
|
|
|
|
(Leq16U (Const16 [c]) (Const16 [d])) -> (ConstBool [b2i(uint16(c) <= uint16(d))])
|
|
|
|
|
(Leq8U (Const8 [c]) (Const8 [d])) -> (ConstBool [b2i(uint8(c) <= uint8(d))])
|
|
|
|
|
|
2015-08-14 12:59:33 +02:00
|
|
|
// simplifications
|
|
|
|
|
(Or64 x x) -> x
|
|
|
|
|
(Or32 x x) -> x
|
|
|
|
|
(Or16 x x) -> x
|
2016-04-26 12:08:31 -07:00
|
|
|
(Or8 x x) -> x
|
2016-02-09 19:13:43 +01:00
|
|
|
(Or64 (Const64 [0]) x) -> x
|
|
|
|
|
(Or32 (Const32 [0]) x) -> x
|
|
|
|
|
(Or16 (Const16 [0]) x) -> x
|
2016-04-26 12:08:31 -07:00
|
|
|
(Or8 (Const8 [0]) x) -> x
|
2016-02-09 19:13:43 +01:00
|
|
|
(Or64 (Const64 [-1]) _) -> (Const64 [-1])
|
|
|
|
|
(Or32 (Const32 [-1]) _) -> (Const32 [-1])
|
|
|
|
|
(Or16 (Const16 [-1]) _) -> (Const16 [-1])
|
2016-04-26 12:08:31 -07:00
|
|
|
(Or8 (Const8 [-1]) _) -> (Const8 [-1])
|
2015-08-14 12:59:33 +02:00
|
|
|
(And64 x x) -> x
|
|
|
|
|
(And32 x x) -> x
|
|
|
|
|
(And16 x x) -> x
|
2016-04-26 12:08:31 -07:00
|
|
|
(And8 x x) -> x
|
2016-02-09 19:13:43 +01:00
|
|
|
(And64 (Const64 [-1]) x) -> x
|
|
|
|
|
(And32 (Const32 [-1]) x) -> x
|
|
|
|
|
(And16 (Const16 [-1]) x) -> x
|
2016-04-26 12:08:31 -07:00
|
|
|
(And8 (Const8 [-1]) x) -> x
|
2016-02-09 19:13:43 +01:00
|
|
|
(And64 (Const64 [0]) _) -> (Const64 [0])
|
|
|
|
|
(And32 (Const32 [0]) _) -> (Const32 [0])
|
|
|
|
|
(And16 (Const16 [0]) _) -> (Const16 [0])
|
2016-04-26 12:08:31 -07:00
|
|
|
(And8 (Const8 [0]) _) -> (Const8 [0])
|
2015-08-14 12:59:33 +02:00
|
|
|
(Xor64 x x) -> (Const64 [0])
|
|
|
|
|
(Xor32 x x) -> (Const32 [0])
|
|
|
|
|
(Xor16 x x) -> (Const16 [0])
|
2016-04-26 12:08:31 -07:00
|
|
|
(Xor8 x x) -> (Const8 [0])
|
2016-02-09 19:13:43 +01:00
|
|
|
(Xor64 (Const64 [0]) x) -> x
|
|
|
|
|
(Xor32 (Const32 [0]) x) -> x
|
|
|
|
|
(Xor16 (Const16 [0]) x) -> x
|
2016-04-26 12:08:31 -07:00
|
|
|
(Xor8 (Const8 [0]) x) -> x
|
2016-02-09 19:13:43 +01:00
|
|
|
(Add64 (Const64 [0]) x) -> x
|
|
|
|
|
(Add32 (Const32 [0]) x) -> x
|
|
|
|
|
(Add16 (Const16 [0]) x) -> x
|
2016-04-26 12:08:31 -07:00
|
|
|
(Add8 (Const8 [0]) x) -> x
|
2015-08-14 12:59:33 +02:00
|
|
|
(Sub64 x x) -> (Const64 [0])
|
|
|
|
|
(Sub32 x x) -> (Const32 [0])
|
|
|
|
|
(Sub16 x x) -> (Const16 [0])
|
2016-04-26 12:08:31 -07:00
|
|
|
(Sub8 x x) -> (Const8 [0])
|
2016-02-09 19:13:43 +01:00
|
|
|
(Mul64 (Const64 [0]) _) -> (Const64 [0])
|
|
|
|
|
(Mul32 (Const32 [0]) _) -> (Const32 [0])
|
|
|
|
|
(Mul16 (Const16 [0]) _) -> (Const16 [0])
|
2016-04-26 12:08:31 -07:00
|
|
|
(Mul8 (Const8 [0]) _) -> (Const8 [0])
|
|
|
|
|
(Com8 (Com8 x)) -> x
|
2015-08-05 10:33:09 -07:00
|
|
|
(Com16 (Com16 x)) -> x
|
|
|
|
|
(Com32 (Com32 x)) -> x
|
|
|
|
|
(Com64 (Com64 x)) -> x
|
2016-04-26 12:08:31 -07:00
|
|
|
(Neg8 (Sub8 x y)) -> (Sub8 y x)
|
2016-02-09 19:13:43 +01:00
|
|
|
(Neg16 (Sub16 x y)) -> (Sub16 y x)
|
|
|
|
|
(Neg32 (Sub32 x y)) -> (Sub32 y x)
|
|
|
|
|
(Neg64 (Sub64 x y)) -> (Sub64 y x)
|
2017-02-20 08:43:54 -08:00
|
|
|
(Add8 (Const8 [1]) (Com8 x)) -> (Neg8 x)
|
|
|
|
|
(Add16 (Const16 [1]) (Com16 x)) -> (Neg16 x)
|
|
|
|
|
(Add32 (Const32 [1]) (Com32 x)) -> (Neg32 x)
|
|
|
|
|
(Add64 (Const64 [1]) (Com64 x)) -> (Neg64 x)
|
2015-07-30 16:02:24 -04:00
|
|
|
|
2016-04-18 09:28:50 -07:00
|
|
|
(And64 x (And64 x y)) -> (And64 x y)
|
|
|
|
|
(And32 x (And32 x y)) -> (And32 x y)
|
|
|
|
|
(And16 x (And16 x y)) -> (And16 x y)
|
|
|
|
|
(And8 x (And8 x y)) -> (And8 x y)
|
|
|
|
|
(And64 x (And64 y x)) -> (And64 x y)
|
|
|
|
|
(And32 x (And32 y x)) -> (And32 x y)
|
|
|
|
|
(And16 x (And16 y x)) -> (And16 x y)
|
|
|
|
|
(And8 x (And8 y x)) -> (And8 x y)
|
|
|
|
|
(And64 (And64 x y) x) -> (And64 x y)
|
|
|
|
|
(And32 (And32 x y) x) -> (And32 x y)
|
|
|
|
|
(And16 (And16 x y) x) -> (And16 x y)
|
|
|
|
|
(And8 (And8 x y) x) -> (And8 x y)
|
|
|
|
|
(And64 (And64 x y) y) -> (And64 x y)
|
|
|
|
|
(And32 (And32 x y) y) -> (And32 x y)
|
|
|
|
|
(And16 (And16 x y) y) -> (And16 x y)
|
|
|
|
|
(And8 (And8 x y) y) -> (And8 x y)
|
|
|
|
|
(Or64 x (Or64 x y)) -> (Or64 x y)
|
|
|
|
|
(Or32 x (Or32 x y)) -> (Or32 x y)
|
|
|
|
|
(Or16 x (Or16 x y)) -> (Or16 x y)
|
|
|
|
|
(Or8 x (Or8 x y)) -> (Or8 x y)
|
|
|
|
|
(Or64 x (Or64 y x)) -> (Or64 x y)
|
|
|
|
|
(Or32 x (Or32 y x)) -> (Or32 x y)
|
|
|
|
|
(Or16 x (Or16 y x)) -> (Or16 x y)
|
|
|
|
|
(Or8 x (Or8 y x)) -> (Or8 x y)
|
|
|
|
|
(Or64 (Or64 x y) x) -> (Or64 x y)
|
|
|
|
|
(Or32 (Or32 x y) x) -> (Or32 x y)
|
|
|
|
|
(Or16 (Or16 x y) x) -> (Or16 x y)
|
|
|
|
|
(Or8 (Or8 x y) x) -> (Or8 x y)
|
|
|
|
|
(Or64 (Or64 x y) y) -> (Or64 x y)
|
|
|
|
|
(Or32 (Or32 x y) y) -> (Or32 x y)
|
|
|
|
|
(Or16 (Or16 x y) y) -> (Or16 x y)
|
|
|
|
|
(Or8 (Or8 x y) y) -> (Or8 x y)
|
|
|
|
|
(Xor64 x (Xor64 x y)) -> y
|
|
|
|
|
(Xor32 x (Xor32 x y)) -> y
|
|
|
|
|
(Xor16 x (Xor16 x y)) -> y
|
|
|
|
|
(Xor8 x (Xor8 x y)) -> y
|
|
|
|
|
(Xor64 x (Xor64 y x)) -> y
|
|
|
|
|
(Xor32 x (Xor32 y x)) -> y
|
|
|
|
|
(Xor16 x (Xor16 y x)) -> y
|
|
|
|
|
(Xor8 x (Xor8 y x)) -> y
|
|
|
|
|
(Xor64 (Xor64 x y) x) -> y
|
|
|
|
|
(Xor32 (Xor32 x y) x) -> y
|
|
|
|
|
(Xor16 (Xor16 x y) x) -> y
|
|
|
|
|
(Xor8 (Xor8 x y) x) -> y
|
|
|
|
|
(Xor64 (Xor64 x y) y) -> x
|
|
|
|
|
(Xor32 (Xor32 x y) y) -> x
|
|
|
|
|
(Xor16 (Xor16 x y) y) -> x
|
|
|
|
|
(Xor8 (Xor8 x y) y) -> x
|
|
|
|
|
|
2016-04-26 12:08:31 -07:00
|
|
|
(Trunc64to8 (And64 (Const64 [y]) x)) && y&0xFF == 0xFF -> (Trunc64to8 x)
|
2016-03-02 15:49:55 -05:00
|
|
|
(Trunc64to16 (And64 (Const64 [y]) x)) && y&0xFFFF == 0xFFFF -> (Trunc64to16 x)
|
|
|
|
|
(Trunc64to32 (And64 (Const64 [y]) x)) && y&0xFFFFFFFF == 0xFFFFFFFF -> (Trunc64to32 x)
|
2016-04-26 12:08:31 -07:00
|
|
|
(Trunc32to8 (And32 (Const32 [y]) x)) && y&0xFF == 0xFF -> (Trunc32to8 x)
|
2016-03-02 15:49:55 -05:00
|
|
|
(Trunc32to16 (And32 (Const32 [y]) x)) && y&0xFFFF == 0xFFFF -> (Trunc32to16 x)
|
2016-04-26 12:08:31 -07:00
|
|
|
(Trunc16to8 (And16 (Const16 [y]) x)) && y&0xFF == 0xFF -> (Trunc16to8 x)
|
2016-03-02 15:49:55 -05:00
|
|
|
|
2016-08-30 15:25:20 -07:00
|
|
|
(ZeroExt8to64 (Trunc64to8 x:(Rsh64Ux64 _ (Const64 [s])))) && s >= 56 -> x
|
|
|
|
|
(ZeroExt16to64 (Trunc64to16 x:(Rsh64Ux64 _ (Const64 [s])))) && s >= 48 -> x
|
|
|
|
|
(ZeroExt32to64 (Trunc64to32 x:(Rsh64Ux64 _ (Const64 [s])))) && s >= 32 -> x
|
|
|
|
|
(ZeroExt8to32 (Trunc32to8 x:(Rsh32Ux64 _ (Const64 [s])))) && s >= 24 -> x
|
|
|
|
|
(ZeroExt16to32 (Trunc32to16 x:(Rsh32Ux64 _ (Const64 [s])))) && s >= 16 -> x
|
|
|
|
|
(ZeroExt8to16 (Trunc16to8 x:(Rsh16Ux64 _ (Const64 [s])))) && s >= 8 -> x
|
|
|
|
|
|
|
|
|
|
(SignExt8to64 (Trunc64to8 x:(Rsh64x64 _ (Const64 [s])))) && s >= 56 -> x
|
|
|
|
|
(SignExt16to64 (Trunc64to16 x:(Rsh64x64 _ (Const64 [s])))) && s >= 48 -> x
|
|
|
|
|
(SignExt32to64 (Trunc64to32 x:(Rsh64x64 _ (Const64 [s])))) && s >= 32 -> x
|
|
|
|
|
(SignExt8to32 (Trunc32to8 x:(Rsh32x64 _ (Const64 [s])))) && s >= 24 -> x
|
|
|
|
|
(SignExt16to32 (Trunc32to16 x:(Rsh32x64 _ (Const64 [s])))) && s >= 16 -> x
|
|
|
|
|
(SignExt8to16 (Trunc16to8 x:(Rsh16x64 _ (Const64 [s])))) && s >= 8 -> x
|
|
|
|
|
|
2016-10-25 15:49:52 -07:00
|
|
|
(Slicemask (Const32 [x])) && x > 0 -> (Const32 [-1])
|
|
|
|
|
(Slicemask (Const32 [0])) -> (Const32 [0])
|
|
|
|
|
(Slicemask (Const64 [x])) && x > 0 -> (Const64 [-1])
|
|
|
|
|
(Slicemask (Const64 [0])) -> (Const64 [0])
|
|
|
|
|
|
2016-03-08 15:08:25 -05:00
|
|
|
// Rewrite AND of consts as shifts if possible, slightly faster for 64 bit operands
|
2016-02-11 20:43:15 -06:00
|
|
|
// leading zeros can be shifted left, then right
|
2016-04-26 12:08:31 -07:00
|
|
|
(And64 <t> (Const64 [y]) x) && nlz(y) + nto(y) == 64 && nto(y) >= 32
|
|
|
|
|
-> (Rsh64Ux64 (Lsh64x64 <t> x (Const64 <t> [nlz(y)])) (Const64 <t> [nlz(y)]))
|
2016-02-11 20:43:15 -06:00
|
|
|
// trailing zeros can be shifted right, then left
|
2016-04-26 12:08:31 -07:00
|
|
|
(And64 <t> (Const64 [y]) x) && nlo(y) + ntz(y) == 64 && ntz(y) >= 32
|
|
|
|
|
-> (Lsh64x64 (Rsh64Ux64 <t> x (Const64 <t> [ntz(y)])) (Const64 <t> [ntz(y)]))
|
2016-02-11 20:43:15 -06:00
|
|
|
|
2015-11-09 20:54:34 -08:00
|
|
|
// simplifications often used for lengths. e.g. len(s[i:i+5])==5
|
|
|
|
|
(Sub64 (Add64 x y) x) -> y
|
|
|
|
|
(Sub64 (Add64 x y) y) -> x
|
|
|
|
|
(Sub32 (Add32 x y) x) -> y
|
|
|
|
|
(Sub32 (Add32 x y) y) -> x
|
|
|
|
|
(Sub16 (Add16 x y) x) -> y
|
|
|
|
|
(Sub16 (Add16 x y) y) -> x
|
2016-04-26 12:08:31 -07:00
|
|
|
(Sub8 (Add8 x y) x) -> y
|
|
|
|
|
(Sub8 (Add8 x y) y) -> x
|
2015-11-09 20:54:34 -08:00
|
|
|
|
2016-02-09 19:46:26 +01:00
|
|
|
// basic phi simplifications
|
2016-04-26 12:08:31 -07:00
|
|
|
(Phi (Const8 [c]) (Const8 [c])) -> (Const8 [c])
|
2016-03-29 16:39:53 -07:00
|
|
|
(Phi (Const16 [c]) (Const16 [c])) -> (Const16 [c])
|
|
|
|
|
(Phi (Const32 [c]) (Const32 [c])) -> (Const32 [c])
|
2016-02-09 19:46:26 +01:00
|
|
|
(Phi (Const64 [c]) (Const64 [c])) -> (Const64 [c])
|
|
|
|
|
|
2015-08-30 21:19:20 -05:00
|
|
|
// user nil checks
|
|
|
|
|
(NeqPtr p (ConstNil)) -> (IsNonNil p)
|
|
|
|
|
(NeqPtr (ConstNil) p) -> (IsNonNil p)
|
|
|
|
|
(EqPtr p (ConstNil)) -> (Not (IsNonNil p))
|
|
|
|
|
(EqPtr (ConstNil) p) -> (Not (IsNonNil p))
|
2017-01-20 12:14:22 -05:00
|
|
|
(IsNonNil (ConstNil)) -> (ConstBool [0])
|
2015-08-30 21:19:20 -05:00
|
|
|
|
2015-07-27 13:17:45 -07:00
|
|
|
// slice and interface comparisons
|
2015-09-10 13:53:27 -07:00
|
|
|
// The frontend ensures that we can only compare against nil,
|
|
|
|
|
// so we need only compare the first word (interface type or slice ptr).
|
|
|
|
|
(EqInter x y) -> (EqPtr (ITab x) (ITab y))
|
|
|
|
|
(NeqInter x y) -> (NeqPtr (ITab x) (ITab y))
|
|
|
|
|
(EqSlice x y) -> (EqPtr (SlicePtr x) (SlicePtr y))
|
|
|
|
|
(NeqSlice x y) -> (NeqPtr (SlicePtr x) (SlicePtr y))
|
2015-07-27 13:17:45 -07:00
|
|
|
|
2016-02-13 17:37:19 -06:00
|
|
|
// Load of store of same address, with compatibly typed value and same size
|
|
|
|
|
(Load <t1> p1 (Store [w] p2 x _)) && isSamePtr(p1,p2) && t1.Compare(x.Type)==CMPeq && w == t1.Size() -> x
|
|
|
|
|
|
2016-03-04 14:12:44 -08:00
|
|
|
// Collapse OffPtr
|
|
|
|
|
(OffPtr (OffPtr p [b]) [a]) -> (OffPtr p [a+b])
|
2016-03-18 10:50:00 +01:00
|
|
|
(OffPtr p [0]) && v.Type.Compare(p.Type) == CMPeq -> p
|
2016-03-04 14:12:44 -08:00
|
|
|
|
2015-05-18 16:44:20 -07:00
|
|
|
// indexing operations
|
2015-04-15 15:51:25 -07:00
|
|
|
// Note: bounds check has already been done
|
2016-03-10 14:35:39 -08:00
|
|
|
(PtrIndex <t> ptr idx) && config.PtrSize == 4 -> (AddPtr ptr (Mul32 <config.fe.TypeInt()> idx (Const32 <config.fe.TypeInt()> [t.ElemType().Size()])))
|
|
|
|
|
(PtrIndex <t> ptr idx) && config.PtrSize == 8 -> (AddPtr ptr (Mul64 <config.fe.TypeInt()> idx (Const64 <config.fe.TypeInt()> [t.ElemType().Size()])))
|
2016-01-11 21:05:33 -08:00
|
|
|
|
|
|
|
|
// struct operations
|
|
|
|
|
(StructSelect (StructMake1 x)) -> x
|
|
|
|
|
(StructSelect [0] (StructMake2 x _)) -> x
|
|
|
|
|
(StructSelect [1] (StructMake2 _ x)) -> x
|
|
|
|
|
(StructSelect [0] (StructMake3 x _ _)) -> x
|
|
|
|
|
(StructSelect [1] (StructMake3 _ x _)) -> x
|
|
|
|
|
(StructSelect [2] (StructMake3 _ _ x)) -> x
|
|
|
|
|
(StructSelect [0] (StructMake4 x _ _ _)) -> x
|
|
|
|
|
(StructSelect [1] (StructMake4 _ x _ _)) -> x
|
|
|
|
|
(StructSelect [2] (StructMake4 _ _ x _)) -> x
|
|
|
|
|
(StructSelect [3] (StructMake4 _ _ _ x)) -> x
|
|
|
|
|
|
|
|
|
|
(Load <t> _ _) && t.IsStruct() && t.NumFields() == 0 && config.fe.CanSSA(t) ->
|
|
|
|
|
(StructMake0)
|
|
|
|
|
(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 1 && config.fe.CanSSA(t) ->
|
|
|
|
|
(StructMake1
|
|
|
|
|
(Load <t.FieldType(0)> ptr mem))
|
|
|
|
|
(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 2 && config.fe.CanSSA(t) ->
|
|
|
|
|
(StructMake2
|
|
|
|
|
(Load <t.FieldType(0)> ptr mem)
|
|
|
|
|
(Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem))
|
|
|
|
|
(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 3 && config.fe.CanSSA(t) ->
|
|
|
|
|
(StructMake3
|
|
|
|
|
(Load <t.FieldType(0)> ptr mem)
|
|
|
|
|
(Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem)
|
|
|
|
|
(Load <t.FieldType(2)> (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] ptr) mem))
|
|
|
|
|
(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 4 && config.fe.CanSSA(t) ->
|
|
|
|
|
(StructMake4
|
|
|
|
|
(Load <t.FieldType(0)> ptr mem)
|
|
|
|
|
(Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem)
|
|
|
|
|
(Load <t.FieldType(2)> (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] ptr) mem)
|
|
|
|
|
(Load <t.FieldType(3)> (OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] ptr) mem))
|
|
|
|
|
|
2016-03-21 16:18:45 -07:00
|
|
|
(StructSelect [i] x:(Load <t> ptr mem)) && !config.fe.CanSSA(t) ->
|
|
|
|
|
@x.Block (Load <v.Type> (OffPtr <v.Type.PtrTo()> [t.FieldOff(int(i))] ptr) mem)
|
2016-01-11 21:05:33 -08:00
|
|
|
|
|
|
|
|
(Store _ (StructMake0) mem) -> mem
|
|
|
|
|
(Store dst (StructMake1 <t> f0) mem) ->
|
|
|
|
|
(Store [t.FieldType(0).Size()] dst f0 mem)
|
|
|
|
|
(Store dst (StructMake2 <t> f0 f1) mem) ->
|
|
|
|
|
(Store [t.FieldType(1).Size()]
|
|
|
|
|
(OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
|
|
|
|
|
f1
|
|
|
|
|
(Store [t.FieldType(0).Size()] dst f0 mem))
|
|
|
|
|
(Store dst (StructMake3 <t> f0 f1 f2) mem) ->
|
|
|
|
|
(Store [t.FieldType(2).Size()]
|
|
|
|
|
(OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)
|
|
|
|
|
f2
|
|
|
|
|
(Store [t.FieldType(1).Size()]
|
|
|
|
|
(OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
|
|
|
|
|
f1
|
|
|
|
|
(Store [t.FieldType(0).Size()] dst f0 mem)))
|
|
|
|
|
(Store dst (StructMake4 <t> f0 f1 f2 f3) mem) ->
|
|
|
|
|
(Store [t.FieldType(3).Size()]
|
|
|
|
|
(OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] dst)
|
|
|
|
|
f3
|
|
|
|
|
(Store [t.FieldType(2).Size()]
|
|
|
|
|
(OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)
|
|
|
|
|
f2
|
|
|
|
|
(Store [t.FieldType(1).Size()]
|
|
|
|
|
(OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
|
|
|
|
|
f1
|
|
|
|
|
(Store [t.FieldType(0).Size()] dst f0 mem))))
|
2015-05-18 16:44:20 -07:00
|
|
|
|
2016-10-28 11:37:45 -07:00
|
|
|
// Putting struct{*byte} and similar into direct interfaces.
|
2016-10-30 21:10:03 -07:00
|
|
|
(IMake typ (StructMake1 val)) -> (IMake typ val)
|
2016-10-28 11:37:45 -07:00
|
|
|
(StructSelect [0] x:(IData _)) -> x
|
2016-10-30 21:10:03 -07:00
|
|
|
|
cmd/compile: better job of naming compound types
Compound AUTO types weren't named previously. That was because live
variable analysis (plive.go) doesn't handle spilling to compound types.
It can't handle them because there is no valid place to put VARDEFs when
regalloc is spilling compound types.
compound types = multiword builtin types: complex, string, slice, and
interface.
Instead, we split named AUTOs into individual one-word variables. For
example, a string s gets split into a byte ptr s.ptr and an integer
s.len. Those two variables can be spilled to / restored from
independently. As a result, live variable analysis can handle them
because they are one-word objects.
This CL will change how AUTOs are described in DWARF information.
Consider the code:
func f(s string, i int) int {
x := s[i:i+5]
g()
return lookup(x)
}
The old compiler would spill x to two consecutive slots on the stack,
both named x (at offsets 0 and 8). The new compiler spills the pointer
of x to a slot named x.ptr. It doesn't spill x.len at all, as it is a
constant (5) and can be rematerialized for the call to lookup.
So compound objects may not be spilled in their entirety, and even if
they are they won't necessarily be contiguous. Such is the price of
optimization.
Re-enable live variable analysis tests. One test remains disabled, it
fails because of #14904.
Change-Id: I8ef2b5ab91e43a0d2136bfc231c05d100ec0b801
Reviewed-on: https://go-review.googlesource.com/21233
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2016-03-28 11:25:17 -07:00
|
|
|
// un-SSAable values use mem->mem copies
|
2016-06-27 16:54:57 -04:00
|
|
|
(Store [size] dst (Load <t> src mem) mem) && !config.fe.CanSSA(t) ->
|
|
|
|
|
(Move [MakeSizeAndAlign(size, t.Alignment()).Int64()] dst src mem)
|
|
|
|
|
(Store [size] dst (Load <t> src mem) (VarDef {x} mem)) && !config.fe.CanSSA(t) ->
|
|
|
|
|
(Move [MakeSizeAndAlign(size, t.Alignment()).Int64()] dst src (VarDef {x} mem))
|
2015-08-28 14:24:10 -04:00
|
|
|
|
2016-10-30 21:10:03 -07:00
|
|
|
// array ops
|
|
|
|
|
(ArraySelect (ArrayMake1 x)) -> x
|
|
|
|
|
|
|
|
|
|
(Load <t> _ _) && t.IsArray() && t.NumElem() == 0 ->
|
|
|
|
|
(ArrayMake0)
|
|
|
|
|
|
|
|
|
|
(Load <t> ptr mem) && t.IsArray() && t.NumElem() == 1 && config.fe.CanSSA(t) ->
|
|
|
|
|
(ArrayMake1 (Load <t.ElemType()> ptr mem))
|
|
|
|
|
|
|
|
|
|
(Store _ (ArrayMake0) mem) -> mem
|
|
|
|
|
(Store [size] dst (ArrayMake1 e) mem) -> (Store [size] dst e mem)
|
|
|
|
|
|
|
|
|
|
(ArraySelect [0] (Load ptr mem)) -> (Load ptr mem)
|
|
|
|
|
|
2016-10-28 11:37:45 -07:00
|
|
|
// Putting [1]{*byte} and similar into direct interfaces.
|
2016-10-30 21:10:03 -07:00
|
|
|
(IMake typ (ArrayMake1 val)) -> (IMake typ val)
|
2016-10-28 11:37:45 -07:00
|
|
|
(ArraySelect [0] x:(IData _)) -> x
|
2016-10-30 21:10:03 -07:00
|
|
|
|
2015-05-27 14:52:22 -07:00
|
|
|
// string ops
|
2016-03-14 19:11:19 +01:00
|
|
|
// Decomposing StringMake and lowering of StringPtr and StringLen
|
|
|
|
|
// happens in a later pass, dec, so that these operations are available
|
cmd/compile: better job of naming compound types
Compound AUTO types weren't named previously. That was because live
variable analysis (plive.go) doesn't handle spilling to compound types.
It can't handle them because there is no valid place to put VARDEFs when
regalloc is spilling compound types.
compound types = multiword builtin types: complex, string, slice, and
interface.
Instead, we split named AUTOs into individual one-word variables. For
example, a string s gets split into a byte ptr s.ptr and an integer
s.len. Those two variables can be spilled to / restored from
independently. As a result, live variable analysis can handle them
because they are one-word objects.
This CL will change how AUTOs are described in DWARF information.
Consider the code:
func f(s string, i int) int {
x := s[i:i+5]
g()
return lookup(x)
}
The old compiler would spill x to two consecutive slots on the stack,
both named x (at offsets 0 and 8). The new compiler spills the pointer
of x to a slot named x.ptr. It doesn't spill x.len at all, as it is a
constant (5) and can be rematerialized for the call to lookup.
So compound objects may not be spilled in their entirety, and even if
they are they won't necessarily be contiguous. Such is the price of
optimization.
Re-enable live variable analysis tests. One test remains disabled, it
fails because of #14904.
Change-Id: I8ef2b5ab91e43a0d2136bfc231c05d100ec0b801
Reviewed-on: https://go-review.googlesource.com/21233
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2016-03-28 11:25:17 -07:00
|
|
|
// to other passes for optimizations.
|
2016-03-03 11:13:43 +01:00
|
|
|
(StringPtr (StringMake (Const64 <t> [c]) _)) -> (Const64 <t> [c])
|
|
|
|
|
(StringLen (StringMake _ (Const64 <t> [c]))) -> (Const64 <t> [c])
|
2015-11-09 20:54:34 -08:00
|
|
|
(ConstString {s}) && config.PtrSize == 4 && s.(string) == "" ->
|
|
|
|
|
(StringMake (ConstNil) (Const32 <config.fe.TypeInt()> [0]))
|
|
|
|
|
(ConstString {s}) && config.PtrSize == 8 && s.(string) == "" ->
|
|
|
|
|
(StringMake (ConstNil) (Const64 <config.fe.TypeInt()> [0]))
|
|
|
|
|
(ConstString {s}) && config.PtrSize == 4 && s.(string) != "" ->
|
2015-11-02 21:28:13 -08:00
|
|
|
(StringMake
|
|
|
|
|
(Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))}
|
|
|
|
|
(SB))
|
|
|
|
|
(Const32 <config.fe.TypeInt()> [int64(len(s.(string)))]))
|
2015-11-09 20:54:34 -08:00
|
|
|
(ConstString {s}) && config.PtrSize == 8 && s.(string) != "" ->
|
2015-08-18 10:26:28 -07:00
|
|
|
(StringMake
|
|
|
|
|
(Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))}
|
2015-09-01 09:16:58 -07:00
|
|
|
(SB))
|
2015-11-02 21:28:13 -08:00
|
|
|
(Const64 <config.fe.TypeInt()> [int64(len(s.(string)))]))
|
2015-08-18 10:26:28 -07:00
|
|
|
|
|
|
|
|
// slice ops
|
cmd/compile: better job of naming compound types
Compound AUTO types weren't named previously. That was because live
variable analysis (plive.go) doesn't handle spilling to compound types.
It can't handle them because there is no valid place to put VARDEFs when
regalloc is spilling compound types.
compound types = multiword builtin types: complex, string, slice, and
interface.
Instead, we split named AUTOs into individual one-word variables. For
example, a string s gets split into a byte ptr s.ptr and an integer
s.len. Those two variables can be spilled to / restored from
independently. As a result, live variable analysis can handle them
because they are one-word objects.
This CL will change how AUTOs are described in DWARF information.
Consider the code:
func f(s string, i int) int {
x := s[i:i+5]
g()
return lookup(x)
}
The old compiler would spill x to two consecutive slots on the stack,
both named x (at offsets 0 and 8). The new compiler spills the pointer
of x to a slot named x.ptr. It doesn't spill x.len at all, as it is a
constant (5) and can be rematerialized for the call to lookup.
So compound objects may not be spilled in their entirety, and even if
they are they won't necessarily be contiguous. Such is the price of
optimization.
Re-enable live variable analysis tests. One test remains disabled, it
fails because of #14904.
Change-Id: I8ef2b5ab91e43a0d2136bfc231c05d100ec0b801
Reviewed-on: https://go-review.googlesource.com/21233
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2016-03-28 11:25:17 -07:00
|
|
|
// Only a few slice rules are provided here. See dec.rules for
|
|
|
|
|
// a more comprehensive set.
|
2016-03-03 11:13:43 +01:00
|
|
|
(SliceLen (SliceMake _ (Const64 <t> [c]) _)) -> (Const64 <t> [c])
|
|
|
|
|
(SliceCap (SliceMake _ _ (Const64 <t> [c]))) -> (Const64 <t> [c])
|
2016-10-19 11:47:52 -04:00
|
|
|
(SliceLen (SliceMake _ (Const32 <t> [c]) _)) -> (Const32 <t> [c])
|
|
|
|
|
(SliceCap (SliceMake _ _ (Const32 <t> [c]))) -> (Const32 <t> [c])
|
2016-03-07 18:36:16 +01:00
|
|
|
(SlicePtr (SliceMake (SlicePtr x) _ _)) -> (SlicePtr x)
|
|
|
|
|
(SliceLen (SliceMake _ (SliceLen x) _)) -> (SliceLen x)
|
|
|
|
|
(SliceCap (SliceMake _ _ (SliceCap x))) -> (SliceCap x)
|
2016-03-22 17:34:36 +01:00
|
|
|
(SliceCap (SliceMake _ _ (SliceLen x))) -> (SliceLen x)
|
2015-11-02 21:28:13 -08:00
|
|
|
(ConstSlice) && config.PtrSize == 4 ->
|
|
|
|
|
(SliceMake
|
cmd/compile: better job of naming compound types
Compound AUTO types weren't named previously. That was because live
variable analysis (plive.go) doesn't handle spilling to compound types.
It can't handle them because there is no valid place to put VARDEFs when
regalloc is spilling compound types.
compound types = multiword builtin types: complex, string, slice, and
interface.
Instead, we split named AUTOs into individual one-word variables. For
example, a string s gets split into a byte ptr s.ptr and an integer
s.len. Those two variables can be spilled to / restored from
independently. As a result, live variable analysis can handle them
because they are one-word objects.
This CL will change how AUTOs are described in DWARF information.
Consider the code:
func f(s string, i int) int {
x := s[i:i+5]
g()
return lookup(x)
}
The old compiler would spill x to two consecutive slots on the stack,
both named x (at offsets 0 and 8). The new compiler spills the pointer
of x to a slot named x.ptr. It doesn't spill x.len at all, as it is a
constant (5) and can be rematerialized for the call to lookup.
So compound objects may not be spilled in their entirety, and even if
they are they won't necessarily be contiguous. Such is the price of
optimization.
Re-enable live variable analysis tests. One test remains disabled, it
fails because of #14904.
Change-Id: I8ef2b5ab91e43a0d2136bfc231c05d100ec0b801
Reviewed-on: https://go-review.googlesource.com/21233
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2016-03-28 11:25:17 -07:00
|
|
|
(ConstNil <v.Type.ElemType().PtrTo()>)
|
2015-11-02 21:28:13 -08:00
|
|
|
(Const32 <config.fe.TypeInt()> [0])
|
|
|
|
|
(Const32 <config.fe.TypeInt()> [0]))
|
|
|
|
|
(ConstSlice) && config.PtrSize == 8 ->
|
2015-08-18 10:26:28 -07:00
|
|
|
(SliceMake
|
cmd/compile: better job of naming compound types
Compound AUTO types weren't named previously. That was because live
variable analysis (plive.go) doesn't handle spilling to compound types.
It can't handle them because there is no valid place to put VARDEFs when
regalloc is spilling compound types.
compound types = multiword builtin types: complex, string, slice, and
interface.
Instead, we split named AUTOs into individual one-word variables. For
example, a string s gets split into a byte ptr s.ptr and an integer
s.len. Those two variables can be spilled to / restored from
independently. As a result, live variable analysis can handle them
because they are one-word objects.
This CL will change how AUTOs are described in DWARF information.
Consider the code:
func f(s string, i int) int {
x := s[i:i+5]
g()
return lookup(x)
}
The old compiler would spill x to two consecutive slots on the stack,
both named x (at offsets 0 and 8). The new compiler spills the pointer
of x to a slot named x.ptr. It doesn't spill x.len at all, as it is a
constant (5) and can be rematerialized for the call to lookup.
So compound objects may not be spilled in their entirety, and even if
they are they won't necessarily be contiguous. Such is the price of
optimization.
Re-enable live variable analysis tests. One test remains disabled, it
fails because of #14904.
Change-Id: I8ef2b5ab91e43a0d2136bfc231c05d100ec0b801
Reviewed-on: https://go-review.googlesource.com/21233
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2016-03-28 11:25:17 -07:00
|
|
|
(ConstNil <v.Type.ElemType().PtrTo()>)
|
2015-11-02 21:28:13 -08:00
|
|
|
(Const64 <config.fe.TypeInt()> [0])
|
|
|
|
|
(Const64 <config.fe.TypeInt()> [0]))
|
2015-08-18 10:26:28 -07:00
|
|
|
|
|
|
|
|
// interface ops
|
|
|
|
|
(ConstInterface) ->
|
|
|
|
|
(IMake
|
|
|
|
|
(ConstNil <config.fe.TypeBytePtr()>)
|
|
|
|
|
(ConstNil <config.fe.TypeBytePtr()>))
|
2015-06-06 16:03:33 -07:00
|
|
|
|
2016-09-13 17:01:01 -07:00
|
|
|
(NilCheck (GetG mem) mem) -> mem
|
2015-08-12 11:22:16 -07:00
|
|
|
|
2015-07-23 18:44:09 -05:00
|
|
|
(If (Not cond) yes no) -> (If cond no yes)
|
2015-09-03 18:24:22 -05:00
|
|
|
(If (ConstBool [c]) yes no) && c == 1 -> (First nil yes no)
|
|
|
|
|
(If (ConstBool [c]) yes no) && c == 0 -> (First nil no yes)
|
2015-10-23 14:08:50 -07:00
|
|
|
|
|
|
|
|
// Get rid of Convert ops for pointer arithmetic on unsafe.Pointer.
|
2015-11-10 15:35:36 -08:00
|
|
|
(Convert (Add64 (Convert ptr mem) off) mem) -> (Add64 ptr off)
|
2016-02-23 21:48:33 +01:00
|
|
|
(Convert (Add64 off (Convert ptr mem)) mem) -> (Add64 ptr off)
|
2015-11-10 15:35:36 -08:00
|
|
|
(Convert (Convert ptr mem) mem) -> ptr
|
2015-11-02 08:10:26 -08:00
|
|
|
|
|
|
|
|
// Decompose compound argument values
|
|
|
|
|
(Arg {n} [off]) && v.Type.IsString() ->
|
|
|
|
|
(StringMake
|
|
|
|
|
(Arg <config.fe.TypeBytePtr()> {n} [off])
|
|
|
|
|
(Arg <config.fe.TypeInt()> {n} [off+config.PtrSize]))
|
|
|
|
|
|
|
|
|
|
(Arg {n} [off]) && v.Type.IsSlice() ->
|
|
|
|
|
(SliceMake
|
cmd/compile: better job of naming compound types
Compound AUTO types weren't named previously. That was because live
variable analysis (plive.go) doesn't handle spilling to compound types.
It can't handle them because there is no valid place to put VARDEFs when
regalloc is spilling compound types.
compound types = multiword builtin types: complex, string, slice, and
interface.
Instead, we split named AUTOs into individual one-word variables. For
example, a string s gets split into a byte ptr s.ptr and an integer
s.len. Those two variables can be spilled to / restored from
independently. As a result, live variable analysis can handle them
because they are one-word objects.
This CL will change how AUTOs are described in DWARF information.
Consider the code:
func f(s string, i int) int {
x := s[i:i+5]
g()
return lookup(x)
}
The old compiler would spill x to two consecutive slots on the stack,
both named x (at offsets 0 and 8). The new compiler spills the pointer
of x to a slot named x.ptr. It doesn't spill x.len at all, as it is a
constant (5) and can be rematerialized for the call to lookup.
So compound objects may not be spilled in their entirety, and even if
they are they won't necessarily be contiguous. Such is the price of
optimization.
Re-enable live variable analysis tests. One test remains disabled, it
fails because of #14904.
Change-Id: I8ef2b5ab91e43a0d2136bfc231c05d100ec0b801
Reviewed-on: https://go-review.googlesource.com/21233
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2016-03-28 11:25:17 -07:00
|
|
|
(Arg <v.Type.ElemType().PtrTo()> {n} [off])
|
2015-11-02 08:10:26 -08:00
|
|
|
(Arg <config.fe.TypeInt()> {n} [off+config.PtrSize])
|
|
|
|
|
(Arg <config.fe.TypeInt()> {n} [off+2*config.PtrSize]))
|
|
|
|
|
|
|
|
|
|
(Arg {n} [off]) && v.Type.IsInterface() ->
|
|
|
|
|
(IMake
|
|
|
|
|
(Arg <config.fe.TypeBytePtr()> {n} [off])
|
|
|
|
|
(Arg <config.fe.TypeBytePtr()> {n} [off+config.PtrSize]))
|
|
|
|
|
|
|
|
|
|
(Arg {n} [off]) && v.Type.IsComplex() && v.Type.Size() == 16 ->
|
|
|
|
|
(ComplexMake
|
|
|
|
|
(Arg <config.fe.TypeFloat64()> {n} [off])
|
|
|
|
|
(Arg <config.fe.TypeFloat64()> {n} [off+8]))
|
|
|
|
|
|
|
|
|
|
(Arg {n} [off]) && v.Type.IsComplex() && v.Type.Size() == 8 ->
|
|
|
|
|
(ComplexMake
|
|
|
|
|
(Arg <config.fe.TypeFloat32()> {n} [off])
|
|
|
|
|
(Arg <config.fe.TypeFloat32()> {n} [off+4]))
|
2016-01-11 21:05:33 -08:00
|
|
|
|
|
|
|
|
(Arg <t>) && t.IsStruct() && t.NumFields() == 0 && config.fe.CanSSA(t) ->
|
|
|
|
|
(StructMake0)
|
|
|
|
|
(Arg <t> {n} [off]) && t.IsStruct() && t.NumFields() == 1 && config.fe.CanSSA(t) ->
|
|
|
|
|
(StructMake1
|
|
|
|
|
(Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)]))
|
|
|
|
|
(Arg <t> {n} [off]) && t.IsStruct() && t.NumFields() == 2 && config.fe.CanSSA(t) ->
|
|
|
|
|
(StructMake2
|
|
|
|
|
(Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)])
|
|
|
|
|
(Arg <t.FieldType(1)> {n} [off+t.FieldOff(1)]))
|
|
|
|
|
(Arg <t> {n} [off]) && t.IsStruct() && t.NumFields() == 3 && config.fe.CanSSA(t) ->
|
|
|
|
|
(StructMake3
|
|
|
|
|
(Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)])
|
|
|
|
|
(Arg <t.FieldType(1)> {n} [off+t.FieldOff(1)])
|
|
|
|
|
(Arg <t.FieldType(2)> {n} [off+t.FieldOff(2)]))
|
|
|
|
|
(Arg <t> {n} [off]) && t.IsStruct() && t.NumFields() == 4 && config.fe.CanSSA(t) ->
|
|
|
|
|
(StructMake4
|
|
|
|
|
(Arg <t.FieldType(0)> {n} [off+t.FieldOff(0)])
|
|
|
|
|
(Arg <t.FieldType(1)> {n} [off+t.FieldOff(1)])
|
|
|
|
|
(Arg <t.FieldType(2)> {n} [off+t.FieldOff(2)])
|
|
|
|
|
(Arg <t.FieldType(3)> {n} [off+t.FieldOff(3)]))
|
2016-02-05 20:26:18 -08:00
|
|
|
|
2016-10-30 21:10:03 -07:00
|
|
|
(Arg <t>) && t.IsArray() && t.NumElem() == 0 ->
|
|
|
|
|
(ArrayMake0)
|
|
|
|
|
(Arg <t> {n} [off]) && t.IsArray() && t.NumElem() == 1 && config.fe.CanSSA(t) ->
|
|
|
|
|
(ArrayMake1 (Arg <t.ElemType()> {n} [off]))
|
|
|
|
|
|
2016-02-05 20:26:18 -08:00
|
|
|
// strength reduction of divide by a constant.
|
2017-02-13 16:00:09 -08:00
|
|
|
// See ../magic.go for a detailed description of these algorithms.
|
2016-02-05 20:26:18 -08:00
|
|
|
|
2017-02-13 16:00:09 -08:00
|
|
|
// Unsigned divide by power of 2. Strength reduce to a shift.
|
|
|
|
|
(Div8u n (Const8 [c])) && isPowerOfTwo(c&0xff) -> (Rsh8Ux64 n (Const64 <config.fe.TypeUInt64()> [log2(c&0xff)]))
|
|
|
|
|
(Div16u n (Const16 [c])) && isPowerOfTwo(c&0xffff) -> (Rsh16Ux64 n (Const64 <config.fe.TypeUInt64()> [log2(c&0xffff)]))
|
|
|
|
|
(Div32u n (Const32 [c])) && isPowerOfTwo(c&0xffffffff) -> (Rsh32Ux64 n (Const64 <config.fe.TypeUInt64()> [log2(c&0xffffffff)]))
|
|
|
|
|
(Div64u n (Const64 [c])) && isPowerOfTwo(c) -> (Rsh64Ux64 n (Const64 <config.fe.TypeUInt64()> [log2(c)]))
|
2016-02-05 20:26:18 -08:00
|
|
|
|
|
|
|
|
// Unsigned divide, not a power of 2. Strength reduce to a multiply.
|
2017-02-13 16:00:09 -08:00
|
|
|
// For 8-bit divides, we just do a direct 9-bit by 8-bit multiply.
|
|
|
|
|
(Div8u x (Const8 [c])) && umagicOK(8, c) ->
|
|
|
|
|
(Trunc32to8
|
|
|
|
|
(Rsh32Ux64 <config.fe.TypeUInt32()>
|
|
|
|
|
(Mul32 <config.fe.TypeUInt32()>
|
|
|
|
|
(Const32 <config.fe.TypeUInt32()> [int64(1<<8+umagic(8,c).m)])
|
|
|
|
|
(ZeroExt8to32 x))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [8+umagic(8,c).s])))
|
|
|
|
|
|
|
|
|
|
// For 16-bit divides on 64-bit machines, we do a direct 17-bit by 16-bit multiply.
|
|
|
|
|
(Div16u x (Const16 [c])) && umagicOK(16, c) && config.RegSize == 8 ->
|
|
|
|
|
(Trunc64to16
|
|
|
|
|
(Rsh64Ux64 <config.fe.TypeUInt64()>
|
|
|
|
|
(Mul64 <config.fe.TypeUInt64()>
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [int64(1<<16+umagic(16,c).m)])
|
|
|
|
|
(ZeroExt16to64 x))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [16+umagic(16,c).s])))
|
|
|
|
|
|
|
|
|
|
// For 16-bit divides on 32-bit machines
|
|
|
|
|
(Div16u x (Const16 [c])) && umagicOK(16, c) && config.RegSize == 4 && umagic(16,c).m&1 == 0 ->
|
|
|
|
|
(Trunc32to16
|
|
|
|
|
(Rsh32Ux64 <config.fe.TypeUInt32()>
|
|
|
|
|
(Mul32 <config.fe.TypeUInt32()>
|
|
|
|
|
(Const32 <config.fe.TypeUInt32()> [int64(1<<15+umagic(16,c).m/2)])
|
|
|
|
|
(ZeroExt16to32 x))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [16+umagic(16,c).s-1])))
|
|
|
|
|
(Div16u x (Const16 [c])) && umagicOK(16, c) && config.RegSize == 4 && c&1 == 0 ->
|
|
|
|
|
(Trunc32to16
|
|
|
|
|
(Rsh32Ux64 <config.fe.TypeUInt32()>
|
|
|
|
|
(Mul32 <config.fe.TypeUInt32()>
|
|
|
|
|
(Const32 <config.fe.TypeUInt32()> [int64(1<<15+(umagic(16,c).m+1)/2)])
|
|
|
|
|
(Rsh32Ux64 <config.fe.TypeUInt32()> (ZeroExt16to32 x) (Const64 <config.fe.TypeUInt64()> [1])))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [16+umagic(16,c).s-2])))
|
|
|
|
|
(Div16u x (Const16 [c])) && umagicOK(16, c) && config.RegSize == 4 ->
|
|
|
|
|
(Trunc32to16
|
|
|
|
|
(Rsh32Ux64 <config.fe.TypeUInt32()>
|
|
|
|
|
(Avg32u
|
|
|
|
|
(Lsh32x64 <config.fe.TypeUInt32()> (ZeroExt16to32 x) (Const64 <config.fe.TypeUInt64()> [16]))
|
|
|
|
|
(Mul32 <config.fe.TypeUInt32()>
|
|
|
|
|
(Const32 <config.fe.TypeUInt32()> [int64(umagic(16,c).m)])
|
|
|
|
|
(ZeroExt16to32 x)))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [16+umagic(16,c).s-1])))
|
|
|
|
|
|
|
|
|
|
// For 32-bit divides on 32-bit machines
|
|
|
|
|
(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 4 && umagic(32,c).m&1 == 0 ->
|
|
|
|
|
(Rsh32Ux64 <config.fe.TypeUInt32()>
|
|
|
|
|
(Hmul32u <config.fe.TypeUInt32()>
|
|
|
|
|
(Const32 <config.fe.TypeUInt32()> [int64(int32(1<<31+umagic(32,c).m/2))])
|
2016-02-05 20:26:18 -08:00
|
|
|
x)
|
2017-02-13 16:00:09 -08:00
|
|
|
(Const64 <config.fe.TypeUInt64()> [umagic(32,c).s-1]))
|
|
|
|
|
(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 4 && c&1 == 0 ->
|
|
|
|
|
(Rsh32Ux64 <config.fe.TypeUInt32()>
|
|
|
|
|
(Hmul32u <config.fe.TypeUInt32()>
|
|
|
|
|
(Const32 <config.fe.TypeUInt32()> [int64(int32(1<<31+(umagic(32,c).m+1)/2))])
|
|
|
|
|
(Rsh32Ux64 <config.fe.TypeUInt32()> x (Const64 <config.fe.TypeUInt64()> [1])))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [umagic(32,c).s-2]))
|
|
|
|
|
(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 4 ->
|
|
|
|
|
(Rsh32Ux64 <config.fe.TypeUInt32()>
|
|
|
|
|
(Avg32u
|
|
|
|
|
x
|
|
|
|
|
(Hmul32u <config.fe.TypeUInt32()>
|
|
|
|
|
(Const32 <config.fe.TypeUInt32()> [int64(int32(umagic(32,c).m))])
|
|
|
|
|
x))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [umagic(32,c).s-1]))
|
|
|
|
|
|
|
|
|
|
// For 32-bit divides on 64-bit machines
|
|
|
|
|
// We'll use a regular (non-hi) multiply for this case.
|
|
|
|
|
(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 8 && umagic(32,c).m&1 == 0 ->
|
|
|
|
|
(Trunc64to32
|
|
|
|
|
(Rsh64Ux64 <config.fe.TypeUInt64()>
|
|
|
|
|
(Mul64 <config.fe.TypeUInt64()>
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [int64(1<<31+umagic(32,c).m/2)])
|
|
|
|
|
(ZeroExt32to64 x))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [32+umagic(32,c).s-1])))
|
|
|
|
|
(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 8 && c&1 == 0 ->
|
|
|
|
|
(Trunc64to32
|
|
|
|
|
(Rsh64Ux64 <config.fe.TypeUInt64()>
|
|
|
|
|
(Mul64 <config.fe.TypeUInt64()>
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [int64(1<<31+(umagic(32,c).m+1)/2)])
|
|
|
|
|
(Rsh64Ux64 <config.fe.TypeUInt64()> (ZeroExt32to64 x) (Const64 <config.fe.TypeUInt64()> [1])))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [32+umagic(32,c).s-2])))
|
|
|
|
|
(Div32u x (Const32 [c])) && umagicOK(32, c) && config.RegSize == 8 ->
|
|
|
|
|
(Trunc64to32
|
|
|
|
|
(Rsh64Ux64 <config.fe.TypeUInt64()>
|
|
|
|
|
(Avg64u
|
|
|
|
|
(Lsh64x64 <config.fe.TypeUInt64()> (ZeroExt32to64 x) (Const64 <config.fe.TypeUInt64()> [32]))
|
2017-02-17 11:36:08 -08:00
|
|
|
(Mul64 <config.fe.TypeUInt64()>
|
2017-02-13 16:00:09 -08:00
|
|
|
(Const64 <config.fe.TypeUInt32()> [int64(umagic(32,c).m)])
|
|
|
|
|
(ZeroExt32to64 x)))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [32+umagic(32,c).s-1])))
|
|
|
|
|
|
|
|
|
|
// For 64-bit divides on 64-bit machines
|
|
|
|
|
// (64-bit divides on 32-bit machines are lowered to a runtime call by the walk pass.)
|
|
|
|
|
(Div64u x (Const64 [c])) && umagicOK(64, c) && config.RegSize == 8 && umagic(64,c).m&1 == 0 ->
|
|
|
|
|
(Rsh64Ux64 <config.fe.TypeUInt64()>
|
|
|
|
|
(Hmul64u <config.fe.TypeUInt64()>
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [int64(1<<63+umagic(64,c).m/2)])
|
2016-02-05 20:26:18 -08:00
|
|
|
x)
|
2017-02-13 16:00:09 -08:00
|
|
|
(Const64 <config.fe.TypeUInt64()> [umagic(64,c).s-1]))
|
|
|
|
|
(Div64u x (Const64 [c])) && umagicOK(64, c) && config.RegSize == 8 && c&1 == 0 ->
|
|
|
|
|
(Rsh64Ux64 <config.fe.TypeUInt64()>
|
|
|
|
|
(Hmul64u <config.fe.TypeUInt64()>
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [int64(1<<63+(umagic(64,c).m+1)/2)])
|
|
|
|
|
(Rsh64Ux64 <config.fe.TypeUInt64()> x (Const64 <config.fe.TypeUInt64()> [1])))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [umagic(64,c).s-2]))
|
|
|
|
|
(Div64u x (Const64 [c])) && umagicOK(64, c) && config.RegSize == 8 ->
|
|
|
|
|
(Rsh64Ux64 <config.fe.TypeUInt64()>
|
|
|
|
|
(Avg64u
|
|
|
|
|
x
|
|
|
|
|
(Hmul64u <config.fe.TypeUInt64()>
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [int64(umagic(64,c).m)])
|
|
|
|
|
x))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [umagic(64,c).s-1]))
|
|
|
|
|
|
|
|
|
|
// Signed divide by a negative constant. Rewrite to divide by a positive constant.
|
|
|
|
|
(Div8 <t> n (Const8 [c])) && c < 0 && c != -1<<7 -> (Neg8 (Div8 <t> n (Const8 <t> [-c])))
|
|
|
|
|
(Div16 <t> n (Const16 [c])) && c < 0 && c != -1<<15 -> (Neg16 (Div16 <t> n (Const16 <t> [-c])))
|
|
|
|
|
(Div32 <t> n (Const32 [c])) && c < 0 && c != -1<<31 -> (Neg32 (Div32 <t> n (Const32 <t> [-c])))
|
|
|
|
|
(Div64 <t> n (Const64 [c])) && c < 0 && c != -1<<63 -> (Neg64 (Div64 <t> n (Const64 <t> [-c])))
|
|
|
|
|
|
|
|
|
|
// Dividing by the most-negative number. Result is always 0 except
|
|
|
|
|
// if the input is also the most-negative number.
|
|
|
|
|
// We can detect that using the sign bit of x & -x.
|
|
|
|
|
(Div8 <t> x (Const8 [-1<<7 ])) -> (Rsh8Ux64 (And8 <t> x (Neg8 <t> x)) (Const64 <config.fe.TypeUInt64()> [7 ]))
|
|
|
|
|
(Div16 <t> x (Const16 [-1<<15])) -> (Rsh16Ux64 (And16 <t> x (Neg16 <t> x)) (Const64 <config.fe.TypeUInt64()> [15]))
|
|
|
|
|
(Div32 <t> x (Const32 [-1<<31])) -> (Rsh32Ux64 (And32 <t> x (Neg32 <t> x)) (Const64 <config.fe.TypeUInt64()> [31]))
|
|
|
|
|
(Div64 <t> x (Const64 [-1<<63])) -> (Rsh64Ux64 (And64 <t> x (Neg64 <t> x)) (Const64 <config.fe.TypeUInt64()> [63]))
|
|
|
|
|
|
|
|
|
|
// Signed divide by power of 2.
|
|
|
|
|
// n / c = n >> log(c) if n >= 0
|
|
|
|
|
// = (n+c-1) >> log(c) if n < 0
|
|
|
|
|
// We conditionally add c-1 by adding n>>63>>(64-log(c)) (first shift signed, second shift unsigned).
|
|
|
|
|
(Div8 <t> n (Const8 [c])) && isPowerOfTwo(c) ->
|
|
|
|
|
(Rsh8x64
|
|
|
|
|
(Add8 <t> n (Rsh8Ux64 <t> (Rsh8x64 <t> n (Const64 <config.fe.TypeUInt64()> [ 7])) (Const64 <config.fe.TypeUInt64()> [ 8-log2(c)])))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [log2(c)]))
|
|
|
|
|
(Div16 <t> n (Const16 [c])) && isPowerOfTwo(c) ->
|
|
|
|
|
(Rsh16x64
|
|
|
|
|
(Add16 <t> n (Rsh16Ux64 <t> (Rsh16x64 <t> n (Const64 <config.fe.TypeUInt64()> [15])) (Const64 <config.fe.TypeUInt64()> [16-log2(c)])))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [log2(c)]))
|
|
|
|
|
(Div32 <t> n (Const32 [c])) && isPowerOfTwo(c) ->
|
|
|
|
|
(Rsh32x64
|
|
|
|
|
(Add32 <t> n (Rsh32Ux64 <t> (Rsh32x64 <t> n (Const64 <config.fe.TypeUInt64()> [31])) (Const64 <config.fe.TypeUInt64()> [32-log2(c)])))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [log2(c)]))
|
|
|
|
|
(Div64 <t> n (Const64 [c])) && isPowerOfTwo(c) ->
|
|
|
|
|
(Rsh64x64
|
|
|
|
|
(Add64 <t> n (Rsh64Ux64 <t> (Rsh64x64 <t> n (Const64 <config.fe.TypeUInt64()> [63])) (Const64 <config.fe.TypeUInt64()> [64-log2(c)])))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [log2(c)]))
|
2016-02-05 20:26:18 -08:00
|
|
|
|
|
|
|
|
// Signed divide, not a power of 2. Strength reduce to a multiply.
|
2017-02-13 16:00:09 -08:00
|
|
|
(Div8 <t> x (Const8 [c])) && smagicOK(8,c) ->
|
|
|
|
|
(Sub8 <t>
|
|
|
|
|
(Rsh32x64 <t>
|
|
|
|
|
(Mul32 <config.fe.TypeUInt32()>
|
|
|
|
|
(Const32 <config.fe.TypeUInt32()> [int64(smagic(8,c).m)])
|
|
|
|
|
(SignExt8to32 x))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [8+smagic(8,c).s]))
|
|
|
|
|
(Rsh32x64 <t>
|
|
|
|
|
(SignExt8to32 x)
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [31])))
|
|
|
|
|
(Div16 <t> x (Const16 [c])) && smagicOK(16,c) ->
|
|
|
|
|
(Sub16 <t>
|
|
|
|
|
(Rsh32x64 <t>
|
|
|
|
|
(Mul32 <config.fe.TypeUInt32()>
|
|
|
|
|
(Const32 <config.fe.TypeUInt32()> [int64(smagic(16,c).m)])
|
|
|
|
|
(SignExt16to32 x))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [16+smagic(16,c).s]))
|
|
|
|
|
(Rsh32x64 <t>
|
|
|
|
|
(SignExt16to32 x)
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [31])))
|
|
|
|
|
(Div32 <t> x (Const32 [c])) && smagicOK(32,c) && config.RegSize == 8 ->
|
|
|
|
|
(Sub32 <t>
|
|
|
|
|
(Rsh64x64 <t>
|
|
|
|
|
(Mul64 <config.fe.TypeUInt64()>
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [int64(smagic(32,c).m)])
|
|
|
|
|
(SignExt32to64 x))
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [32+smagic(32,c).s]))
|
|
|
|
|
(Rsh64x64 <t>
|
|
|
|
|
(SignExt32to64 x)
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [63])))
|
|
|
|
|
(Div32 <t> x (Const32 [c])) && smagicOK(32,c) && config.RegSize == 4 && smagic(32,c).m&1 == 0 ->
|
|
|
|
|
(Sub32 <t>
|
|
|
|
|
(Rsh32x64 <t>
|
|
|
|
|
(Hmul32 <t>
|
|
|
|
|
(Const32 <config.fe.TypeUInt32()> [int64(int32(smagic(32,c).m/2))])
|
|
|
|
|
x)
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [smagic(32,c).s-1]))
|
|
|
|
|
(Rsh32x64 <t>
|
|
|
|
|
x
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [31])))
|
|
|
|
|
(Div32 <t> x (Const32 [c])) && smagicOK(32,c) && config.RegSize == 4 && smagic(32,c).m&1 != 0 ->
|
|
|
|
|
(Sub32 <t>
|
|
|
|
|
(Rsh32x64 <t>
|
|
|
|
|
(Add32 <t>
|
|
|
|
|
(Hmul32 <t>
|
|
|
|
|
(Const32 <config.fe.TypeUInt32()> [int64(int32(smagic(32,c).m))])
|
|
|
|
|
x)
|
|
|
|
|
x)
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [smagic(32,c).s]))
|
|
|
|
|
(Rsh32x64 <t>
|
|
|
|
|
x
|
|
|
|
|
(Const64 <config.fe.TypeUInt64()> [31])))
|
|
|
|
|
(Div64 <t> x (Const64 [c])) && smagicOK(64,c) && smagic(64,c).m&1 == 0 ->
|
2016-02-05 20:26:18 -08:00
|
|
|
(Sub64 <t>
|
|
|
|
|
(Rsh64x64 <t>
|
|
|
|
|
(Hmul64 <t>
|
2017-02-13 16:00:09 -08:00
|
|
|
(Const64 <config.fe.TypeUInt64()> [int64(smagic(64,c).m/2)])
|
2016-02-05 20:26:18 -08:00
|
|
|
x)
|
2017-02-13 16:00:09 -08:00
|
|
|
(Const64 <config.fe.TypeUInt64()> [smagic(64,c).s-1]))
|
2016-02-05 20:26:18 -08:00
|
|
|
(Rsh64x64 <t>
|
|
|
|
|
x
|
2017-02-13 16:00:09 -08:00
|
|
|
(Const64 <config.fe.TypeUInt64()> [63])))
|
|
|
|
|
(Div64 <t> x (Const64 [c])) && smagicOK(64,c) && smagic(64,c).m&1 != 0 ->
|
2016-02-05 20:26:18 -08:00
|
|
|
(Sub64 <t>
|
|
|
|
|
(Rsh64x64 <t>
|
|
|
|
|
(Add64 <t>
|
|
|
|
|
(Hmul64 <t>
|
2017-02-13 16:00:09 -08:00
|
|
|
(Const64 <config.fe.TypeUInt64()> [int64(smagic(64,c).m)])
|
2016-02-05 20:26:18 -08:00
|
|
|
x)
|
|
|
|
|
x)
|
2017-02-13 16:00:09 -08:00
|
|
|
(Const64 <config.fe.TypeUInt64()> [smagic(64,c).s]))
|
2016-02-05 20:26:18 -08:00
|
|
|
(Rsh64x64 <t>
|
|
|
|
|
x
|
2017-02-13 16:00:09 -08:00
|
|
|
(Const64 <config.fe.TypeUInt64()> [63])))
|
|
|
|
|
|
|
|
|
|
// Unsigned mod by power of 2 constant.
|
|
|
|
|
(Mod8u <t> n (Const8 [c])) && isPowerOfTwo(c&0xff) -> (And8 n (Const8 <t> [(c&0xff)-1]))
|
|
|
|
|
(Mod16u <t> n (Const16 [c])) && isPowerOfTwo(c&0xffff) -> (And16 n (Const16 <t> [(c&0xffff)-1]))
|
|
|
|
|
(Mod32u <t> n (Const32 [c])) && isPowerOfTwo(c&0xffffffff) -> (And32 n (Const32 <t> [(c&0xffffffff)-1]))
|
|
|
|
|
(Mod64u <t> n (Const64 [c])) && isPowerOfTwo(c) -> (And64 n (Const64 <t> [c-1]))
|
|
|
|
|
|
|
|
|
|
// Signed mod by negative constant.
|
|
|
|
|
(Mod8 <t> n (Const8 [c])) && c < 0 && c != -1<<7 -> (Mod8 <t> n (Const8 <t> [-c]))
|
|
|
|
|
(Mod16 <t> n (Const16 [c])) && c < 0 && c != -1<<15 -> (Mod16 <t> n (Const16 <t> [-c]))
|
|
|
|
|
(Mod32 <t> n (Const32 [c])) && c < 0 && c != -1<<31 -> (Mod32 <t> n (Const32 <t> [-c]))
|
|
|
|
|
(Mod64 <t> n (Const64 [c])) && c < 0 && c != -1<<63 -> (Mod64 <t> n (Const64 <t> [-c]))
|
2016-02-05 20:26:18 -08:00
|
|
|
|
2017-02-13 16:00:09 -08:00
|
|
|
// All other mods by constants, do A%B = A-(A/B*B).
|
2016-02-05 20:26:18 -08:00
|
|
|
// This implements % with two * and a bunch of ancillary ops.
|
|
|
|
|
// One of the * is free if the user's code also computes A/B.
|
2017-02-13 16:00:09 -08:00
|
|
|
(Mod8 <t> x (Const8 [c])) && x.Op != OpConst8 && (c > 0 || c == -1<<7)
|
|
|
|
|
-> (Sub8 x (Mul8 <t> (Div8 <t> x (Const8 <t> [c])) (Const8 <t> [c])))
|
|
|
|
|
(Mod16 <t> x (Const16 [c])) && x.Op != OpConst16 && (c > 0 || c == -1<<15)
|
|
|
|
|
-> (Sub16 x (Mul16 <t> (Div16 <t> x (Const16 <t> [c])) (Const16 <t> [c])))
|
|
|
|
|
(Mod32 <t> x (Const32 [c])) && x.Op != OpConst32 && (c > 0 || c == -1<<31)
|
|
|
|
|
-> (Sub32 x (Mul32 <t> (Div32 <t> x (Const32 <t> [c])) (Const32 <t> [c])))
|
|
|
|
|
(Mod64 <t> x (Const64 [c])) && x.Op != OpConst64 && (c > 0 || c == -1<<63)
|
2016-04-26 12:08:31 -07:00
|
|
|
-> (Sub64 x (Mul64 <t> (Div64 <t> x (Const64 <t> [c])) (Const64 <t> [c])))
|
2017-02-13 16:00:09 -08:00
|
|
|
(Mod8u <t> x (Const8 [c])) && x.Op != OpConst8 && c > 0 && umagicOK(8 ,c)
|
|
|
|
|
-> (Sub8 x (Mul8 <t> (Div8u <t> x (Const8 <t> [c])) (Const8 <t> [c])))
|
|
|
|
|
(Mod16u <t> x (Const16 [c])) && x.Op != OpConst16 && c > 0 && umagicOK(16,c)
|
|
|
|
|
-> (Sub16 x (Mul16 <t> (Div16u <t> x (Const16 <t> [c])) (Const16 <t> [c])))
|
|
|
|
|
(Mod32u <t> x (Const32 [c])) && x.Op != OpConst32 && c > 0 && umagicOK(32,c)
|
|
|
|
|
-> (Sub32 x (Mul32 <t> (Div32u <t> x (Const32 <t> [c])) (Const32 <t> [c])))
|
|
|
|
|
(Mod64u <t> x (Const64 [c])) && x.Op != OpConst64 && c > 0 && umagicOK(64,c)
|
2016-04-26 12:08:31 -07:00
|
|
|
-> (Sub64 x (Mul64 <t> (Div64u <t> x (Const64 <t> [c])) (Const64 <t> [c])))
|
2016-07-06 10:04:45 -04:00
|
|
|
|
2017-02-20 08:43:54 -08:00
|
|
|
// Reassociate expressions involving
|
|
|
|
|
// constants such that constants come first,
|
|
|
|
|
// exposing obvious constant-folding opportunities.
|
|
|
|
|
// First, re-write (op x (op y z)) to (op (op y z) x) if
|
|
|
|
|
// the op is commutative, to reduce the number of subsequent
|
|
|
|
|
// matching rules for folding. Then, reassociate
|
|
|
|
|
// (op (op y C) x) to (op C (op x y)) or similar, where C
|
|
|
|
|
// is constant, which pushes constants to the outside
|
|
|
|
|
// of the expression. At that point, any constant-folding
|
|
|
|
|
// opportunities should be obvious.
|
|
|
|
|
|
|
|
|
|
(Add64 x l:(Add64 _ _)) && (x.Op != OpAdd64 && x.Op != OpConst64) -> (Add64 l x)
|
|
|
|
|
(Add32 x l:(Add32 _ _)) && (x.Op != OpAdd32 && x.Op != OpConst32) -> (Add32 l x)
|
|
|
|
|
(Add16 x l:(Add16 _ _)) && (x.Op != OpAdd16 && x.Op != OpConst16) -> (Add16 l x)
|
|
|
|
|
(Add8 x l:(Add8 _ _)) && (x.Op != OpAdd8 && x.Op != OpConst8) -> (Add8 l x)
|
|
|
|
|
(And64 x l:(And64 _ _)) && (x.Op != OpAnd64 && x.Op != OpConst64) -> (And64 l x)
|
|
|
|
|
(And32 x l:(And32 _ _)) && (x.Op != OpAnd32 && x.Op != OpConst32) -> (And32 l x)
|
|
|
|
|
(And16 x l:(And16 _ _)) && (x.Op != OpAnd16 && x.Op != OpConst16) -> (And16 l x)
|
|
|
|
|
(And8 x l:(And8 _ _)) && (x.Op != OpAnd8 && x.Op != OpConst8) -> (And8 l x)
|
|
|
|
|
(Or64 x l:(Or64 _ _)) && (x.Op != OpOr64 && x.Op != OpConst64) -> (Or64 l x)
|
|
|
|
|
(Or32 x l:(Or32 _ _)) && (x.Op != OpOr32 && x.Op != OpConst32) -> (Or32 l x)
|
|
|
|
|
(Or16 x l:(Or16 _ _)) && (x.Op != OpOr16 && x.Op != OpConst16) -> (Or16 l x)
|
|
|
|
|
(Or8 x l:(Or8 _ _)) && (x.Op != OpOr8 && x.Op != OpConst8) -> (Or8 l x)
|
|
|
|
|
(Xor64 x l:(Xor64 _ _)) && (x.Op != OpXor64 && x.Op != OpConst64) -> (Xor64 l x)
|
|
|
|
|
(Xor32 x l:(Xor32 _ _)) && (x.Op != OpXor32 && x.Op != OpConst32) -> (Xor32 l x)
|
|
|
|
|
(Xor16 x l:(Xor16 _ _)) && (x.Op != OpXor16 && x.Op != OpConst16) -> (Xor16 l x)
|
|
|
|
|
(Xor8 x l:(Xor8 _ _)) && (x.Op != OpXor8 && x.Op != OpConst8) -> (Xor8 l x)
|
|
|
|
|
(Mul64 x l:(Mul64 _ _)) && (x.Op != OpMul64 && x.Op != OpConst64) -> (Mul64 l x)
|
|
|
|
|
(Mul32 x l:(Mul32 _ _)) && (x.Op != OpMul32 && x.Op != OpConst32) -> (Mul32 l x)
|
|
|
|
|
(Mul16 x l:(Mul16 _ _)) && (x.Op != OpMul16 && x.Op != OpConst16) -> (Mul16 l x)
|
|
|
|
|
(Mul8 x l:(Mul8 _ _)) && (x.Op != OpMul8 && x.Op != OpConst8) -> (Mul8 l x)
|
|
|
|
|
|
|
|
|
|
// x + (C + z) -> C + (x + z)
|
|
|
|
|
(Add64 (Add64 i:(Const64 <t>) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Add64 i (Add64 <t> z x))
|
|
|
|
|
(Add32 (Add32 i:(Const32 <t>) z) x) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Add32 i (Add32 <t> z x))
|
|
|
|
|
(Add16 (Add16 i:(Const16 <t>) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Add16 i (Add16 <t> z x))
|
|
|
|
|
(Add8 (Add8 i:(Const8 <t>) z) x) && (z.Op != OpConst8 && x.Op != OpConst8) -> (Add8 i (Add8 <t> z x))
|
|
|
|
|
|
|
|
|
|
// x + (C - z) -> C + (x - z)
|
|
|
|
|
(Add64 (Sub64 i:(Const64 <t>) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Add64 i (Sub64 <t> x z))
|
|
|
|
|
(Add32 (Sub32 i:(Const32 <t>) z) x) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Add32 i (Sub32 <t> x z))
|
|
|
|
|
(Add16 (Sub16 i:(Const16 <t>) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Add16 i (Sub16 <t> x z))
|
|
|
|
|
(Add8 (Sub8 i:(Const8 <t>) z) x) && (z.Op != OpConst8 && x.Op != OpConst8) -> (Add8 i (Sub8 <t> x z))
|
|
|
|
|
(Add64 x (Sub64 i:(Const64 <t>) z)) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Add64 i (Sub64 <t> x z))
|
|
|
|
|
(Add32 x (Sub32 i:(Const32 <t>) z)) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Add32 i (Sub32 <t> x z))
|
|
|
|
|
(Add16 x (Sub16 i:(Const16 <t>) z)) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Add16 i (Sub16 <t> x z))
|
|
|
|
|
(Add8 x (Sub8 i:(Const8 <t>) z)) && (z.Op != OpConst8 && x.Op != OpConst8) -> (Add8 i (Sub8 <t> x z))
|
|
|
|
|
|
|
|
|
|
// x + (z - C) -> (x + z) - C
|
|
|
|
|
(Add64 (Sub64 z i:(Const64 <t>)) x) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Sub64 (Add64 <t> x z) i)
|
|
|
|
|
(Add32 (Sub32 z i:(Const32 <t>)) x) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Sub32 (Add32 <t> x z) i)
|
|
|
|
|
(Add16 (Sub16 z i:(Const16 <t>)) x) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Sub16 (Add16 <t> x z) i)
|
|
|
|
|
(Add8 (Sub8 z i:(Const8 <t>)) x) && (z.Op != OpConst8 && x.Op != OpConst8) -> (Sub8 (Add8 <t> x z) i)
|
|
|
|
|
(Add64 x (Sub64 z i:(Const64 <t>))) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Sub64 (Add64 <t> x z) i)
|
|
|
|
|
(Add32 x (Sub32 z i:(Const32 <t>))) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Sub32 (Add32 <t> x z) i)
|
|
|
|
|
(Add16 x (Sub16 z i:(Const16 <t>))) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Sub16 (Add16 <t> x z) i)
|
|
|
|
|
(Add8 x (Sub8 z i:(Const8 <t>))) && (z.Op != OpConst8 && x.Op != OpConst8) -> (Sub8 (Add8 <t> x z) i)
|
|
|
|
|
|
|
|
|
|
// x - (C - z) -> x + (z - C) -> (x + z) - C
|
|
|
|
|
(Sub64 x (Sub64 i:(Const64 <t>) z)) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Sub64 (Add64 <t> x z) i)
|
|
|
|
|
(Sub32 x (Sub32 i:(Const32 <t>) z)) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Sub32 (Add32 <t> x z) i)
|
|
|
|
|
(Sub16 x (Sub16 i:(Const16 <t>) z)) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Sub16 (Add16 <t> x z) i)
|
|
|
|
|
(Sub8 x (Sub8 i:(Const8 <t>) z)) && (z.Op != OpConst8 && x.Op != OpConst8) -> (Sub8 (Add8 <t> x z) i)
|
|
|
|
|
|
|
|
|
|
// x - (z - C) -> x + (C - z) -> (x - z) + C
|
|
|
|
|
(Sub64 x (Sub64 z i:(Const64 <t>))) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Add64 i (Sub64 <t> x z))
|
|
|
|
|
(Sub32 x (Sub32 z i:(Const32 <t>))) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Add32 i (Sub32 <t> x z))
|
|
|
|
|
(Sub16 x (Sub16 z i:(Const16 <t>))) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Add16 i (Sub16 <t> x z))
|
|
|
|
|
(Sub8 x (Sub8 z i:(Const8 <t>))) && (z.Op != OpConst8 && x.Op != OpConst8) -> (Add8 i (Sub8 <t> x z))
|
|
|
|
|
|
|
|
|
|
// x & (C & z) -> C & (x & z)
|
|
|
|
|
(And64 (And64 i:(Const64 <t>) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) -> (And64 i (And64 <t> z x))
|
|
|
|
|
(And32 (And32 i:(Const32 <t>) z) x) && (z.Op != OpConst32 && x.Op != OpConst32) -> (And32 i (And32 <t> z x))
|
|
|
|
|
(And16 (And16 i:(Const16 <t>) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) -> (And16 i (And16 <t> z x))
|
|
|
|
|
(And8 (And8 i:(Const8 <t>) z) x) && (z.Op != OpConst8 && x.Op != OpConst8) -> (And8 i (And8 <t> z x))
|
|
|
|
|
|
|
|
|
|
// x | (C | z) -> C | (x | z)
|
|
|
|
|
(Or64 (Or64 i:(Const64 <t>) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Or64 i (Or64 <t> z x))
|
|
|
|
|
(Or32 (Or32 i:(Const32 <t>) z) x) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Or32 i (Or32 <t> z x))
|
|
|
|
|
(Or16 (Or16 i:(Const16 <t>) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Or16 i (Or16 <t> z x))
|
|
|
|
|
(Or8 (Or8 i:(Const8 <t>) z) x) && (z.Op != OpConst8 && x.Op != OpConst8) -> (Or8 i (Or8 <t> z x))
|
|
|
|
|
|
|
|
|
|
// x ^ (C ^ z) -> C ^ (x ^ z)
|
|
|
|
|
(Xor64 (Xor64 i:(Const64 <t>) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) -> (Xor64 i (Xor64 <t> z x))
|
|
|
|
|
(Xor32 (Xor32 i:(Const32 <t>) z) x) && (z.Op != OpConst32 && x.Op != OpConst32) -> (Xor32 i (Xor32 <t> z x))
|
|
|
|
|
(Xor16 (Xor16 i:(Const16 <t>) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) -> (Xor16 i (Xor16 <t> z x))
|
|
|
|
|
(Xor8 (Xor8 i:(Const8 <t>) z) x) && (z.Op != OpConst8 && x.Op != OpConst8) -> (Xor8 i (Xor8 <t> z x))
|
|
|
|
|
|
|
|
|
|
// C + (D + x) -> (C + D) + x
|
|
|
|
|
(Add64 (Const64 <t> [c]) (Add64 (Const64 <t> [d]) x)) -> (Add64 (Const64 <t> [c+d]) x)
|
|
|
|
|
(Add32 (Const32 <t> [c]) (Add32 (Const32 <t> [d]) x)) -> (Add32 (Const32 <t> [int64(int32(c+d))]) x)
|
|
|
|
|
(Add16 (Const16 <t> [c]) (Add16 (Const16 <t> [d]) x)) -> (Add16 (Const16 <t> [int64(int16(c+d))]) x)
|
|
|
|
|
(Add8 (Const8 <t> [c]) (Add8 (Const8 <t> [d]) x)) -> (Add8 (Const8 <t> [int64(int8(c+d))]) x)
|
|
|
|
|
|
|
|
|
|
// C + (D - x) -> (C + D) - x
|
|
|
|
|
(Add64 (Const64 <t> [c]) (Sub64 (Const64 <t> [d]) x)) -> (Sub64 (Const64 <t> [c+d]) x)
|
|
|
|
|
(Add32 (Const32 <t> [c]) (Sub32 (Const32 <t> [d]) x)) -> (Sub32 (Const32 <t> [int64(int32(c+d))]) x)
|
|
|
|
|
(Add16 (Const16 <t> [c]) (Sub16 (Const16 <t> [d]) x)) -> (Sub16 (Const16 <t> [int64(int16(c+d))]) x)
|
|
|
|
|
(Add8 (Const8 <t> [c]) (Sub8 (Const8 <t> [d]) x)) -> (Sub8 (Const8 <t> [int64(int8(c+d))]) x)
|
|
|
|
|
|
|
|
|
|
// C + (x - D) -> (C - D) + x
|
|
|
|
|
(Add64 (Const64 <t> [c]) (Sub64 x (Const64 <t> [d]))) -> (Add64 (Const64 <t> [c-d]) x)
|
|
|
|
|
(Add32 (Const32 <t> [c]) (Sub32 x (Const32 <t> [d]))) -> (Add32 (Const32 <t> [int64(int32(c-d))]) x)
|
|
|
|
|
(Add16 (Const16 <t> [c]) (Sub16 x (Const16 <t> [d]))) -> (Add16 (Const16 <t> [int64(int16(c-d))]) x)
|
|
|
|
|
(Add8 (Const8 <t> [c]) (Sub8 x (Const8 <t> [d]))) -> (Add8 (Const8 <t> [int64(int8(c-d))]) x)
|
|
|
|
|
|
|
|
|
|
// C - (x - D) -> (C + D) - x
|
|
|
|
|
(Sub64 (Const64 <t> [c]) (Sub64 x (Const64 <t> [d]))) -> (Sub64 (Const64 <t> [c+d]) x)
|
|
|
|
|
(Sub32 (Const32 <t> [c]) (Sub32 x (Const32 <t> [d]))) -> (Sub32 (Const32 <t> [int64(int32(c+d))]) x)
|
|
|
|
|
(Sub16 (Const16 <t> [c]) (Sub16 x (Const16 <t> [d]))) -> (Sub16 (Const16 <t> [int64(int16(c+d))]) x)
|
|
|
|
|
(Sub8 (Const8 <t> [c]) (Sub8 x (Const8 <t> [d]))) -> (Sub8 (Const8 <t> [int64(int8(c+d))]) x)
|
|
|
|
|
|
|
|
|
|
// C - (D - x) -> (C - D) + x
|
|
|
|
|
(Sub64 (Const64 <t> [c]) (Sub64 (Const64 <t> [d]) x)) -> (Add64 (Const64 <t> [c-d]) x)
|
|
|
|
|
(Sub32 (Const32 <t> [c]) (Sub32 (Const32 <t> [d]) x)) -> (Add32 (Const32 <t> [int64(int32(c-d))]) x)
|
|
|
|
|
(Sub16 (Const16 <t> [c]) (Sub16 (Const16 <t> [d]) x)) -> (Add16 (Const16 <t> [int64(int16(c-d))]) x)
|
|
|
|
|
(Sub8 (Const8 <t> [c]) (Sub8 (Const8 <t> [d]) x)) -> (Add8 (Const8 <t> [int64(int8(c-d))]) x)
|
|
|
|
|
|
|
|
|
|
// C & (D & x) -> (C & D) & x
|
|
|
|
|
(And64 (Const64 <t> [c]) (And64 (Const64 <t> [d]) x)) -> (And64 (Const64 <t> [c&d]) x)
|
|
|
|
|
(And32 (Const32 <t> [c]) (And32 (Const32 <t> [d]) x)) -> (And32 (Const32 <t> [int64(int32(c&d))]) x)
|
|
|
|
|
(And16 (Const16 <t> [c]) (And16 (Const16 <t> [d]) x)) -> (And16 (Const16 <t> [int64(int16(c&d))]) x)
|
|
|
|
|
(And8 (Const8 <t> [c]) (And8 (Const8 <t> [d]) x)) -> (And8 (Const8 <t> [int64(int8(c&d))]) x)
|
|
|
|
|
|
|
|
|
|
// C | (D | x) -> (C | D) | x
|
|
|
|
|
(Or64 (Const64 <t> [c]) (Or64 (Const64 <t> [d]) x)) -> (Or64 (Const64 <t> [c|d]) x)
|
|
|
|
|
(Or32 (Const32 <t> [c]) (Or32 (Const32 <t> [d]) x)) -> (Or32 (Const32 <t> [int64(int32(c|d))]) x)
|
|
|
|
|
(Or16 (Const16 <t> [c]) (Or16 (Const16 <t> [d]) x)) -> (Or16 (Const16 <t> [int64(int16(c|d))]) x)
|
|
|
|
|
(Or8 (Const8 <t> [c]) (Or8 (Const8 <t> [d]) x)) -> (Or8 (Const8 <t> [int64(int8(c|d))]) x)
|
|
|
|
|
|
|
|
|
|
// C ^ (D ^ x) -> (C ^ D) ^ x
|
|
|
|
|
(Xor64 (Const64 <t> [c]) (Xor64 (Const64 <t> [d]) x)) -> (Xor64 (Const64 <t> [c^d]) x)
|
|
|
|
|
(Xor32 (Const32 <t> [c]) (Xor32 (Const32 <t> [d]) x)) -> (Xor32 (Const32 <t> [int64(int32(c^d))]) x)
|
|
|
|
|
(Xor16 (Const16 <t> [c]) (Xor16 (Const16 <t> [d]) x)) -> (Xor16 (Const16 <t> [int64(int16(c^d))]) x)
|
|
|
|
|
(Xor8 (Const8 <t> [c]) (Xor8 (Const8 <t> [d]) x)) -> (Xor8 (Const8 <t> [int64(int8(c^d))]) x)
|
|
|
|
|
|
|
|
|
|
// C * (D * x) = (C * D) * x
|
|
|
|
|
(Mul64 (Const64 <t> [c]) (Mul64 (Const64 <t> [d]) x)) -> (Mul64 (Const64 <t> [c*d]) x)
|
|
|
|
|
(Mul32 (Const32 <t> [c]) (Mul32 (Const32 <t> [d]) x)) -> (Mul32 (Const32 <t> [int64(int32(c*d))]) x)
|
|
|
|
|
(Mul16 (Const16 <t> [c]) (Mul16 (Const16 <t> [d]) x)) -> (Mul16 (Const16 <t> [int64(int16(c*d))]) x)
|
|
|
|
|
(Mul8 (Const8 <t> [c]) (Mul8 (Const8 <t> [d]) x)) -> (Mul8 (Const8 <t> [int64(int8(c*d))]) x)
|
|
|
|
|
|
2016-07-06 10:04:45 -04:00
|
|
|
// floating point optimizations
|
|
|
|
|
(Add32F x (Const32F [0])) -> x
|
|
|
|
|
(Add32F (Const32F [0]) x) -> x
|
|
|
|
|
(Add64F x (Const64F [0])) -> x
|
|
|
|
|
(Add64F (Const64F [0]) x) -> x
|
|
|
|
|
(Sub32F x (Const32F [0])) -> x
|
|
|
|
|
(Sub64F x (Const64F [0])) -> x
|
|
|
|
|
(Mul32F x (Const32F [f2i(1)])) -> x
|
|
|
|
|
(Mul32F (Const32F [f2i(1)]) x) -> x
|
|
|
|
|
(Mul64F x (Const64F [f2i(1)])) -> x
|
|
|
|
|
(Mul64F (Const64F [f2i(1)]) x) -> x
|
|
|
|
|
(Mul32F x (Const32F [f2i(-1)])) -> (Neg32F x)
|
|
|
|
|
(Mul32F (Const32F [f2i(-1)]) x) -> (Neg32F x)
|
|
|
|
|
(Mul64F x (Const64F [f2i(-1)])) -> (Neg64F x)
|
|
|
|
|
(Mul64F (Const64F [f2i(-1)]) x) -> (Neg64F x)
|
|
|
|
|
(Div32F x (Const32F [f2i(1)])) -> x
|
|
|
|
|
(Div64F x (Const64F [f2i(1)])) -> x
|
|
|
|
|
(Div32F x (Const32F [f2i(-1)])) -> (Neg32F x)
|
|
|
|
|
(Div64F x (Const64F [f2i(-1)])) -> (Neg32F x)
|
2016-08-20 22:05:47 -07:00
|
|
|
|
|
|
|
|
(Sqrt (Const64F [c])) -> (Const64F [f2i(math.Sqrt(i2f(c)))])
|
2016-08-26 15:41:51 -04:00
|
|
|
|
|
|
|
|
// recognize runtime.newobject and don't Zero/Nilcheck it
|
2016-09-13 17:01:01 -07:00
|
|
|
(Zero (Load (OffPtr [c] (SP)) mem) mem)
|
2017-03-03 13:53:13 -05:00
|
|
|
&& mem.Op == OpStaticCall
|
2016-09-13 17:01:01 -07:00
|
|
|
&& isSameSym(mem.Aux, "runtime.newobject")
|
2017-03-03 13:53:13 -05:00
|
|
|
&& c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value
|
2016-08-26 15:41:51 -04:00
|
|
|
-> mem
|
2017-02-03 16:18:01 -05:00
|
|
|
(Store (Load (OffPtr [c] (SP)) mem) x mem)
|
|
|
|
|
&& isConstZero(x)
|
|
|
|
|
&& mem.Op == OpStaticCall
|
|
|
|
|
&& isSameSym(mem.Aux, "runtime.newobject")
|
|
|
|
|
&& c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value
|
|
|
|
|
-> mem
|
|
|
|
|
(Store (OffPtr (Load (OffPtr [c] (SP)) mem)) x mem)
|
|
|
|
|
&& isConstZero(x)
|
|
|
|
|
&& mem.Op == OpStaticCall
|
|
|
|
|
&& isSameSym(mem.Aux, "runtime.newobject")
|
|
|
|
|
&& c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value
|
|
|
|
|
-> mem
|
2016-09-13 17:01:01 -07:00
|
|
|
// nil checks just need to rewrite to something useless.
|
|
|
|
|
// they will be deadcode eliminated soon afterwards.
|
2016-09-28 10:20:24 -04:00
|
|
|
(NilCheck (Load (OffPtr [c] (SP)) mem) mem)
|
|
|
|
|
&& mem.Op == OpStaticCall
|
|
|
|
|
&& isSameSym(mem.Aux, "runtime.newobject")
|
|
|
|
|
&& c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value
|
2017-02-01 14:40:58 -05:00
|
|
|
&& warnRule(config.Debug_checknil() && v.Pos.Line() > 1, v, "removed nil check")
|
2016-09-28 10:20:24 -04:00
|
|
|
-> (Invalid)
|
|
|
|
|
(NilCheck (OffPtr (Load (OffPtr [c] (SP)) mem)) mem)
|
|
|
|
|
&& mem.Op == OpStaticCall
|
|
|
|
|
&& isSameSym(mem.Aux, "runtime.newobject")
|
|
|
|
|
&& c == config.ctxt.FixedFrameSize() + config.RegSize // offset of return value
|
2017-02-01 14:40:58 -05:00
|
|
|
&& warnRule(config.Debug_checknil() && v.Pos.Line() > 1, v, "removed nil check")
|
2016-09-28 10:20:24 -04:00
|
|
|
-> (Invalid)
|