From d556c251a1f1506f68e1e4064c3537948ff667a3 Mon Sep 17 00:00:00 2001 From: fanzha02 Date: Thu, 28 May 2020 18:11:52 +0800 Subject: [PATCH] cmd/compile: add more generic rewrite rules to reassociate (op (op y C) x|C) With this patch, opt pass can expose more obvious constant-folding opportunites. Example: func test(i int) int {return (i+8)-(i+4)} The previous version: MOVD "".i(FP), R0 ADD $8, R0, R1 ADD $4, R0, R0 SUB R0, R1, R0 MOVD R0, "".~r1+8(FP) RET (R30) The optimized version: MOVD $4, R0 MOVD R0, "".~r1+8(FP) RET (R30) This patch removes some existing reassociation rules, such as "x+(z-C)", because the current generic rewrite rules will canonicalize "x-const" to "x+(-const)", making "x+(z-C)" equal to "x+(z+(-C))". This patch also adds test cases. Change-Id: I857108ba0b5fcc18a879eeab38e2551bc4277797 Reviewed-on: https://go-review.googlesource.com/c/go/+/237137 Run-TryBot: Keith Randall TryBot-Result: Gobot Gobot Reviewed-by: Keith Randall --- .../compile/internal/ssa/gen/generic.rules | 54 +- .../compile/internal/ssa/rewritegeneric.go | 816 +++++++++++------- test/codegen/arithmetic.go | 31 +- 3 files changed, 545 insertions(+), 356 deletions(-) diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index 2d39d27226..f7e6bbebac 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -1807,6 +1807,8 @@ // invariant that pointers must stay within the pointed-to object, // we can't pull part of a pointer computation above the AddPtr. // See issue 37881. +// Note: we don't need to handle any (x-C) cases because we already rewrite +// (x-C) to (x+(-C)). // x + (C + z) -> C + (x + z) (Add64 (Add64 i:(Const64 ) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) => (Add64 i (Add64 z x)) @@ -1820,23 +1822,29 @@ (Add16 (Sub16 i:(Const16 ) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) => (Add16 i (Sub16 x z)) (Add8 (Sub8 i:(Const8 ) z) x) && (z.Op != OpConst8 && x.Op != OpConst8) => (Add8 i (Sub8 x z)) -// x + (z - C) -> (x + z) - C -(Add64 (Sub64 z i:(Const64 )) x) && (z.Op != OpConst64 && x.Op != OpConst64) => (Sub64 (Add64 x z) i) -(Add32 (Sub32 z i:(Const32 )) x) && (z.Op != OpConst32 && x.Op != OpConst32) => (Sub32 (Add32 x z) i) -(Add16 (Sub16 z i:(Const16 )) x) && (z.Op != OpConst16 && x.Op != OpConst16) => (Sub16 (Add16 x z) i) -(Add8 (Sub8 z i:(Const8 )) x) && (z.Op != OpConst8 && x.Op != OpConst8) => (Sub8 (Add8 x z) i) - // x - (C - z) -> x + (z - C) -> (x + z) - C (Sub64 x (Sub64 i:(Const64 ) z)) && (z.Op != OpConst64 && x.Op != OpConst64) => (Sub64 (Add64 x z) i) (Sub32 x (Sub32 i:(Const32 ) z)) && (z.Op != OpConst32 && x.Op != OpConst32) => (Sub32 (Add32 x z) i) (Sub16 x (Sub16 i:(Const16 ) z)) && (z.Op != OpConst16 && x.Op != OpConst16) => (Sub16 (Add16 x z) i) (Sub8 x (Sub8 i:(Const8 ) z)) && (z.Op != OpConst8 && x.Op != OpConst8) => (Sub8 (Add8 x z) i) -// x - (z - C) -> x + (C - z) -> (x - z) + C -(Sub64 x (Sub64 z i:(Const64 ))) && (z.Op != OpConst64 && x.Op != OpConst64) => (Add64 i (Sub64 x z)) -(Sub32 x (Sub32 z i:(Const32 ))) && (z.Op != OpConst32 && x.Op != OpConst32) => (Add32 i (Sub32 x z)) -(Sub16 x (Sub16 z i:(Const16 ))) && (z.Op != OpConst16 && x.Op != OpConst16) => (Add16 i (Sub16 x z)) -(Sub8 x (Sub8 z i:(Const8 ))) && (z.Op != OpConst8 && x.Op != OpConst8) => (Add8 i (Sub8 x z)) +// x - (z + C) -> x + (-z - C) -> (x - z) - C +(Sub64 x (Add64 z i:(Const64 ))) && (z.Op != OpConst64 && x.Op != OpConst64) => (Sub64 (Sub64 x z) i) +(Sub32 x (Add32 z i:(Const32 ))) && (z.Op != OpConst32 && x.Op != OpConst32) => (Sub32 (Sub32 x z) i) +(Sub16 x (Add16 z i:(Const16 ))) && (z.Op != OpConst16 && x.Op != OpConst16) => (Sub16 (Sub16 x z) i) +(Sub8 x (Add8 z i:(Const8 ))) && (z.Op != OpConst8 && x.Op != OpConst8) => (Sub8 (Sub8 x z) i) + +// (C - z) - x -> C - (z + x) +(Sub64 (Sub64 i:(Const64 ) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) => (Sub64 i (Add64 z x)) +(Sub32 (Sub32 i:(Const32 ) z) x) && (z.Op != OpConst32 && x.Op != OpConst32) => (Sub32 i (Add32 z x)) +(Sub16 (Sub16 i:(Const16 ) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) => (Sub16 i (Add16 z x)) +(Sub8 (Sub8 i:(Const8 ) z) x) && (z.Op != OpConst8 && x.Op != OpConst8) => (Sub8 i (Add8 z x)) + +// (z + C) -x -> C + (z - x) +(Sub64 (Add64 z i:(Const64 )) x) && (z.Op != OpConst64 && x.Op != OpConst64) => (Add64 i (Sub64 z x)) +(Sub32 (Add32 z i:(Const32 )) x) && (z.Op != OpConst32 && x.Op != OpConst32) => (Add32 i (Sub32 z x)) +(Sub16 (Add16 z i:(Const16 )) x) && (z.Op != OpConst16 && x.Op != OpConst16) => (Add16 i (Sub16 z x)) +(Sub8 (Add8 z i:(Const8 )) x) && (z.Op != OpConst8 && x.Op != OpConst8) => (Add8 i (Sub8 z x)) // x & (C & z) -> C & (x & z) (And64 (And64 i:(Const64 ) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) => (And64 i (And64 z x)) @@ -1856,6 +1864,12 @@ (Xor16 (Xor16 i:(Const16 ) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) => (Xor16 i (Xor16 z x)) (Xor8 (Xor8 i:(Const8 ) z) x) && (z.Op != OpConst8 && x.Op != OpConst8) => (Xor8 i (Xor8 z x)) +// x * (D * z) = D * (x * z) +(Mul64 (Mul64 i:(Const64 ) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) => (Mul64 i (Mul64 x z)) +(Mul32 (Mul32 i:(Const32 ) z) x) && (z.Op != OpConst32 && x.Op != OpConst32) => (Mul32 i (Mul32 x z)) +(Mul16 (Mul16 i:(Const16 ) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) => (Mul16 i (Mul16 x z)) +(Mul8 (Mul8 i:(Const8 ) z) x) && (z.Op != OpConst8 && x.Op != OpConst8) => (Mul8 i (Mul8 x z)) + // C + (D + x) -> (C + D) + x (Add64 (Const64 [c]) (Add64 (Const64 [d]) x)) => (Add64 (Const64 [c+d]) x) (Add32 (Const32 [c]) (Add32 (Const32 [d]) x)) => (Add32 (Const32 [c+d]) x) @@ -1868,24 +1882,18 @@ (Add16 (Const16 [c]) (Sub16 (Const16 [d]) x)) => (Sub16 (Const16 [c+d]) x) (Add8 (Const8 [c]) (Sub8 (Const8 [d]) x)) => (Sub8 (Const8 [c+d]) x) -// C + (x - D) -> (C - D) + x -(Add64 (Const64 [c]) (Sub64 x (Const64 [d]))) => (Add64 (Const64 [c-d]) x) -(Add32 (Const32 [c]) (Sub32 x (Const32 [d]))) => (Add32 (Const32 [c-d]) x) -(Add16 (Const16 [c]) (Sub16 x (Const16 [d]))) => (Add16 (Const16 [c-d]) x) -(Add8 (Const8 [c]) (Sub8 x (Const8 [d]))) => (Add8 (Const8 [c-d]) x) - -// C - (x - D) -> (C + D) - x -(Sub64 (Const64 [c]) (Sub64 x (Const64 [d]))) => (Sub64 (Const64 [c+d]) x) -(Sub32 (Const32 [c]) (Sub32 x (Const32 [d]))) => (Sub32 (Const32 [c+d]) x) -(Sub16 (Const16 [c]) (Sub16 x (Const16 [d]))) => (Sub16 (Const16 [c+d]) x) -(Sub8 (Const8 [c]) (Sub8 x (Const8 [d]))) => (Sub8 (Const8 [c+d]) x) - // C - (D - x) -> (C - D) + x (Sub64 (Const64 [c]) (Sub64 (Const64 [d]) x)) => (Add64 (Const64 [c-d]) x) (Sub32 (Const32 [c]) (Sub32 (Const32 [d]) x)) => (Add32 (Const32 [c-d]) x) (Sub16 (Const16 [c]) (Sub16 (Const16 [d]) x)) => (Add16 (Const16 [c-d]) x) (Sub8 (Const8 [c]) (Sub8 (Const8 [d]) x)) => (Add8 (Const8 [c-d]) x) +// C - (D + x) -> (C - D) - x +(Sub64 (Const64 [c]) (Add64 (Const64 [d]) x)) => (Sub64 (Const64 [c-d]) x) +(Sub32 (Const32 [c]) (Add32 (Const32 [d]) x)) => (Sub32 (Const32 [c-d]) x) +(Sub16 (Const16 [c]) (Add16 (Const16 [d]) x)) => (Sub16 (Const16 [c-d]) x) +(Sub8 (Const8 [c]) (Add8 (Const8 [d]) x)) => (Sub8 (Const8 [c-d]) x) + // C & (D & x) -> (C & D) & x (And64 (Const64 [c]) (And64 (Const64 [d]) x)) => (And64 (Const64 [c&d]) x) (And32 (Const32 [c]) (And32 (Const32 [d]) x)) => (And32 (Const32 [c&d]) x) diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 68e49f46f3..180e48b34c 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -588,33 +588,6 @@ func rewriteValuegeneric_OpAdd16(v *Value) bool { } break } - // match: (Add16 (Sub16 z i:(Const16 )) x) - // cond: (z.Op != OpConst16 && x.Op != OpConst16) - // result: (Sub16 (Add16 x z) i) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != OpSub16 { - continue - } - _ = v_0.Args[1] - z := v_0.Args[0] - i := v_0.Args[1] - if i.Op != OpConst16 { - continue - } - t := i.Type - x := v_1 - if !(z.Op != OpConst16 && x.Op != OpConst16) { - continue - } - v.reset(OpSub16) - v0 := b.NewValue0(v.Pos, OpAdd16, t) - v0.AddArg2(x, z) - v.AddArg2(v0, i) - return true - } - break - } // match: (Add16 (Const16 [c]) (Add16 (Const16 [d]) x)) // result: (Add16 (Const16 [c+d]) x) for { @@ -671,33 +644,6 @@ func rewriteValuegeneric_OpAdd16(v *Value) bool { } break } - // match: (Add16 (Const16 [c]) (Sub16 x (Const16 [d]))) - // result: (Add16 (Const16 [c-d]) x) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != OpConst16 { - continue - } - t := v_0.Type - c := auxIntToInt16(v_0.AuxInt) - if v_1.Op != OpSub16 { - continue - } - _ = v_1.Args[1] - x := v_1.Args[0] - v_1_1 := v_1.Args[1] - if v_1_1.Op != OpConst16 || v_1_1.Type != t { - continue - } - d := auxIntToInt16(v_1_1.AuxInt) - v.reset(OpAdd16) - v0 := b.NewValue0(v.Pos, OpConst16, t) - v0.AuxInt = int16ToAuxInt(c - d) - v.AddArg2(v0, x) - return true - } - break - } return false } func rewriteValuegeneric_OpAdd32(v *Value) bool { @@ -841,33 +787,6 @@ func rewriteValuegeneric_OpAdd32(v *Value) bool { } break } - // match: (Add32 (Sub32 z i:(Const32 )) x) - // cond: (z.Op != OpConst32 && x.Op != OpConst32) - // result: (Sub32 (Add32 x z) i) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != OpSub32 { - continue - } - _ = v_0.Args[1] - z := v_0.Args[0] - i := v_0.Args[1] - if i.Op != OpConst32 { - continue - } - t := i.Type - x := v_1 - if !(z.Op != OpConst32 && x.Op != OpConst32) { - continue - } - v.reset(OpSub32) - v0 := b.NewValue0(v.Pos, OpAdd32, t) - v0.AddArg2(x, z) - v.AddArg2(v0, i) - return true - } - break - } // match: (Add32 (Const32 [c]) (Add32 (Const32 [d]) x)) // result: (Add32 (Const32 [c+d]) x) for { @@ -924,33 +843,6 @@ func rewriteValuegeneric_OpAdd32(v *Value) bool { } break } - // match: (Add32 (Const32 [c]) (Sub32 x (Const32 [d]))) - // result: (Add32 (Const32 [c-d]) x) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != OpConst32 { - continue - } - t := v_0.Type - c := auxIntToInt32(v_0.AuxInt) - if v_1.Op != OpSub32 { - continue - } - _ = v_1.Args[1] - x := v_1.Args[0] - v_1_1 := v_1.Args[1] - if v_1_1.Op != OpConst32 || v_1_1.Type != t { - continue - } - d := auxIntToInt32(v_1_1.AuxInt) - v.reset(OpAdd32) - v0 := b.NewValue0(v.Pos, OpConst32, t) - v0.AuxInt = int32ToAuxInt(c - d) - v.AddArg2(v0, x) - return true - } - break - } return false } func rewriteValuegeneric_OpAdd32F(v *Value) bool { @@ -1121,33 +1013,6 @@ func rewriteValuegeneric_OpAdd64(v *Value) bool { } break } - // match: (Add64 (Sub64 z i:(Const64 )) x) - // cond: (z.Op != OpConst64 && x.Op != OpConst64) - // result: (Sub64 (Add64 x z) i) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != OpSub64 { - continue - } - _ = v_0.Args[1] - z := v_0.Args[0] - i := v_0.Args[1] - if i.Op != OpConst64 { - continue - } - t := i.Type - x := v_1 - if !(z.Op != OpConst64 && x.Op != OpConst64) { - continue - } - v.reset(OpSub64) - v0 := b.NewValue0(v.Pos, OpAdd64, t) - v0.AddArg2(x, z) - v.AddArg2(v0, i) - return true - } - break - } // match: (Add64 (Const64 [c]) (Add64 (Const64 [d]) x)) // result: (Add64 (Const64 [c+d]) x) for { @@ -1204,33 +1069,6 @@ func rewriteValuegeneric_OpAdd64(v *Value) bool { } break } - // match: (Add64 (Const64 [c]) (Sub64 x (Const64 [d]))) - // result: (Add64 (Const64 [c-d]) x) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != OpConst64 { - continue - } - t := v_0.Type - c := auxIntToInt64(v_0.AuxInt) - if v_1.Op != OpSub64 { - continue - } - _ = v_1.Args[1] - x := v_1.Args[0] - v_1_1 := v_1.Args[1] - if v_1_1.Op != OpConst64 || v_1_1.Type != t { - continue - } - d := auxIntToInt64(v_1_1.AuxInt) - v.reset(OpAdd64) - v0 := b.NewValue0(v.Pos, OpConst64, t) - v0.AuxInt = int64ToAuxInt(c - d) - v.AddArg2(v0, x) - return true - } - break - } return false } func rewriteValuegeneric_OpAdd64F(v *Value) bool { @@ -1401,33 +1239,6 @@ func rewriteValuegeneric_OpAdd8(v *Value) bool { } break } - // match: (Add8 (Sub8 z i:(Const8 )) x) - // cond: (z.Op != OpConst8 && x.Op != OpConst8) - // result: (Sub8 (Add8 x z) i) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != OpSub8 { - continue - } - _ = v_0.Args[1] - z := v_0.Args[0] - i := v_0.Args[1] - if i.Op != OpConst8 { - continue - } - t := i.Type - x := v_1 - if !(z.Op != OpConst8 && x.Op != OpConst8) { - continue - } - v.reset(OpSub8) - v0 := b.NewValue0(v.Pos, OpAdd8, t) - v0.AddArg2(x, z) - v.AddArg2(v0, i) - return true - } - break - } // match: (Add8 (Const8 [c]) (Add8 (Const8 [d]) x)) // result: (Add8 (Const8 [c+d]) x) for { @@ -1484,33 +1295,6 @@ func rewriteValuegeneric_OpAdd8(v *Value) bool { } break } - // match: (Add8 (Const8 [c]) (Sub8 x (Const8 [d]))) - // result: (Add8 (Const8 [c-d]) x) - for { - for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != OpConst8 { - continue - } - t := v_0.Type - c := auxIntToInt8(v_0.AuxInt) - if v_1.Op != OpSub8 { - continue - } - _ = v_1.Args[1] - x := v_1.Args[0] - v_1_1 := v_1.Args[1] - if v_1_1.Op != OpConst8 || v_1_1.Type != t { - continue - } - d := auxIntToInt8(v_1_1.AuxInt) - v.reset(OpAdd8) - v0 := b.NewValue0(v.Pos, OpConst8, t) - v0.AuxInt = int8ToAuxInt(c - d) - v.AddArg2(v0, x) - return true - } - break - } return false } func rewriteValuegeneric_OpAddPtr(v *Value) bool { @@ -13922,6 +13706,37 @@ func rewriteValuegeneric_OpMul16(v *Value) bool { } break } + // match: (Mul16 (Mul16 i:(Const16 ) z) x) + // cond: (z.Op != OpConst16 && x.Op != OpConst16) + // result: (Mul16 i (Mul16 x z)) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + if v_0.Op != OpMul16 { + continue + } + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + v_0_1 := v_0.Args[1] + for _i1 := 0; _i1 <= 1; _i1, v_0_0, v_0_1 = _i1+1, v_0_1, v_0_0 { + i := v_0_0 + if i.Op != OpConst16 { + continue + } + t := i.Type + z := v_0_1 + x := v_1 + if !(z.Op != OpConst16 && x.Op != OpConst16) { + continue + } + v.reset(OpMul16) + v0 := b.NewValue0(v.Pos, OpMul16, t) + v0.AddArg2(x, z) + v.AddArg2(i, v0) + return true + } + } + break + } // match: (Mul16 (Const16 [c]) (Mul16 (Const16 [d]) x)) // result: (Mul16 (Const16 [c*d]) x) for { @@ -14098,6 +13913,37 @@ func rewriteValuegeneric_OpMul32(v *Value) bool { } break } + // match: (Mul32 (Mul32 i:(Const32 ) z) x) + // cond: (z.Op != OpConst32 && x.Op != OpConst32) + // result: (Mul32 i (Mul32 x z)) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + if v_0.Op != OpMul32 { + continue + } + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + v_0_1 := v_0.Args[1] + for _i1 := 0; _i1 <= 1; _i1, v_0_0, v_0_1 = _i1+1, v_0_1, v_0_0 { + i := v_0_0 + if i.Op != OpConst32 { + continue + } + t := i.Type + z := v_0_1 + x := v_1 + if !(z.Op != OpConst32 && x.Op != OpConst32) { + continue + } + v.reset(OpMul32) + v0 := b.NewValue0(v.Pos, OpMul32, t) + v0.AddArg2(x, z) + v.AddArg2(i, v0) + return true + } + } + break + } // match: (Mul32 (Const32 [c]) (Mul32 (Const32 [d]) x)) // result: (Mul32 (Const32 [c*d]) x) for { @@ -14342,16 +14188,47 @@ func rewriteValuegeneric_OpMul64(v *Value) bool { } break } - // match: (Mul64 (Const64 [c]) (Mul64 (Const64 [d]) x)) - // result: (Mul64 (Const64 [c*d]) x) + // match: (Mul64 (Mul64 i:(Const64 ) z) x) + // cond: (z.Op != OpConst64 && x.Op != OpConst64) + // result: (Mul64 i (Mul64 x z)) for { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { - if v_0.Op != OpConst64 { - continue - } - t := v_0.Type - c := auxIntToInt64(v_0.AuxInt) - if v_1.Op != OpMul64 { + if v_0.Op != OpMul64 { + continue + } + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + v_0_1 := v_0.Args[1] + for _i1 := 0; _i1 <= 1; _i1, v_0_0, v_0_1 = _i1+1, v_0_1, v_0_0 { + i := v_0_0 + if i.Op != OpConst64 { + continue + } + t := i.Type + z := v_0_1 + x := v_1 + if !(z.Op != OpConst64 && x.Op != OpConst64) { + continue + } + v.reset(OpMul64) + v0 := b.NewValue0(v.Pos, OpMul64, t) + v0.AddArg2(x, z) + v.AddArg2(i, v0) + return true + } + } + break + } + // match: (Mul64 (Const64 [c]) (Mul64 (Const64 [d]) x)) + // result: (Mul64 (Const64 [c*d]) x) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + if v_0.Op != OpConst64 { + continue + } + t := v_0.Type + c := auxIntToInt64(v_0.AuxInt) + if v_1.Op != OpMul64 { continue } _ = v_1.Args[1] @@ -14552,6 +14429,37 @@ func rewriteValuegeneric_OpMul8(v *Value) bool { } break } + // match: (Mul8 (Mul8 i:(Const8 ) z) x) + // cond: (z.Op != OpConst8 && x.Op != OpConst8) + // result: (Mul8 i (Mul8 x z)) + for { + for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { + if v_0.Op != OpMul8 { + continue + } + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + v_0_1 := v_0.Args[1] + for _i1 := 0; _i1 <= 1; _i1, v_0_0, v_0_1 = _i1+1, v_0_1, v_0_0 { + i := v_0_0 + if i.Op != OpConst8 { + continue + } + t := i.Type + z := v_0_1 + x := v_1 + if !(z.Op != OpConst8 && x.Op != OpConst8) { + continue + } + v.reset(OpMul8) + v0 := b.NewValue0(v.Pos, OpMul8, t) + v0.AddArg2(x, z) + v.AddArg2(i, v0) + return true + } + } + break + } // match: (Mul8 (Const8 [c]) (Mul8 (Const8 [d]) x)) // result: (Mul8 (Const8 [c*d]) x) for { @@ -22432,53 +22340,86 @@ func rewriteValuegeneric_OpSub16(v *Value) bool { v.AddArg2(v0, i) return true } - // match: (Sub16 x (Sub16 z i:(Const16 ))) + // match: (Sub16 x (Add16 z i:(Const16 ))) // cond: (z.Op != OpConst16 && x.Op != OpConst16) - // result: (Add16 i (Sub16 x z)) + // result: (Sub16 (Sub16 x z) i) for { x := v_0 - if v_1.Op != OpSub16 { + if v_1.Op != OpAdd16 { break } _ = v_1.Args[1] - z := v_1.Args[0] - i := v_1.Args[1] + v_1_0 := v_1.Args[0] + v_1_1 := v_1.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 { + z := v_1_0 + i := v_1_1 + if i.Op != OpConst16 { + continue + } + t := i.Type + if !(z.Op != OpConst16 && x.Op != OpConst16) { + continue + } + v.reset(OpSub16) + v0 := b.NewValue0(v.Pos, OpSub16, t) + v0.AddArg2(x, z) + v.AddArg2(v0, i) + return true + } + break + } + // match: (Sub16 (Sub16 i:(Const16 ) z) x) + // cond: (z.Op != OpConst16 && x.Op != OpConst16) + // result: (Sub16 i (Add16 z x)) + for { + if v_0.Op != OpSub16 { + break + } + z := v_0.Args[1] + i := v_0.Args[0] if i.Op != OpConst16 { break } t := i.Type + x := v_1 if !(z.Op != OpConst16 && x.Op != OpConst16) { break } - v.reset(OpAdd16) - v0 := b.NewValue0(v.Pos, OpSub16, t) - v0.AddArg2(x, z) + v.reset(OpSub16) + v0 := b.NewValue0(v.Pos, OpAdd16, t) + v0.AddArg2(z, x) v.AddArg2(i, v0) return true } - // match: (Sub16 (Const16 [c]) (Sub16 x (Const16 [d]))) - // result: (Sub16 (Const16 [c+d]) x) + // match: (Sub16 (Add16 z i:(Const16 )) x) + // cond: (z.Op != OpConst16 && x.Op != OpConst16) + // result: (Add16 i (Sub16 z x)) for { - if v_0.Op != OpConst16 { - break - } - t := v_0.Type - c := auxIntToInt16(v_0.AuxInt) - if v_1.Op != OpSub16 { + if v_0.Op != OpAdd16 { break } - _ = v_1.Args[1] - x := v_1.Args[0] - v_1_1 := v_1.Args[1] - if v_1_1.Op != OpConst16 || v_1_1.Type != t { - break + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + v_0_1 := v_0.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { + z := v_0_0 + i := v_0_1 + if i.Op != OpConst16 { + continue + } + t := i.Type + x := v_1 + if !(z.Op != OpConst16 && x.Op != OpConst16) { + continue + } + v.reset(OpAdd16) + v0 := b.NewValue0(v.Pos, OpSub16, t) + v0.AddArg2(z, x) + v.AddArg2(i, v0) + return true } - d := auxIntToInt16(v_1_1.AuxInt) - v.reset(OpSub16) - v0 := b.NewValue0(v.Pos, OpConst16, t) - v0.AuxInt = int16ToAuxInt(c + d) - v.AddArg2(v0, x) - return true + break } // match: (Sub16 (Const16 [c]) (Sub16 (Const16 [d]) x)) // result: (Add16 (Const16 [c-d]) x) @@ -22503,6 +22444,34 @@ func rewriteValuegeneric_OpSub16(v *Value) bool { v.AddArg2(v0, x) return true } + // match: (Sub16 (Const16 [c]) (Add16 (Const16 [d]) x)) + // result: (Sub16 (Const16 [c-d]) x) + for { + if v_0.Op != OpConst16 { + break + } + t := v_0.Type + c := auxIntToInt16(v_0.AuxInt) + if v_1.Op != OpAdd16 { + break + } + _ = v_1.Args[1] + v_1_0 := v_1.Args[0] + v_1_1 := v_1.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 { + if v_1_0.Op != OpConst16 || v_1_0.Type != t { + continue + } + d := auxIntToInt16(v_1_0.AuxInt) + x := v_1_1 + v.reset(OpSub16) + v0 := b.NewValue0(v.Pos, OpConst16, t) + v0.AuxInt = int16ToAuxInt(c - d) + v.AddArg2(v0, x) + return true + } + break + } return false } func rewriteValuegeneric_OpSub32(v *Value) bool { @@ -22650,53 +22619,86 @@ func rewriteValuegeneric_OpSub32(v *Value) bool { v.AddArg2(v0, i) return true } - // match: (Sub32 x (Sub32 z i:(Const32 ))) + // match: (Sub32 x (Add32 z i:(Const32 ))) // cond: (z.Op != OpConst32 && x.Op != OpConst32) - // result: (Add32 i (Sub32 x z)) + // result: (Sub32 (Sub32 x z) i) for { x := v_0 - if v_1.Op != OpSub32 { + if v_1.Op != OpAdd32 { break } _ = v_1.Args[1] - z := v_1.Args[0] - i := v_1.Args[1] + v_1_0 := v_1.Args[0] + v_1_1 := v_1.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 { + z := v_1_0 + i := v_1_1 + if i.Op != OpConst32 { + continue + } + t := i.Type + if !(z.Op != OpConst32 && x.Op != OpConst32) { + continue + } + v.reset(OpSub32) + v0 := b.NewValue0(v.Pos, OpSub32, t) + v0.AddArg2(x, z) + v.AddArg2(v0, i) + return true + } + break + } + // match: (Sub32 (Sub32 i:(Const32 ) z) x) + // cond: (z.Op != OpConst32 && x.Op != OpConst32) + // result: (Sub32 i (Add32 z x)) + for { + if v_0.Op != OpSub32 { + break + } + z := v_0.Args[1] + i := v_0.Args[0] if i.Op != OpConst32 { break } t := i.Type + x := v_1 if !(z.Op != OpConst32 && x.Op != OpConst32) { break } - v.reset(OpAdd32) - v0 := b.NewValue0(v.Pos, OpSub32, t) - v0.AddArg2(x, z) + v.reset(OpSub32) + v0 := b.NewValue0(v.Pos, OpAdd32, t) + v0.AddArg2(z, x) v.AddArg2(i, v0) return true } - // match: (Sub32 (Const32 [c]) (Sub32 x (Const32 [d]))) - // result: (Sub32 (Const32 [c+d]) x) + // match: (Sub32 (Add32 z i:(Const32 )) x) + // cond: (z.Op != OpConst32 && x.Op != OpConst32) + // result: (Add32 i (Sub32 z x)) for { - if v_0.Op != OpConst32 { - break - } - t := v_0.Type - c := auxIntToInt32(v_0.AuxInt) - if v_1.Op != OpSub32 { + if v_0.Op != OpAdd32 { break } - _ = v_1.Args[1] - x := v_1.Args[0] - v_1_1 := v_1.Args[1] - if v_1_1.Op != OpConst32 || v_1_1.Type != t { - break + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + v_0_1 := v_0.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { + z := v_0_0 + i := v_0_1 + if i.Op != OpConst32 { + continue + } + t := i.Type + x := v_1 + if !(z.Op != OpConst32 && x.Op != OpConst32) { + continue + } + v.reset(OpAdd32) + v0 := b.NewValue0(v.Pos, OpSub32, t) + v0.AddArg2(z, x) + v.AddArg2(i, v0) + return true } - d := auxIntToInt32(v_1_1.AuxInt) - v.reset(OpSub32) - v0 := b.NewValue0(v.Pos, OpConst32, t) - v0.AuxInt = int32ToAuxInt(c + d) - v.AddArg2(v0, x) - return true + break } // match: (Sub32 (Const32 [c]) (Sub32 (Const32 [d]) x)) // result: (Add32 (Const32 [c-d]) x) @@ -22721,6 +22723,34 @@ func rewriteValuegeneric_OpSub32(v *Value) bool { v.AddArg2(v0, x) return true } + // match: (Sub32 (Const32 [c]) (Add32 (Const32 [d]) x)) + // result: (Sub32 (Const32 [c-d]) x) + for { + if v_0.Op != OpConst32 { + break + } + t := v_0.Type + c := auxIntToInt32(v_0.AuxInt) + if v_1.Op != OpAdd32 { + break + } + _ = v_1.Args[1] + v_1_0 := v_1.Args[0] + v_1_1 := v_1.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 { + if v_1_0.Op != OpConst32 || v_1_0.Type != t { + continue + } + d := auxIntToInt32(v_1_0.AuxInt) + x := v_1_1 + v.reset(OpSub32) + v0 := b.NewValue0(v.Pos, OpConst32, t) + v0.AuxInt = int32ToAuxInt(c - d) + v.AddArg2(v0, x) + return true + } + break + } return false } func rewriteValuegeneric_OpSub32F(v *Value) bool { @@ -22892,53 +22922,86 @@ func rewriteValuegeneric_OpSub64(v *Value) bool { v.AddArg2(v0, i) return true } - // match: (Sub64 x (Sub64 z i:(Const64 ))) + // match: (Sub64 x (Add64 z i:(Const64 ))) // cond: (z.Op != OpConst64 && x.Op != OpConst64) - // result: (Add64 i (Sub64 x z)) + // result: (Sub64 (Sub64 x z) i) for { x := v_0 - if v_1.Op != OpSub64 { + if v_1.Op != OpAdd64 { break } _ = v_1.Args[1] - z := v_1.Args[0] - i := v_1.Args[1] + v_1_0 := v_1.Args[0] + v_1_1 := v_1.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 { + z := v_1_0 + i := v_1_1 + if i.Op != OpConst64 { + continue + } + t := i.Type + if !(z.Op != OpConst64 && x.Op != OpConst64) { + continue + } + v.reset(OpSub64) + v0 := b.NewValue0(v.Pos, OpSub64, t) + v0.AddArg2(x, z) + v.AddArg2(v0, i) + return true + } + break + } + // match: (Sub64 (Sub64 i:(Const64 ) z) x) + // cond: (z.Op != OpConst64 && x.Op != OpConst64) + // result: (Sub64 i (Add64 z x)) + for { + if v_0.Op != OpSub64 { + break + } + z := v_0.Args[1] + i := v_0.Args[0] if i.Op != OpConst64 { break } t := i.Type + x := v_1 if !(z.Op != OpConst64 && x.Op != OpConst64) { break } - v.reset(OpAdd64) - v0 := b.NewValue0(v.Pos, OpSub64, t) - v0.AddArg2(x, z) + v.reset(OpSub64) + v0 := b.NewValue0(v.Pos, OpAdd64, t) + v0.AddArg2(z, x) v.AddArg2(i, v0) return true } - // match: (Sub64 (Const64 [c]) (Sub64 x (Const64 [d]))) - // result: (Sub64 (Const64 [c+d]) x) + // match: (Sub64 (Add64 z i:(Const64 )) x) + // cond: (z.Op != OpConst64 && x.Op != OpConst64) + // result: (Add64 i (Sub64 z x)) for { - if v_0.Op != OpConst64 { - break - } - t := v_0.Type - c := auxIntToInt64(v_0.AuxInt) - if v_1.Op != OpSub64 { + if v_0.Op != OpAdd64 { break } - _ = v_1.Args[1] - x := v_1.Args[0] - v_1_1 := v_1.Args[1] - if v_1_1.Op != OpConst64 || v_1_1.Type != t { - break + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + v_0_1 := v_0.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { + z := v_0_0 + i := v_0_1 + if i.Op != OpConst64 { + continue + } + t := i.Type + x := v_1 + if !(z.Op != OpConst64 && x.Op != OpConst64) { + continue + } + v.reset(OpAdd64) + v0 := b.NewValue0(v.Pos, OpSub64, t) + v0.AddArg2(z, x) + v.AddArg2(i, v0) + return true } - d := auxIntToInt64(v_1_1.AuxInt) - v.reset(OpSub64) - v0 := b.NewValue0(v.Pos, OpConst64, t) - v0.AuxInt = int64ToAuxInt(c + d) - v.AddArg2(v0, x) - return true + break } // match: (Sub64 (Const64 [c]) (Sub64 (Const64 [d]) x)) // result: (Add64 (Const64 [c-d]) x) @@ -22963,6 +23026,34 @@ func rewriteValuegeneric_OpSub64(v *Value) bool { v.AddArg2(v0, x) return true } + // match: (Sub64 (Const64 [c]) (Add64 (Const64 [d]) x)) + // result: (Sub64 (Const64 [c-d]) x) + for { + if v_0.Op != OpConst64 { + break + } + t := v_0.Type + c := auxIntToInt64(v_0.AuxInt) + if v_1.Op != OpAdd64 { + break + } + _ = v_1.Args[1] + v_1_0 := v_1.Args[0] + v_1_1 := v_1.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 { + if v_1_0.Op != OpConst64 || v_1_0.Type != t { + continue + } + d := auxIntToInt64(v_1_0.AuxInt) + x := v_1_1 + v.reset(OpSub64) + v0 := b.NewValue0(v.Pos, OpConst64, t) + v0.AuxInt = int64ToAuxInt(c - d) + v.AddArg2(v0, x) + return true + } + break + } return false } func rewriteValuegeneric_OpSub64F(v *Value) bool { @@ -23134,53 +23225,86 @@ func rewriteValuegeneric_OpSub8(v *Value) bool { v.AddArg2(v0, i) return true } - // match: (Sub8 x (Sub8 z i:(Const8 ))) + // match: (Sub8 x (Add8 z i:(Const8 ))) // cond: (z.Op != OpConst8 && x.Op != OpConst8) - // result: (Add8 i (Sub8 x z)) + // result: (Sub8 (Sub8 x z) i) for { x := v_0 - if v_1.Op != OpSub8 { + if v_1.Op != OpAdd8 { break } _ = v_1.Args[1] - z := v_1.Args[0] - i := v_1.Args[1] + v_1_0 := v_1.Args[0] + v_1_1 := v_1.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 { + z := v_1_0 + i := v_1_1 + if i.Op != OpConst8 { + continue + } + t := i.Type + if !(z.Op != OpConst8 && x.Op != OpConst8) { + continue + } + v.reset(OpSub8) + v0 := b.NewValue0(v.Pos, OpSub8, t) + v0.AddArg2(x, z) + v.AddArg2(v0, i) + return true + } + break + } + // match: (Sub8 (Sub8 i:(Const8 ) z) x) + // cond: (z.Op != OpConst8 && x.Op != OpConst8) + // result: (Sub8 i (Add8 z x)) + for { + if v_0.Op != OpSub8 { + break + } + z := v_0.Args[1] + i := v_0.Args[0] if i.Op != OpConst8 { break } t := i.Type + x := v_1 if !(z.Op != OpConst8 && x.Op != OpConst8) { break } - v.reset(OpAdd8) - v0 := b.NewValue0(v.Pos, OpSub8, t) - v0.AddArg2(x, z) + v.reset(OpSub8) + v0 := b.NewValue0(v.Pos, OpAdd8, t) + v0.AddArg2(z, x) v.AddArg2(i, v0) return true } - // match: (Sub8 (Const8 [c]) (Sub8 x (Const8 [d]))) - // result: (Sub8 (Const8 [c+d]) x) + // match: (Sub8 (Add8 z i:(Const8 )) x) + // cond: (z.Op != OpConst8 && x.Op != OpConst8) + // result: (Add8 i (Sub8 z x)) for { - if v_0.Op != OpConst8 { - break - } - t := v_0.Type - c := auxIntToInt8(v_0.AuxInt) - if v_1.Op != OpSub8 { + if v_0.Op != OpAdd8 { break } - _ = v_1.Args[1] - x := v_1.Args[0] - v_1_1 := v_1.Args[1] - if v_1_1.Op != OpConst8 || v_1_1.Type != t { - break + _ = v_0.Args[1] + v_0_0 := v_0.Args[0] + v_0_1 := v_0.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_0_0, v_0_1 = _i0+1, v_0_1, v_0_0 { + z := v_0_0 + i := v_0_1 + if i.Op != OpConst8 { + continue + } + t := i.Type + x := v_1 + if !(z.Op != OpConst8 && x.Op != OpConst8) { + continue + } + v.reset(OpAdd8) + v0 := b.NewValue0(v.Pos, OpSub8, t) + v0.AddArg2(z, x) + v.AddArg2(i, v0) + return true } - d := auxIntToInt8(v_1_1.AuxInt) - v.reset(OpSub8) - v0 := b.NewValue0(v.Pos, OpConst8, t) - v0.AuxInt = int8ToAuxInt(c + d) - v.AddArg2(v0, x) - return true + break } // match: (Sub8 (Const8 [c]) (Sub8 (Const8 [d]) x)) // result: (Add8 (Const8 [c-d]) x) @@ -23205,6 +23329,34 @@ func rewriteValuegeneric_OpSub8(v *Value) bool { v.AddArg2(v0, x) return true } + // match: (Sub8 (Const8 [c]) (Add8 (Const8 [d]) x)) + // result: (Sub8 (Const8 [c-d]) x) + for { + if v_0.Op != OpConst8 { + break + } + t := v_0.Type + c := auxIntToInt8(v_0.AuxInt) + if v_1.Op != OpAdd8 { + break + } + _ = v_1.Args[1] + v_1_0 := v_1.Args[0] + v_1_1 := v_1.Args[1] + for _i0 := 0; _i0 <= 1; _i0, v_1_0, v_1_1 = _i0+1, v_1_1, v_1_0 { + if v_1_0.Op != OpConst8 || v_1_0.Type != t { + continue + } + d := auxIntToInt8(v_1_0.AuxInt) + x := v_1_1 + v.reset(OpSub8) + v0 := b.NewValue0(v.Pos, OpConst8, t) + v0.AuxInt = int8ToAuxInt(c - d) + v.AddArg2(v0, x) + return true + } + break + } return false } func rewriteValuegeneric_OpTrunc16to8(v *Value) bool { diff --git a/test/codegen/arithmetic.go b/test/codegen/arithmetic.go index 45fdb68903..afd4d66bd9 100644 --- a/test/codegen/arithmetic.go +++ b/test/codegen/arithmetic.go @@ -462,7 +462,6 @@ func addSpecial(a, b, c uint32) (uint32, uint32, uint32) { return a, b, c } - // Divide -> shift rules usually require fixup for negative inputs. // If the input is non-negative, make sure the fixup is eliminated. func divInt(v int64) int64 { @@ -472,3 +471,33 @@ func divInt(v int64) int64 { // amd64:-`.*SARQ.*63,`, -".*SHRQ", ".*SARQ.*[$]9," return v / 512 } + +// The reassociate rules "x - (z + C) -> (x - z) - C" and +// "(z + C) -x -> C + (z - x)" can optimize the following cases. +func constantFold1(i0, j0, i1, j1, i2, j2, i3, j3 int) (int, int, int, int) { + // arm64:"SUB","ADD\t[$]2" + r0 := (i0 + 3) - (j0 + 1) + // arm64:"SUB","SUB\t[$]4" + r1 := (i1 - 3) - (j1 + 1) + // arm64:"SUB","ADD\t[$]4" + r2 := (i2 + 3) - (j2 - 1) + // arm64:"SUB","SUB\t[$]2" + r3 := (i3 - 3) - (j3 - 1) + return r0, r1, r2, r3 +} + +// The reassociate rules "x - (z + C) -> (x - z) - C" and +// "(C - z) - x -> C - (z + x)" can optimize the following cases. +func constantFold2(i0, j0, i1, j1 int) (int, int) { + // arm64:"ADD","MOVD\t[$]2","SUB" + r0 := (3 - i0) - (j0 + 1) + // arm64:"ADD","MOVD\t[$]4","SUB" + r1 := (3 - i1) - (j1 - 1) + return r0, r1 +} + +func constantFold3(i, j int) int { + // arm64: "MOVD\t[$]30","MUL",-"ADD",-"LSL" + r := (5 * i) * (6 * j) + return r +} -- 2.50.0