diff --git a/src/cmd/compile/internal/ssa/_gen/generic.rules b/src/cmd/compile/internal/ssa/_gen/generic.rules
index ea3611c..97a1165 100644
--- a/src/cmd/compile/internal/ssa/_gen/generic.rules
+++ b/src/cmd/compile/internal/ssa/_gen/generic.rules
@@ -810,6 +810,8 @@
(Sub(64|32|16|8) x (Add(64|32|16|8) x y)) => (Neg(64|32|16|8) y)
(Add(64|32|16|8) x (Sub(64|32|16|8) y x)) => y
(Add(64|32|16|8) x (Add(64|32|16|8) y (Sub(64|32|16|8) z x))) => (Add(64|32|16|8) y z)
+// x + (y - (x - z)) == y + z
+(Add(64|32|16|8) x (Sub(64|32|16|8) y (Sub(64|32|16|8) x z))) => (Add(64|32|16|8) y z)
// basic phi simplifications
(Phi (Const8 [c]) (Const8 [c])) => (Const8 [c])
diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
index 7d175ab..329005c 100644
--- a/src/cmd/compile/internal/ssa/rewritegeneric.go
+++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
@@ -715,6 +715,30 @@
}
break
}
+ // match: (Add16 x (Sub16 y (Sub16 x z)))
+ // result: (Add16 y z)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ x := v_0
+ if v_1.Op != OpSub16 {
+ continue
+ }
+ _ = v_1.Args[1]
+ y := v_1.Args[0]
+ v_1_1 := v_1.Args[1]
+ if v_1_1.Op != OpSub16 {
+ continue
+ }
+ z := v_1_1.Args[1]
+ if x != v_1_1.Args[0] {
+ continue
+ }
+ v.reset(OpAdd16)
+ v.AddArg2(y, z)
+ return true
+ }
+ break
+ }
// match: (Add16 (Add16 i:(Const16 <t>) z) x)
// cond: (z.Op != OpConst16 && x.Op != OpConst16)
// result: (Add16 i (Add16 <t> z x))
@@ -1341,6 +1365,30 @@
}
break
}
+ // match: (Add32 x (Sub32 y (Sub32 x z)))
+ // result: (Add32 y z)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ x := v_0
+ if v_1.Op != OpSub32 {
+ continue
+ }
+ _ = v_1.Args[1]
+ y := v_1.Args[0]
+ v_1_1 := v_1.Args[1]
+ if v_1_1.Op != OpSub32 {
+ continue
+ }
+ z := v_1_1.Args[1]
+ if x != v_1_1.Args[0] {
+ continue
+ }
+ v.reset(OpAdd32)
+ v.AddArg2(y, z)
+ return true
+ }
+ break
+ }
// match: (Add32 (Add32 i:(Const32 <t>) z) x)
// cond: (z.Op != OpConst32 && x.Op != OpConst32)
// result: (Add32 i (Add32 <t> z x))
@@ -1994,6 +2042,30 @@
}
break
}
+ // match: (Add64 x (Sub64 y (Sub64 x z)))
+ // result: (Add64 y z)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ x := v_0
+ if v_1.Op != OpSub64 {
+ continue
+ }
+ _ = v_1.Args[1]
+ y := v_1.Args[0]
+ v_1_1 := v_1.Args[1]
+ if v_1_1.Op != OpSub64 {
+ continue
+ }
+ z := v_1_1.Args[1]
+ if x != v_1_1.Args[0] {
+ continue
+ }
+ v.reset(OpAdd64)
+ v.AddArg2(y, z)
+ return true
+ }
+ break
+ }
// match: (Add64 (Add64 i:(Const64 <t>) z) x)
// cond: (z.Op != OpConst64 && x.Op != OpConst64)
// result: (Add64 i (Add64 <t> z x))
@@ -2685,6 +2757,30 @@
}
break
}
+ // match: (Add8 x (Sub8 y (Sub8 x z)))
+ // result: (Add8 y z)
+ for {
+ for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
+ x := v_0
+ if v_1.Op != OpSub8 {
+ continue
+ }
+ _ = v_1.Args[1]
+ y := v_1.Args[0]
+ v_1_1 := v_1.Args[1]
+ if v_1_1.Op != OpSub8 {
+ continue
+ }
+ z := v_1_1.Args[1]
+ if x != v_1_1.Args[0] {
+ continue
+ }
+ v.reset(OpAdd8)
+ v.AddArg2(y, z)
+ return true
+ }
+ break
+ }
// match: (Add8 (Add8 i:(Const8 <t>) z) x)
// cond: (z.Op != OpConst8 && x.Op != OpConst8)
// result: (Add8 i (Add8 <t> z x))
diff --git a/test/codegen/arithmetic.go b/test/codegen/arithmetic.go
index 71b4b88..b6a478e 100644
--- a/test/codegen/arithmetic.go
+++ b/test/codegen/arithmetic.go
@@ -220,6 +220,17 @@
return r
}
+func AddSubSubSimplify(a, b, c int) int {
+ // amd64:"LEAQ" -"SUBQ"
+ // arm64:"ADD" -"SUB"
+ // loong64:"ADDV" -"SUBV"
+ // mips:"ADD" -"SUB"
+ // mips64:"ADDV" -"SUBV"
+ // ppc64x:-"SUB"
+ // riscv64:"ADD" -"SUB"
+ return a + (b - (a - c))
+}
+
func NegToInt32(a int) int {
// riscv64: "NEGW" -"MOVW"
r := int(int32(-a))