]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: add more generic rewrite rules to reassociate (op (op y C) x|C)
authorfanzha02 <fannie.zhang@arm.com>
Thu, 28 May 2020 10:11:52 +0000 (18:11 +0800)
committerKeith Randall <khr@golang.org>
Mon, 24 Aug 2020 14:52:54 +0000 (14:52 +0000)
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 <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/ssa/gen/generic.rules
src/cmd/compile/internal/ssa/rewritegeneric.go
test/codegen/arithmetic.go

index 2d39d2722620b6dc8241d3458d18dc3c530c3a21..f7e6bbebac7b93810dbc2247952d3af468b9e03f 100644 (file)
 // 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 <t>) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) => (Add64 i (Add64 <t> z x))
 (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))
 
-// 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)
-
 // 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 - (z + C) -> x + (-z - C) -> (x - z) - C
+(Sub64 x (Add64 z i:(Const64 <t>))) && (z.Op != OpConst64 && x.Op != OpConst64) => (Sub64 (Sub64 <t> x z) i)
+(Sub32 x (Add32 z i:(Const32 <t>))) && (z.Op != OpConst32 && x.Op != OpConst32) => (Sub32 (Sub32 <t> x z) i)
+(Sub16 x (Add16 z i:(Const16 <t>))) && (z.Op != OpConst16 && x.Op != OpConst16) => (Sub16 (Sub16 <t> x z) i)
+(Sub8  x (Add8  z i:(Const8  <t>))) && (z.Op != OpConst8  && x.Op != OpConst8)  => (Sub8 (Sub8  <t> x z) i)
+
+// (C - z) - x -> C - (z + x)
+(Sub64 (Sub64 i:(Const64 <t>) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) => (Sub64 i (Add64 <t> z x))
+(Sub32 (Sub32 i:(Const32 <t>) z) x) && (z.Op != OpConst32 && x.Op != OpConst32) => (Sub32 i (Add32 <t> z x))
+(Sub16 (Sub16 i:(Const16 <t>) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) => (Sub16 i (Add16 <t> z x))
+(Sub8  (Sub8  i:(Const8  <t>) z) x) && (z.Op != OpConst8  && x.Op != OpConst8)  => (Sub8  i (Add8  <t> z x))
+
+// (z + C) -x -> C + (z - x)
+(Sub64 (Add64 z i:(Const64 <t>)) x) && (z.Op != OpConst64 && x.Op != OpConst64) => (Add64 i (Sub64 <t> z x))
+(Sub32 (Add32 z i:(Const32 <t>)) x) && (z.Op != OpConst32 && x.Op != OpConst32) => (Add32 i (Sub32 <t> z x))
+(Sub16 (Add16 z i:(Const16 <t>)) x) && (z.Op != OpConst16 && x.Op != OpConst16) => (Add16 i (Sub16 <t> z x))
+(Sub8  (Add8  z i:(Const8  <t>)) x) && (z.Op != OpConst8  && x.Op != OpConst8)  => (Add8  i (Sub8  <t> z x))
 
 // 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))
 (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))
 
+// x * (D * z) = D * (x * z)
+(Mul64 (Mul64 i:(Const64 <t>) z) x) && (z.Op != OpConst64 && x.Op != OpConst64) => (Mul64 i (Mul64 <t> x z))
+(Mul32 (Mul32 i:(Const32 <t>) z) x) && (z.Op != OpConst32 && x.Op != OpConst32) => (Mul32 i (Mul32 <t> x z))
+(Mul16 (Mul16 i:(Const16 <t>) z) x) && (z.Op != OpConst16 && x.Op != OpConst16) => (Mul16 i (Mul16 <t> x z))
+(Mul8  (Mul8  i:(Const8  <t>) z) x) && (z.Op != OpConst8  && x.Op != OpConst8)  => (Mul8  i (Mul8  <t> x z))
+
 // 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> [c+d]) x)
 (Add16 (Const16 <t> [c]) (Sub16 (Const16 <t> [d]) x)) => (Sub16 (Const16 <t> [c+d]) x)
 (Add8  (Const8  <t> [c]) (Sub8  (Const8  <t> [d]) x)) => (Sub8  (Const8  <t> [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> [c-d]) x)
-(Add16 (Const16 <t> [c]) (Sub16 x (Const16 <t> [d]))) => (Add16 (Const16 <t> [c-d]) x)
-(Add8  (Const8  <t> [c]) (Sub8  x (Const8  <t> [d]))) => (Add8  (Const8  <t> [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> [c+d]) x)
-(Sub16 (Const16 <t> [c]) (Sub16 x (Const16 <t> [d]))) => (Sub16 (Const16 <t> [c+d]) x)
-(Sub8  (Const8  <t> [c]) (Sub8  x (Const8  <t> [d]))) => (Sub8  (Const8  <t> [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> [c-d]) x)
 (Sub16 (Const16 <t> [c]) (Sub16 (Const16 <t> [d]) x)) => (Add16 (Const16 <t> [c-d]) x)
 (Sub8  (Const8  <t> [c]) (Sub8  (Const8  <t> [d]) x)) => (Add8  (Const8  <t> [c-d]) x)
 
+// C - (D + x) -> (C - D) - x
+(Sub64 (Const64 <t> [c]) (Add64 (Const64 <t> [d]) x)) => (Sub64 (Const64 <t> [c-d]) x)
+(Sub32 (Const32 <t> [c]) (Add32 (Const32 <t> [d]) x)) => (Sub32 (Const32 <t> [c-d]) x)
+(Sub16 (Const16 <t> [c]) (Add16 (Const16 <t> [d]) x)) => (Sub16 (Const16 <t> [c-d]) x)
+(Sub8  (Const8  <t> [c]) (Add8  (Const8  <t> [d]) x)) => (Sub8  (Const8  <t> [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> [c&d]) x)
index 68e49f46f341c870e7bb1f4aeecd7da0e93f0e3b..180e48b34cc551483ccb357b6aaeb35abcb57bf3 100644 (file)
@@ -588,33 +588,6 @@ func rewriteValuegeneric_OpAdd16(v *Value) bool {
                }
                break
        }
-       // match: (Add16 (Sub16 z i:(Const16 <t>)) x)
-       // cond: (z.Op != OpConst16 && x.Op != OpConst16)
-       // result: (Sub16 (Add16 <t> 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 <t> [c]) (Add16 (Const16 <t> [d]) x))
        // result: (Add16 (Const16 <t> [c+d]) x)
        for {
@@ -671,33 +644,6 @@ func rewriteValuegeneric_OpAdd16(v *Value) bool {
                }
                break
        }
-       // match: (Add16 (Const16 <t> [c]) (Sub16 x (Const16 <t> [d])))
-       // result: (Add16 (Const16 <t> [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 <t>)) x)
-       // cond: (z.Op != OpConst32 && x.Op != OpConst32)
-       // result: (Sub32 (Add32 <t> 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 <t> [c]) (Add32 (Const32 <t> [d]) x))
        // result: (Add32 (Const32 <t> [c+d]) x)
        for {
@@ -924,33 +843,6 @@ func rewriteValuegeneric_OpAdd32(v *Value) bool {
                }
                break
        }
-       // match: (Add32 (Const32 <t> [c]) (Sub32 x (Const32 <t> [d])))
-       // result: (Add32 (Const32 <t> [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 <t>)) x)
-       // cond: (z.Op != OpConst64 && x.Op != OpConst64)
-       // result: (Sub64 (Add64 <t> 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 <t> [c]) (Add64 (Const64 <t> [d]) x))
        // result: (Add64 (Const64 <t> [c+d]) x)
        for {
@@ -1204,33 +1069,6 @@ func rewriteValuegeneric_OpAdd64(v *Value) bool {
                }
                break
        }
-       // match: (Add64 (Const64 <t> [c]) (Sub64 x (Const64 <t> [d])))
-       // result: (Add64 (Const64 <t> [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 <t>)) x)
-       // cond: (z.Op != OpConst8 && x.Op != OpConst8)
-       // result: (Sub8 (Add8 <t> 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 <t> [c]) (Add8 (Const8 <t> [d]) x))
        // result: (Add8 (Const8 <t> [c+d]) x)
        for {
@@ -1484,33 +1295,6 @@ func rewriteValuegeneric_OpAdd8(v *Value) bool {
                }
                break
        }
-       // match: (Add8 (Const8 <t> [c]) (Sub8 x (Const8 <t> [d])))
-       // result: (Add8 (Const8 <t> [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 <t>) z) x)
+       // cond: (z.Op != OpConst16 && x.Op != OpConst16)
+       // result: (Mul16 i (Mul16 <t> 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 <t> [c]) (Mul16 (Const16 <t> [d]) x))
        // result: (Mul16 (Const16 <t> [c*d]) x)
        for {
@@ -14098,6 +13913,37 @@ func rewriteValuegeneric_OpMul32(v *Value) bool {
                }
                break
        }
+       // match: (Mul32 (Mul32 i:(Const32 <t>) z) x)
+       // cond: (z.Op != OpConst32 && x.Op != OpConst32)
+       // result: (Mul32 i (Mul32 <t> 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 <t> [c]) (Mul32 (Const32 <t> [d]) x))
        // result: (Mul32 (Const32 <t> [c*d]) x)
        for {
@@ -14342,16 +14188,47 @@ func rewriteValuegeneric_OpMul64(v *Value) bool {
                }
                break
        }
-       // match: (Mul64 (Const64 <t> [c]) (Mul64 (Const64 <t> [d]) x))
-       // result: (Mul64 (Const64 <t> [c*d]) x)
+       // match: (Mul64 (Mul64 i:(Const64 <t>) z) x)
+       // cond: (z.Op != OpConst64 && x.Op != OpConst64)
+       // result: (Mul64 i (Mul64 <t> 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 <t> [c]) (Mul64 (Const64 <t> [d]) x))
+       // result: (Mul64 (Const64 <t> [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 <t>) z) x)
+       // cond: (z.Op != OpConst8 && x.Op != OpConst8)
+       // result: (Mul8 i (Mul8 <t> 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 <t> [c]) (Mul8 (Const8 <t> [d]) x))
        // result: (Mul8 (Const8 <t> [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 <t>)))
+       // match: (Sub16 x (Add16 z i:(Const16 <t>)))
        // cond: (z.Op != OpConst16 && x.Op != OpConst16)
-       // result: (Add16 i (Sub16 <t> x z))
+       // result: (Sub16 (Sub16 <t> 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 <t>) z) x)
+       // cond: (z.Op != OpConst16 && x.Op != OpConst16)
+       // result: (Sub16 i (Add16 <t> 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 <t> [c]) (Sub16 x (Const16 <t> [d])))
-       // result: (Sub16 (Const16 <t> [c+d]) x)
+       // match: (Sub16 (Add16 z i:(Const16 <t>)) x)
+       // cond: (z.Op != OpConst16 && x.Op != OpConst16)
+       // result: (Add16 i (Sub16 <t> 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 <t> [c]) (Sub16 (Const16 <t> [d]) x))
        // result: (Add16 (Const16 <t> [c-d]) x)
@@ -22503,6 +22444,34 @@ func rewriteValuegeneric_OpSub16(v *Value) bool {
                v.AddArg2(v0, x)
                return true
        }
+       // match: (Sub16 (Const16 <t> [c]) (Add16 (Const16 <t> [d]) x))
+       // result: (Sub16 (Const16 <t> [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 <t>)))
+       // match: (Sub32 x (Add32 z i:(Const32 <t>)))
        // cond: (z.Op != OpConst32 && x.Op != OpConst32)
-       // result: (Add32 i (Sub32 <t> x z))
+       // result: (Sub32 (Sub32 <t> 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 <t>) z) x)
+       // cond: (z.Op != OpConst32 && x.Op != OpConst32)
+       // result: (Sub32 i (Add32 <t> 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 <t> [c]) (Sub32 x (Const32 <t> [d])))
-       // result: (Sub32 (Const32 <t> [c+d]) x)
+       // match: (Sub32 (Add32 z i:(Const32 <t>)) x)
+       // cond: (z.Op != OpConst32 && x.Op != OpConst32)
+       // result: (Add32 i (Sub32 <t> 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 <t> [c]) (Sub32 (Const32 <t> [d]) x))
        // result: (Add32 (Const32 <t> [c-d]) x)
@@ -22721,6 +22723,34 @@ func rewriteValuegeneric_OpSub32(v *Value) bool {
                v.AddArg2(v0, x)
                return true
        }
+       // match: (Sub32 (Const32 <t> [c]) (Add32 (Const32 <t> [d]) x))
+       // result: (Sub32 (Const32 <t> [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 <t>)))
+       // match: (Sub64 x (Add64 z i:(Const64 <t>)))
        // cond: (z.Op != OpConst64 && x.Op != OpConst64)
-       // result: (Add64 i (Sub64 <t> x z))
+       // result: (Sub64 (Sub64 <t> 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 <t>) z) x)
+       // cond: (z.Op != OpConst64 && x.Op != OpConst64)
+       // result: (Sub64 i (Add64 <t> 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 <t> [c]) (Sub64 x (Const64 <t> [d])))
-       // result: (Sub64 (Const64 <t> [c+d]) x)
+       // match: (Sub64 (Add64 z i:(Const64 <t>)) x)
+       // cond: (z.Op != OpConst64 && x.Op != OpConst64)
+       // result: (Add64 i (Sub64 <t> 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 <t> [c]) (Sub64 (Const64 <t> [d]) x))
        // result: (Add64 (Const64 <t> [c-d]) x)
@@ -22963,6 +23026,34 @@ func rewriteValuegeneric_OpSub64(v *Value) bool {
                v.AddArg2(v0, x)
                return true
        }
+       // match: (Sub64 (Const64 <t> [c]) (Add64 (Const64 <t> [d]) x))
+       // result: (Sub64 (Const64 <t> [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 <t>)))
+       // match: (Sub8 x (Add8 z i:(Const8 <t>)))
        // cond: (z.Op != OpConst8 && x.Op != OpConst8)
-       // result: (Add8 i (Sub8 <t> x z))
+       // result: (Sub8 (Sub8 <t> 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 <t>) z) x)
+       // cond: (z.Op != OpConst8 && x.Op != OpConst8)
+       // result: (Sub8 i (Add8 <t> 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 <t> [c]) (Sub8 x (Const8 <t> [d])))
-       // result: (Sub8 (Const8 <t> [c+d]) x)
+       // match: (Sub8 (Add8 z i:(Const8 <t>)) x)
+       // cond: (z.Op != OpConst8 && x.Op != OpConst8)
+       // result: (Add8 i (Sub8 <t> 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 <t> [c]) (Sub8 (Const8 <t> [d]) x))
        // result: (Add8 (Const8 <t> [c-d]) x)
@@ -23205,6 +23329,34 @@ func rewriteValuegeneric_OpSub8(v *Value) bool {
                v.AddArg2(v0, x)
                return true
        }
+       // match: (Sub8 (Const8 <t> [c]) (Add8 (Const8 <t> [d]) x))
+       // result: (Sub8 (Const8 <t> [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 {
index 45fdb68903fb016a8b9af7b4b3780df9f0011a34..afd4d66bd9c43b467e7d612a6266421026251d59 100644 (file)
@@ -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
+}