cmd/compile: fold negation into multiplication

goos: linux
goarch: riscv64
pkg: cmd/compile/internal/test
cpu: Spacemit(R) X60
        │ /root/mul.base.log │          /root/mul.new.log          │
        │       sec/op       │   sec/op     vs base                │
MulNeg           6.426µ ± 0%   4.501µ ± 0%  -29.96% (p=0.000 n=10)
Mul2Neg          9.000µ ± 0%   6.431µ ± 0%  -28.54% (p=0.000 n=10)
Mul2             1.263µ ± 0%   1.263µ ± 0%        ~ (p=1.000 n=10)
MulNeg2          1.577µ ± 0%   1.577µ ± 0%        ~ (p=0.211 n=10)
geomean          3.276µ        2.756µ       -15.89%

goos: linux
goarch: amd64
pkg: cmd/compile/internal/test
cpu: AMD EPYC 7532 32-Core Processor
        │ /root/base  │              /root/new              │
        │   sec/op    │   sec/op     vs base                │
MulNeg    691.9n ± 1%   319.4n ± 0%  -53.83% (p=0.000 n=10)
Mul2Neg   630.0n ± 0%   629.6n ± 0%   -0.07% (p=0.000 n=10)
Mul2      438.1n ± 0%   438.1n ± 0%        ~ (p=0.728 n=10)
MulNeg2   439.3n ± 0%   439.4n ± 0%        ~ (p=0.656 n=10)
geomean   538.2n        443.6n       -17.58%

Change-Id: Ice8e6c8d1e8e3009ba8a0b1b689205174e199019
Reviewed-on: https://go-review.googlesource.com/c/go/+/720180
Reviewed-by: abner chenc <chenguoqi@loongson.cn>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Reviewed-by: Joel Sing <joel@sing.id.au>
Reviewed-by: Keith Randall <khr@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Keith Randall <khr@golang.org>
This commit is contained in:
Meng Zhuo 2025-11-14 12:47:35 +08:00 committed by Gopher Robot
parent b57962b7c7
commit 2cdcc4150b
5 changed files with 171 additions and 46 deletions

View file

@ -743,9 +743,6 @@
(MULV x (MOVVconst [c])) && canMulStrengthReduce(config, c) => {mulStrengthReduce(v, x, c)}
(MULV (NEGV x) (MOVVconst [c])) => (MULV x (MOVVconst [-c]))
(MULV (NEGV x) (NEGV y)) => (MULV x y)
(ADDV x0 x1:(SLLVconst [c] y)) && x1.Uses == 1 && c > 0 && c <= 4 => (ADDshiftLLV x0 y [c])
// fold constant in ADDshift op

View file

@ -195,6 +195,11 @@
// Convert x * -1 to -x.
(Mul(8|16|32|64) (Const(8|16|32|64) [-1]) x) => (Neg(8|16|32|64) x)
// Convert -x * c to x * -c
(Mul(8|16|32|64) (Const(8|16|32|64) <t> [c]) (Neg(8|16|32|64) x)) => (Mul(8|16|32|64) x (Const(8|16|32|64) <t> [-c]))
(Mul(8|16|32|64) (Neg(8|16|32|64) x) (Neg(8|16|32|64) y)) => (Mul(8|16|32|64) x y)
// DeMorgan's Laws
(And(8|16|32|64) <t> (Com(8|16|32|64) x) (Com(8|16|32|64) y)) => (Com(8|16|32|64) (Or(8|16|32|64) <t> x y))
(Or(8|16|32|64) <t> (Com(8|16|32|64) x) (Com(8|16|32|64) y)) => (Com(8|16|32|64) (And(8|16|32|64) <t> x y))

View file

