From bbd0bc22ea4bc447a4d009db7d5137688820896d Mon Sep 17 00:00:00 2001 From: Jorropo Date: Wed, 10 Jan 2024 07:31:57 +0100 Subject: [PATCH] cmd/compile: improve integer comparisons with numeric bounds This do: - Fold always false or always true comparisons for ints and uint. - Reduce < and <= where the true set is only one value to == with such value. Change-Id: Ie9e3f70efd1845bef62db56543f051a50ad2532e Reviewed-on: https://go-review.googlesource.com/c/go/+/555135 Auto-Submit: Keith Randall Reviewed-by: Keith Randall Reviewed-by: Cherry Mui Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI --- .../compile/internal/ssa/_gen/generic.rules | 46 +- .../compile/internal/ssa/rewritegeneric.go | 716 +++++++++++++++++- test/fuse.go | 10 +- test/prove.go | 21 +- 4 files changed, 773 insertions(+), 20 deletions(-) diff --git a/src/cmd/compile/internal/ssa/_gen/generic.rules b/src/cmd/compile/internal/ssa/_gen/generic.rules index aeda62591a7750..4c475d31e00a0c 100644 --- a/src/cmd/compile/internal/ssa/_gen/generic.rules +++ b/src/cmd/compile/internal/ssa/_gen/generic.rules @@ -601,9 +601,49 @@ (Or(64|32|16|8) x (Or(64|32|16|8) x y)) => (Or(64|32|16|8) x y) (Xor(64|32|16|8) x (Xor(64|32|16|8) x y)) => y -// Unsigned comparisons to zero. -(Less(64U|32U|16U|8U) _ (Const(64|32|16|8) [0])) => (ConstBool [false]) -(Leq(64U|32U|16U|8U) (Const(64|32|16|8) [0]) _) => (ConstBool [true]) +// Fold comparisons with numeric bounds +(Less(64|32|16|8)U _ (Const(64|32|16|8) [0])) => (ConstBool [false]) +(Leq(64|32|16|8)U (Const(64|32|16|8) [0]) _) => (ConstBool [true]) +(Less(64|32|16|8)U (Const(64|32|16|8) [-1]) _) => (ConstBool [false]) +(Leq(64|32|16|8)U _ (Const(64|32|16|8) [-1])) => (ConstBool [true]) +(Less64 _ (Const64 [math.MinInt64])) => (ConstBool [false]) +(Less32 _ (Const32 [math.MinInt32])) => (ConstBool [false]) +(Less16 _ (Const16 [math.MinInt16])) => (ConstBool [false]) +(Less8 _ (Const8 [math.MinInt8 ])) => (ConstBool [false]) +(Leq64 (Const64 [math.MinInt64]) _) => (ConstBool [true]) +(Leq32 (Const32 [math.MinInt32]) _) => (ConstBool [true]) +(Leq16 (Const16 [math.MinInt16]) _) => (ConstBool [true]) +(Leq8 (Const8 [math.MinInt8 ]) _) => (ConstBool [true]) +(Less64 (Const64 [math.MaxInt64]) _) => (ConstBool [false]) +(Less32 (Const32 [math.MaxInt32]) _) => (ConstBool [false]) +(Less16 (Const16 [math.MaxInt16]) _) => (ConstBool [false]) +(Less8 (Const8 [math.MaxInt8 ]) _) => (ConstBool [false]) +(Leq64 _ (Const64 [math.MaxInt64])) => (ConstBool [true]) +(Leq32 _ (Const32 [math.MaxInt32])) => (ConstBool [true]) +(Leq16 _ (Const16 [math.MaxInt16])) => (ConstBool [true]) +(Leq8 _ (Const8 [math.MaxInt8 ])) => (ConstBool [true]) + +// Canonicalize <= on numeric bounds and < near numeric bounds to == +(Leq(64|32|16|8)U x c:(Const(64|32|16|8) [0])) => (Eq(64|32|16|8) x c) +(Leq(64|32|16|8)U c:(Const(64|32|16|8) [-1]) x) => (Eq(64|32|16|8) x c) +(Less(64|32|16|8)U x (Const(64|32|16|8) [1])) => (Eq(64|32|16|8) x (Const(64|32|16|8) [0])) +(Less(64|32|16|8)U (Const(64|32|16|8) [-2]) x) => (Eq(64|32|16|8) x (Const(64|32|16|8) [-1])) +(Leq64 x c:(Const64 [math.MinInt64])) => (Eq64 x c) +(Leq32 x c:(Const32 [math.MinInt32])) => (Eq32 x c) +(Leq16 x c:(Const16 [math.MinInt16])) => (Eq16 x c) +(Leq8 x c:(Const8 [math.MinInt8 ])) => (Eq8 x c) +(Leq64 c:(Const64 [math.MaxInt64]) x) => (Eq64 x c) +(Leq32 c:(Const32 [math.MaxInt32]) x) => (Eq32 x c) +(Leq16 c:(Const16 [math.MaxInt16]) x) => (Eq16 x c) +(Leq8 c:(Const8 [math.MaxInt8 ]) x) => (Eq8 x c) +(Less64 x (Const64 [math.MinInt64+1])) => (Eq64 x (Const64 [math.MinInt64])) +(Less32 x (Const32 [math.MinInt32+1])) => (Eq32 x (Const32 [math.MinInt32])) +(Less16 x (Const16 [math.MinInt16+1])) => (Eq16 x (Const16 [math.MinInt16])) +(Less8 x (Const8 [math.MinInt8 +1])) => (Eq8 x (Const8 [math.MinInt8 ])) +(Less64 (Const64 [math.MaxInt64-1]) x) => (Eq64 x (Const64 [math.MaxInt64])) +(Less32 (Const32 [math.MaxInt32-1]) x) => (Eq32 x (Const32 [math.MaxInt32])) +(Less16 (Const16 [math.MaxInt16-1]) x) => (Eq16 x (Const16 [math.MaxInt16])) +(Less8 (Const8 [math.MaxInt8 -1]) x) => (Eq8 x (Const8 [math.MaxInt8 ])) // Ands clear bits. Ors set bits. // If a subsequent Or will set all the bits diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index a018ca04b63507..468e9fa9c610d1 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -11443,6 +11443,50 @@ func rewriteValuegeneric_OpLeq16(v *Value) bool { v.AddArg2(v0, x) return true } + // match: (Leq16 (Const16 [math.MinInt16]) _) + // result: (ConstBool [true]) + for { + if v_0.Op != OpConst16 || auxIntToInt16(v_0.AuxInt) != math.MinInt16 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(true) + return true + } + // match: (Leq16 _ (Const16 [math.MaxInt16])) + // result: (ConstBool [true]) + for { + if v_1.Op != OpConst16 || auxIntToInt16(v_1.AuxInt) != math.MaxInt16 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(true) + return true + } + // match: (Leq16 x c:(Const16 [math.MinInt16])) + // result: (Eq16 x c) + for { + x := v_0 + c := v_1 + if c.Op != OpConst16 || auxIntToInt16(c.AuxInt) != math.MinInt16 { + break + } + v.reset(OpEq16) + v.AddArg2(x, c) + return true + } + // match: (Leq16 c:(Const16 [math.MaxInt16]) x) + // result: (Eq16 x c) + for { + c := v_0 + if c.Op != OpConst16 || auxIntToInt16(c.AuxInt) != math.MaxInt16 { + break + } + x := v_1 + v.reset(OpEq16) + v.AddArg2(x, c) + return true + } return false } func rewriteValuegeneric_OpLeq16U(v *Value) bool { @@ -11491,6 +11535,40 @@ func rewriteValuegeneric_OpLeq16U(v *Value) bool { v.AuxInt = boolToAuxInt(true) return true } + // match: (Leq16U _ (Const16 [-1])) + // result: (ConstBool [true]) + for { + if v_1.Op != OpConst16 || auxIntToInt16(v_1.AuxInt) != -1 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(true) + return true + } + // match: (Leq16U x c:(Const16 [0])) + // result: (Eq16 x c) + for { + x := v_0 + c := v_1 + if c.Op != OpConst16 || auxIntToInt16(c.AuxInt) != 0 { + break + } + v.reset(OpEq16) + v.AddArg2(x, c) + return true + } + // match: (Leq16U c:(Const16 [-1]) x) + // result: (Eq16 x c) + for { + c := v_0 + if c.Op != OpConst16 || auxIntToInt16(c.AuxInt) != -1 { + break + } + x := v_1 + v.reset(OpEq16) + v.AddArg2(x, c) + return true + } return false } func rewriteValuegeneric_OpLeq32(v *Value) bool { @@ -11590,6 +11668,50 @@ func rewriteValuegeneric_OpLeq32(v *Value) bool { v.AddArg2(v0, x) return true } + // match: (Leq32 (Const32 [math.MinInt32]) _) + // result: (ConstBool [true]) + for { + if v_0.Op != OpConst32 || auxIntToInt32(v_0.AuxInt) != math.MinInt32 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(true) + return true + } + // match: (Leq32 _ (Const32 [math.MaxInt32])) + // result: (ConstBool [true]) + for { + if v_1.Op != OpConst32 || auxIntToInt32(v_1.AuxInt) != math.MaxInt32 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(true) + return true + } + // match: (Leq32 x c:(Const32 [math.MinInt32])) + // result: (Eq32 x c) + for { + x := v_0 + c := v_1 + if c.Op != OpConst32 || auxIntToInt32(c.AuxInt) != math.MinInt32 { + break + } + v.reset(OpEq32) + v.AddArg2(x, c) + return true + } + // match: (Leq32 c:(Const32 [math.MaxInt32]) x) + // result: (Eq32 x c) + for { + c := v_0 + if c.Op != OpConst32 || auxIntToInt32(c.AuxInt) != math.MaxInt32 { + break + } + x := v_1 + v.reset(OpEq32) + v.AddArg2(x, c) + return true + } return false } func rewriteValuegeneric_OpLeq32F(v *Value) bool { @@ -11658,6 +11780,40 @@ func rewriteValuegeneric_OpLeq32U(v *Value) bool { v.AuxInt = boolToAuxInt(true) return true } + // match: (Leq32U _ (Const32 [-1])) + // result: (ConstBool [true]) + for { + if v_1.Op != OpConst32 || auxIntToInt32(v_1.AuxInt) != -1 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(true) + return true + } + // match: (Leq32U x c:(Const32 [0])) + // result: (Eq32 x c) + for { + x := v_0 + c := v_1 + if c.Op != OpConst32 || auxIntToInt32(c.AuxInt) != 0 { + break + } + v.reset(OpEq32) + v.AddArg2(x, c) + return true + } + // match: (Leq32U c:(Const32 [-1]) x) + // result: (Eq32 x c) + for { + c := v_0 + if c.Op != OpConst32 || auxIntToInt32(c.AuxInt) != -1 { + break + } + x := v_1 + v.reset(OpEq32) + v.AddArg2(x, c) + return true + } return false } func rewriteValuegeneric_OpLeq64(v *Value) bool { @@ -11757,6 +11913,50 @@ func rewriteValuegeneric_OpLeq64(v *Value) bool { v.AddArg2(v0, x) return true } + // match: (Leq64 (Const64 [math.MinInt64]) _) + // result: (ConstBool [true]) + for { + if v_0.Op != OpConst64 || auxIntToInt64(v_0.AuxInt) != math.MinInt64 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(true) + return true + } + // match: (Leq64 _ (Const64 [math.MaxInt64])) + // result: (ConstBool [true]) + for { + if v_1.Op != OpConst64 || auxIntToInt64(v_1.AuxInt) != math.MaxInt64 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(true) + return true + } + // match: (Leq64 x c:(Const64 [math.MinInt64])) + // result: (Eq64 x c) + for { + x := v_0 + c := v_1 + if c.Op != OpConst64 || auxIntToInt64(c.AuxInt) != math.MinInt64 { + break + } + v.reset(OpEq64) + v.AddArg2(x, c) + return true + } + // match: (Leq64 c:(Const64 [math.MaxInt64]) x) + // result: (Eq64 x c) + for { + c := v_0 + if c.Op != OpConst64 || auxIntToInt64(c.AuxInt) != math.MaxInt64 { + break + } + x := v_1 + v.reset(OpEq64) + v.AddArg2(x, c) + return true + } return false } func rewriteValuegeneric_OpLeq64F(v *Value) bool { @@ -11825,6 +12025,40 @@ func rewriteValuegeneric_OpLeq64U(v *Value) bool { v.AuxInt = boolToAuxInt(true) return true } + // match: (Leq64U _ (Const64 [-1])) + // result: (ConstBool [true]) + for { + if v_1.Op != OpConst64 || auxIntToInt64(v_1.AuxInt) != -1 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(true) + return true + } + // match: (Leq64U x c:(Const64 [0])) + // result: (Eq64 x c) + for { + x := v_0 + c := v_1 + if c.Op != OpConst64 || auxIntToInt64(c.AuxInt) != 0 { + break + } + v.reset(OpEq64) + v.AddArg2(x, c) + return true + } + // match: (Leq64U c:(Const64 [-1]) x) + // result: (Eq64 x c) + for { + c := v_0 + if c.Op != OpConst64 || auxIntToInt64(c.AuxInt) != -1 { + break + } + x := v_1 + v.reset(OpEq64) + v.AddArg2(x, c) + return true + } return false } func rewriteValuegeneric_OpLeq8(v *Value) bool { @@ -11924,6 +12158,50 @@ func rewriteValuegeneric_OpLeq8(v *Value) bool { v.AddArg2(v0, x) return true } + // match: (Leq8 (Const8 [math.MinInt8 ]) _) + // result: (ConstBool [true]) + for { + if v_0.Op != OpConst8 || auxIntToInt8(v_0.AuxInt) != math.MinInt8 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(true) + return true + } + // match: (Leq8 _ (Const8 [math.MaxInt8 ])) + // result: (ConstBool [true]) + for { + if v_1.Op != OpConst8 || auxIntToInt8(v_1.AuxInt) != math.MaxInt8 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(true) + return true + } + // match: (Leq8 x c:(Const8 [math.MinInt8 ])) + // result: (Eq8 x c) + for { + x := v_0 + c := v_1 + if c.Op != OpConst8 || auxIntToInt8(c.AuxInt) != math.MinInt8 { + break + } + v.reset(OpEq8) + v.AddArg2(x, c) + return true + } + // match: (Leq8 c:(Const8 [math.MaxInt8 ]) x) + // result: (Eq8 x c) + for { + c := v_0 + if c.Op != OpConst8 || auxIntToInt8(c.AuxInt) != math.MaxInt8 { + break + } + x := v_1 + v.reset(OpEq8) + v.AddArg2(x, c) + return true + } return false } func rewriteValuegeneric_OpLeq8U(v *Value) bool { @@ -11972,6 +12250,40 @@ func rewriteValuegeneric_OpLeq8U(v *Value) bool { v.AuxInt = boolToAuxInt(true) return true } + // match: (Leq8U _ (Const8 [-1])) + // result: (ConstBool [true]) + for { + if v_1.Op != OpConst8 || auxIntToInt8(v_1.AuxInt) != -1 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(true) + return true + } + // match: (Leq8U x c:(Const8 [0])) + // result: (Eq8 x c) + for { + x := v_0 + c := v_1 + if c.Op != OpConst8 || auxIntToInt8(c.AuxInt) != 0 { + break + } + v.reset(OpEq8) + v.AddArg2(x, c) + return true + } + // match: (Leq8U c:(Const8 [-1]) x) + // result: (Eq8 x c) + for { + c := v_0 + if c.Op != OpConst8 || auxIntToInt8(c.AuxInt) != -1 { + break + } + x := v_1 + v.reset(OpEq8) + v.AddArg2(x, c) + return true + } return false } func rewriteValuegeneric_OpLess16(v *Value) bool { @@ -12066,6 +12378,60 @@ func rewriteValuegeneric_OpLess16(v *Value) bool { v.AddArg2(v0, x) return true } + // match: (Less16 _ (Const16 [math.MinInt16])) + // result: (ConstBool [false]) + for { + if v_1.Op != OpConst16 || auxIntToInt16(v_1.AuxInt) != math.MinInt16 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(false) + return true + } + // match: (Less16 (Const16 [math.MaxInt16]) _) + // result: (ConstBool [false]) + for { + if v_0.Op != OpConst16 || auxIntToInt16(v_0.AuxInt) != math.MaxInt16 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(false) + return true + } + // match: (Less16 x (Const16 [math.MinInt16+1])) + // result: (Eq16 x (Const16 [math.MinInt16])) + for { + x := v_0 + if v_1.Op != OpConst16 { + break + } + t := v_1.Type + if auxIntToInt16(v_1.AuxInt) != math.MinInt16+1 { + break + } + v.reset(OpEq16) + v0 := b.NewValue0(v.Pos, OpConst16, t) + v0.AuxInt = int16ToAuxInt(math.MinInt16) + v.AddArg2(x, v0) + return true + } + // match: (Less16 (Const16 [math.MaxInt16-1]) x) + // result: (Eq16 x (Const16 [math.MaxInt16])) + for { + if v_0.Op != OpConst16 { + break + } + t := v_0.Type + if auxIntToInt16(v_0.AuxInt) != math.MaxInt16-1 { + break + } + x := v_1 + v.reset(OpEq16) + v0 := b.NewValue0(v.Pos, OpConst16, t) + v0.AuxInt = int16ToAuxInt(math.MaxInt16) + v.AddArg2(x, v0) + return true + } return false } func rewriteValuegeneric_OpLess16U(v *Value) bool { @@ -12114,12 +12480,56 @@ func rewriteValuegeneric_OpLess16U(v *Value) bool { v.AuxInt = boolToAuxInt(false) return true } - return false -} -func rewriteValuegeneric_OpLess32(v *Value) bool { - v_1 := v.Args[1] - v_0 := v.Args[0] - b := v.Block + // match: (Less16U (Const16 [-1]) _) + // result: (ConstBool [false]) + for { + if v_0.Op != OpConst16 || auxIntToInt16(v_0.AuxInt) != -1 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(false) + return true + } + // match: (Less16U x (Const16 [1])) + // result: (Eq16 x (Const16 [0])) + for { + x := v_0 + if v_1.Op != OpConst16 { + break + } + t := v_1.Type + if auxIntToInt16(v_1.AuxInt) != 1 { + break + } + v.reset(OpEq16) + v0 := b.NewValue0(v.Pos, OpConst16, t) + v0.AuxInt = int16ToAuxInt(0) + v.AddArg2(x, v0) + return true + } + // match: (Less16U (Const16 [-2]) x) + // result: (Eq16 x (Const16 [-1])) + for { + if v_0.Op != OpConst16 { + break + } + t := v_0.Type + if auxIntToInt16(v_0.AuxInt) != -2 { + break + } + x := v_1 + v.reset(OpEq16) + v0 := b.NewValue0(v.Pos, OpConst16, t) + v0.AuxInt = int16ToAuxInt(-1) + v.AddArg2(x, v0) + return true + } + return false +} +func rewriteValuegeneric_OpLess32(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + b := v.Block // match: (Less32 (Const32 [c]) (Const32 [d])) // result: (ConstBool [c < d]) for { @@ -12208,6 +12618,60 @@ func rewriteValuegeneric_OpLess32(v *Value) bool { v.AddArg2(v0, x) return true } + // match: (Less32 _ (Const32 [math.MinInt32])) + // result: (ConstBool [false]) + for { + if v_1.Op != OpConst32 || auxIntToInt32(v_1.AuxInt) != math.MinInt32 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(false) + return true + } + // match: (Less32 (Const32 [math.MaxInt32]) _) + // result: (ConstBool [false]) + for { + if v_0.Op != OpConst32 || auxIntToInt32(v_0.AuxInt) != math.MaxInt32 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(false) + return true + } + // match: (Less32 x (Const32 [math.MinInt32+1])) + // result: (Eq32 x (Const32 [math.MinInt32])) + for { + x := v_0 + if v_1.Op != OpConst32 { + break + } + t := v_1.Type + if auxIntToInt32(v_1.AuxInt) != math.MinInt32+1 { + break + } + v.reset(OpEq32) + v0 := b.NewValue0(v.Pos, OpConst32, t) + v0.AuxInt = int32ToAuxInt(math.MinInt32) + v.AddArg2(x, v0) + return true + } + // match: (Less32 (Const32 [math.MaxInt32-1]) x) + // result: (Eq32 x (Const32 [math.MaxInt32])) + for { + if v_0.Op != OpConst32 { + break + } + t := v_0.Type + if auxIntToInt32(v_0.AuxInt) != math.MaxInt32-1 { + break + } + x := v_1 + v.reset(OpEq32) + v0 := b.NewValue0(v.Pos, OpConst32, t) + v0.AuxInt = int32ToAuxInt(math.MaxInt32) + v.AddArg2(x, v0) + return true + } return false } func rewriteValuegeneric_OpLess32F(v *Value) bool { @@ -12276,6 +12740,50 @@ func rewriteValuegeneric_OpLess32U(v *Value) bool { v.AuxInt = boolToAuxInt(false) return true } + // match: (Less32U (Const32 [-1]) _) + // result: (ConstBool [false]) + for { + if v_0.Op != OpConst32 || auxIntToInt32(v_0.AuxInt) != -1 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(false) + return true + } + // match: (Less32U x (Const32 [1])) + // result: (Eq32 x (Const32 [0])) + for { + x := v_0 + if v_1.Op != OpConst32 { + break + } + t := v_1.Type + if auxIntToInt32(v_1.AuxInt) != 1 { + break + } + v.reset(OpEq32) + v0 := b.NewValue0(v.Pos, OpConst32, t) + v0.AuxInt = int32ToAuxInt(0) + v.AddArg2(x, v0) + return true + } + // match: (Less32U (Const32 [-2]) x) + // result: (Eq32 x (Const32 [-1])) + for { + if v_0.Op != OpConst32 { + break + } + t := v_0.Type + if auxIntToInt32(v_0.AuxInt) != -2 { + break + } + x := v_1 + v.reset(OpEq32) + v0 := b.NewValue0(v.Pos, OpConst32, t) + v0.AuxInt = int32ToAuxInt(-1) + v.AddArg2(x, v0) + return true + } return false } func rewriteValuegeneric_OpLess64(v *Value) bool { @@ -12370,6 +12878,60 @@ func rewriteValuegeneric_OpLess64(v *Value) bool { v.AddArg2(v0, x) return true } + // match: (Less64 _ (Const64 [math.MinInt64])) + // result: (ConstBool [false]) + for { + if v_1.Op != OpConst64 || auxIntToInt64(v_1.AuxInt) != math.MinInt64 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(false) + return true + } + // match: (Less64 (Const64 [math.MaxInt64]) _) + // result: (ConstBool [false]) + for { + if v_0.Op != OpConst64 || auxIntToInt64(v_0.AuxInt) != math.MaxInt64 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(false) + return true + } + // match: (Less64 x (Const64 [math.MinInt64+1])) + // result: (Eq64 x (Const64 [math.MinInt64])) + for { + x := v_0 + if v_1.Op != OpConst64 { + break + } + t := v_1.Type + if auxIntToInt64(v_1.AuxInt) != math.MinInt64+1 { + break + } + v.reset(OpEq64) + v0 := b.NewValue0(v.Pos, OpConst64, t) + v0.AuxInt = int64ToAuxInt(math.MinInt64) + v.AddArg2(x, v0) + return true + } + // match: (Less64 (Const64 [math.MaxInt64-1]) x) + // result: (Eq64 x (Const64 [math.MaxInt64])) + for { + if v_0.Op != OpConst64 { + break + } + t := v_0.Type + if auxIntToInt64(v_0.AuxInt) != math.MaxInt64-1 { + break + } + x := v_1 + v.reset(OpEq64) + v0 := b.NewValue0(v.Pos, OpConst64, t) + v0.AuxInt = int64ToAuxInt(math.MaxInt64) + v.AddArg2(x, v0) + return true + } return false } func rewriteValuegeneric_OpLess64F(v *Value) bool { @@ -12438,6 +13000,50 @@ func rewriteValuegeneric_OpLess64U(v *Value) bool { v.AuxInt = boolToAuxInt(false) return true } + // match: (Less64U (Const64 [-1]) _) + // result: (ConstBool [false]) + for { + if v_0.Op != OpConst64 || auxIntToInt64(v_0.AuxInt) != -1 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(false) + return true + } + // match: (Less64U x (Const64 [1])) + // result: (Eq64 x (Const64 [0])) + for { + x := v_0 + if v_1.Op != OpConst64 { + break + } + t := v_1.Type + if auxIntToInt64(v_1.AuxInt) != 1 { + break + } + v.reset(OpEq64) + v0 := b.NewValue0(v.Pos, OpConst64, t) + v0.AuxInt = int64ToAuxInt(0) + v.AddArg2(x, v0) + return true + } + // match: (Less64U (Const64 [-2]) x) + // result: (Eq64 x (Const64 [-1])) + for { + if v_0.Op != OpConst64 { + break + } + t := v_0.Type + if auxIntToInt64(v_0.AuxInt) != -2 { + break + } + x := v_1 + v.reset(OpEq64) + v0 := b.NewValue0(v.Pos, OpConst64, t) + v0.AuxInt = int64ToAuxInt(-1) + v.AddArg2(x, v0) + return true + } return false } func rewriteValuegeneric_OpLess8(v *Value) bool { @@ -12532,6 +13138,60 @@ func rewriteValuegeneric_OpLess8(v *Value) bool { v.AddArg2(v0, x) return true } + // match: (Less8 _ (Const8 [math.MinInt8 ])) + // result: (ConstBool [false]) + for { + if v_1.Op != OpConst8 || auxIntToInt8(v_1.AuxInt) != math.MinInt8 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(false) + return true + } + // match: (Less8 (Const8 [math.MaxInt8 ]) _) + // result: (ConstBool [false]) + for { + if v_0.Op != OpConst8 || auxIntToInt8(v_0.AuxInt) != math.MaxInt8 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(false) + return true + } + // match: (Less8 x (Const8 [math.MinInt8 +1])) + // result: (Eq8 x (Const8 [math.MinInt8 ])) + for { + x := v_0 + if v_1.Op != OpConst8 { + break + } + t := v_1.Type + if auxIntToInt8(v_1.AuxInt) != math.MinInt8+1 { + break + } + v.reset(OpEq8) + v0 := b.NewValue0(v.Pos, OpConst8, t) + v0.AuxInt = int8ToAuxInt(math.MinInt8) + v.AddArg2(x, v0) + return true + } + // match: (Less8 (Const8 [math.MaxInt8 -1]) x) + // result: (Eq8 x (Const8 [math.MaxInt8 ])) + for { + if v_0.Op != OpConst8 { + break + } + t := v_0.Type + if auxIntToInt8(v_0.AuxInt) != math.MaxInt8-1 { + break + } + x := v_1 + v.reset(OpEq8) + v0 := b.NewValue0(v.Pos, OpConst8, t) + v0.AuxInt = int8ToAuxInt(math.MaxInt8) + v.AddArg2(x, v0) + return true + } return false } func rewriteValuegeneric_OpLess8U(v *Value) bool { @@ -12580,6 +13240,50 @@ func rewriteValuegeneric_OpLess8U(v *Value) bool { v.AuxInt = boolToAuxInt(false) return true } + // match: (Less8U (Const8 [-1]) _) + // result: (ConstBool [false]) + for { + if v_0.Op != OpConst8 || auxIntToInt8(v_0.AuxInt) != -1 { + break + } + v.reset(OpConstBool) + v.AuxInt = boolToAuxInt(false) + return true + } + // match: (Less8U x (Const8 [1])) + // result: (Eq8 x (Const8 [0])) + for { + x := v_0 + if v_1.Op != OpConst8 { + break + } + t := v_1.Type + if auxIntToInt8(v_1.AuxInt) != 1 { + break + } + v.reset(OpEq8) + v0 := b.NewValue0(v.Pos, OpConst8, t) + v0.AuxInt = int8ToAuxInt(0) + v.AddArg2(x, v0) + return true + } + // match: (Less8U (Const8 [-2]) x) + // result: (Eq8 x (Const8 [-1])) + for { + if v_0.Op != OpConst8 { + break + } + t := v_0.Type + if auxIntToInt8(v_0.AuxInt) != -2 { + break + } + x := v_1 + v.reset(OpEq8) + v0 := b.NewValue0(v.Pos, OpConst8, t) + v0.AuxInt = int8ToAuxInt(-1) + v.AddArg2(x, v0) + return true + } return false } func rewriteValuegeneric_OpLoad(v *Value) bool { diff --git a/test/fuse.go b/test/fuse.go index f64a087965ae09..e9205dcc2355fb 100644 --- a/test/fuse.go +++ b/test/fuse.go @@ -33,7 +33,7 @@ func fEqLessU(a uint, f float64) bool { } func fEqLeqU(a uint64, f float64) bool { - return a == 0 && f > Cf2 || a <= 0 && f < -Cf2 // ERROR "Redirect Leq64U based on Eq64$" + return a == 0 && f > Cf2 || a <= 0 && f < -Cf2 // ERROR "Redirect Eq64 based on Eq64$" } func fNeqEq(a int, f float64) bool { @@ -58,7 +58,7 @@ func fNeqLessU(a uint, f float64) bool { } func fNeqLeqU(a uint32, f float64) bool { - return a != 0 && f > Cf2 || a <= 0 && f < -Cf2 // ERROR "Redirect Leq32U based on Neq32$" + return a != 2 && f > Cf2 || a <= 2 && f < -Cf2 // ERROR "Redirect Leq32U based on Neq32$" } func fLessEq(a int, f float64) bool { @@ -110,11 +110,11 @@ func fLessULeqU(a uint64, f float64) bool { } func fLeqUEq(a uint8, f float64) bool { - return a <= 0 && f > Cf2 || a == 0 && f < -Cf2 // ERROR "Redirect Eq8 based on Leq8U$" + return a <= 2 && f > Cf2 || a == 2 && f < -Cf2 // ERROR "Redirect Eq8 based on Leq8U$" } func fLeqUNeq(a uint16, f float64) bool { - return a <= 0 && f > Cf2 || a != 0 && f < -Cf2 // ERROR "Redirect Neq16 based on Leq16U$" + return a <= 2 && f > Cf2 || a != 2 && f < -Cf2 // ERROR "Redirect Neq16 based on Leq16U$" } func fLeqLessU(a uint32, f float64) bool { @@ -122,7 +122,7 @@ func fLeqLessU(a uint32, f float64) bool { } func fLeqLeqU(a uint64, f float64) bool { - return a <= 0 && f > Cf2 || a <= 0 && f < -Cf2 // ERROR "Redirect Leq64U based on Leq64U$" + return a <= 2 && f > Cf2 || a <= 2 && f < -Cf2 // ERROR "Redirect Leq64U based on Leq64U$" } // Arg tests are disabled because the op name is different on amd64 and arm64. diff --git a/test/prove.go b/test/prove.go index 1aea2822912c27..0d93db905ae871 100644 --- a/test/prove.go +++ b/test/prove.go @@ -396,8 +396,11 @@ func f13e(a int) int { return 0 } -func f13f(a int64) int64 { - if a > math.MaxInt64 { +func f13f(a, b int64) int64 { + if b != math.MaxInt64 { + return 42 + } + if a > b { if a == 0 { // ERROR "Disproved Eq64$" return 1 } @@ -869,9 +872,12 @@ func unrollInclStepTooLarge(a []int) int { } // Not an induction variable (min too small, iterating down) -func unrollDecMin(a []int) int { +func unrollDecMin(a []int, b int) int { + if b != math.MinInt64 { + return 42 + } var i, x int - for i = len(a); i >= math.MinInt64; i -= 2 { + for i = len(a); i >= b; i -= 2 { x += a[i-1] x += a[i-2] } @@ -882,9 +888,12 @@ func unrollDecMin(a []int) int { } // Not an induction variable (min too small, iterating up -- perhaps could allow, but why bother?) -func unrollIncMin(a []int) int { +func unrollIncMin(a []int, b int) int { + if b != math.MinInt64 { + return 42 + } var i, x int - for i = len(a); i >= math.MinInt64; i += 2 { + for i = len(a); i >= b; i += 2 { x += a[i-1] x += a[i-2] }