@ -5866,7 +5866,6 @@ func rewriteValueLOONG64_OpLOONG64MULV(v *Value) bool {
v_0 := v.Args[0]
b := v.Block
config := b.Func.Config
typ := &b.Func.Config.Types
// match: (MULV _ (MOVVconst [0]))
// result: (MOVVconst [0])
for {
@ -5911,44 +5910,6 @@ func rewriteValueLOONG64_OpLOONG64MULV(v *Value) bool {
}
break
}
// match: (MULV (NEGV x) (MOVVconst [c]))
// result: (MULV x (MOVVconst [-c]))
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
if v_0.Op != OpLOONG64NEGV {
continue
}
x := v_0.Args[0]
if v_1.Op != OpLOONG64MOVVconst {
continue
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpLOONG64MULV)
v0 := b.NewValue0(v.Pos, OpLOONG64MOVVconst, typ.UInt64)
v0.AuxInt = int64ToAuxInt(-c)
v.AddArg2(x, v0)
return true
}
break
}
// match: (MULV (NEGV x) (NEGV y))
// result: (MULV x y)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
if v_0.Op != OpLOONG64NEGV {
continue
}
x := v_0.Args[0]
if v_1.Op != OpLOONG64NEGV {
continue
}
y := v_1.Args[0]
v.reset(OpLOONG64MULV)
v.AddArg2(x, y)
return true
}
break
}
// match: (MULV (MOVVconst [c]) (MOVVconst [d]))
// result: (MOVVconst [c*d])
for {

View file

@ -16786,6 +16786,45 @@ func rewriteValuegeneric_OpMul16(v *Value) bool {
}
break
}
// match: (Mul16 (Const16 <t> [c]) (Neg16 x))
// result: (Mul16 x (Const16 <t> [-c]))
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 != OpNeg16 {
continue
}
x := v_1.Args[0]
v.reset(OpMul16)
v0 := b.NewValue0(v.Pos, OpConst16, t)
v0.AuxInt = int16ToAuxInt(-c)
v.AddArg2(x, v0)
return true
}
break
}
// match: (Mul16 (Neg16 x) (Neg16 y))
// result: (Mul16 x y)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
if v_0.Op != OpNeg16 {
continue
}
x := v_0.Args[0]
if v_1.Op != OpNeg16 {
continue
}
y := v_1.Args[0]
v.reset(OpMul16)
v.AddArg2(x, y)
return true
}
break
}
// match: (Mul16 (Const16 <t> [c]) (Add16 <t> (Const16 <t> [d]) x))
// cond: !isPowerOfTwo(c)
// result: (Add16 (Const16 <t> [c*d]) (Mul16 <t> (Const16 <t> [c]) x))
@ -16997,6 +17036,45 @@ func rewriteValuegeneric_OpMul32(v *Value) bool {
}
break
}
// match: (Mul32 (Const32 <t> [c]) (Neg32 x))
// result: (Mul32 x (Const32 <t> [-c]))
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 != OpNeg32 {
continue
}
x := v_1.Args[0]
v.reset(OpMul32)
v0 := b.NewValue0(v.Pos, OpConst32, t)
v0.AuxInt = int32ToAuxInt(-c)
v.AddArg2(x, v0)
return true
}
break
}
// match: (Mul32 (Neg32 x) (Neg32 y))
// result: (Mul32 x y)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
if v_0.Op != OpNeg32 {
continue
}
x := v_0.Args[0]
if v_1.Op != OpNeg32 {
continue
}
y := v_1.Args[0]
v.reset(OpMul32)
v.AddArg2(x, y)
return true
}
break
}
// match: (Mul32 (Const32 <t> [c]) (Add32 <t> (Const32 <t> [d]) x))
// cond: !isPowerOfTwo(c)
// result: (Add32 (Const32 <t> [c*d]) (Mul32 <t> (Const32 <t> [c]) x))
@ -17369,6 +17447,45 @@ func rewriteValuegeneric_OpMul64(v *Value) bool {
}
break
}
// match: (Mul64 (Const64 <t> [c]) (Neg64 x))
// result: (Mul64 x (Const64 <t> [-c]))
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 != OpNeg64 {
continue
}
x := v_1.Args[0]
v.reset(OpMul64)
v0 := b.NewValue0(v.Pos, OpConst64, t)
v0.AuxInt = int64ToAuxInt(-c)
v.AddArg2(x, v0)
return true
}
break
}
// match: (Mul64 (Neg64 x) (Neg64 y))
// result: (Mul64 x y)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
if v_0.Op != OpNeg64 {
continue
}
x := v_0.Args[0]
if v_1.Op != OpNeg64 {
continue
}
y := v_1.Args[0]
v.reset(OpMul64)
v.AddArg2(x, y)
return true
}
break
}
// match: (Mul64 (Const64 <t> [c]) (Add64 <t> (Const64 <t> [d]) x))
// cond: !isPowerOfTwo(c)
// result: (Add64 (Const64 <t> [c*d]) (Mul64 <t> (Const64 <t> [c]) x))
@ -17741,6 +17858,45 @@ func rewriteValuegeneric_OpMul8(v *Value) bool {
}
break
}
// match: (Mul8 (Const8 <t> [c]) (Neg8 x))
// result: (Mul8 x (Const8 <t> [-c]))
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 != OpNeg8 {
continue
}
x := v_1.Args[0]
v.reset(OpMul8)
v0 := b.NewValue0(v.Pos, OpConst8, t)
v0.AuxInt = int8ToAuxInt(-c)
v.AddArg2(x, v0)
return true
}
break
}
// match: (Mul8 (Neg8 x) (Neg8 y))
// result: (Mul8 x y)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
if v_0.Op != OpNeg8 {
continue
}
x := v_0.Args[0]
if v_1.Op != OpNeg8 {
continue
}
y := v_1.Args[0]
v.reset(OpMul8)
v.AddArg2(x, y)
return true
}
break
}
// match: (Mul8 (Const8 <t> [c]) (Add8 <t> (Const8 <t> [d]) x))
// cond: !isPowerOfTwo(c)
// result: (Add8 (Const8 <t> [c*d]) (Mul8 <t> (Const8 <t> [c]) x))

View file

@ -318,13 +318,19 @@ func MergeMuls5(a, n int) int {
// Multiplications folded negation
func FoldNegMul(a int) int {
// loong64:"SUBVU" "ALSLV [$]2" "ALSLV [$]1"
return (-a) * 11
// amd64:"IMUL3Q [$]-11" -"NEGQ"
// arm64:"MOVD [$]-11" "MUL" -"NEG"
// loong64:"ALSLV [$]2" "SUBVU" "ALSLV [$]4"
// riscv64:"MOV [$]-11" "MUL" -"NEG"
return -a * 11
}
func Fold2NegMul(a, b int) int {
// amd64:"IMULQ" -"NEGQ"
// arm64:"MUL" -"NEG"
// loong64:"MULV" -"SUBVU R[0-9], R0,"
return (-a) * (-b)
// riscv64:"MUL" -"NEG"
return -a * -b
}
// -------------- //