]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: Add some CMP and CMN optimization rules on arm64
authoreric fang <eric.fang@arm.com>
Wed, 7 Sep 2022 08:34:52 +0000 (08:34 +0000)
committerEric Fang <eric.fang@arm.com>
Tue, 20 Sep 2022 01:14:40 +0000 (01:14 +0000)
This CL adds some optimizaion rules:
1, Converts CMP to CMN, or vice versa, when comparing with a negative
number.
2, For equal and not equal comparisons, CMP can be converted to CMN in
some cases. In theory we could do the same optimization for LT, LE, GT
and GE, but need to account for overflow, this CL doesn't handle them.

There are no noticeable performance changes.

Change-Id: Ia49266c019ab7908ebc9510c2f02e121b1607869
Reviewed-on: https://go-review.googlesource.com/c/go/+/429795
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Eric Fang <eric.fang@arm.com>

src/cmd/compile/internal/ssa/gen/ARM64.rules
src/cmd/compile/internal/ssa/rewriteARM64.go
src/cmd/internal/obj/arm64/obj7.go
test/codegen/comparisons.go

index a70600918b323ce1102411765a6ab6704dc56dad..3392644e7ddd713ffcf2015b078be4a40b9b2439 100644 (file)
 (EQ (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (EQ (CMN x y) yes no)
 (NE (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (NE (CMN x y) yes no)
 
+(Equal (CMP x z:(NEG y))) && z.Uses == 1 => (Equal (CMN x y))
+(NotEqual (CMP x z:(NEG y))) && z.Uses == 1 => (NotEqual (CMN x y))
+
 // CMPW(x,-y) -> CMNW(x,y) is only valid for unordered comparison, if y can be -1<<31
 (EQ (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (EQ (CMNW x y) yes no)
 (NE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 => (NE (CMNW x y) yes no)
 
+(Equal (CMPW x z:(NEG y))) && z.Uses == 1 => (Equal (CMNW x y))
+(NotEqual (CMPW x z:(NEG y))) && z.Uses == 1 => (NotEqual (CMNW x y))
+
+// For conditional instructions such as CSET, CSEL.
+// TODO: add support for LT, LE, GT, GE, overflow needs to be considered.
+(Equal (CMPconst [0] x:(ADDconst [c] y))) && x.Uses == 1 => (Equal (CMNconst [c] y))
+(NotEqual (CMPconst [0] x:(ADDconst [c] y))) && x.Uses == 1 => (NotEqual (CMNconst [c] y))
+
+(Equal (CMPWconst [0] x:(ADDconst [c] y))) && x.Uses == 1 => (Equal (CMNWconst [int32(c)] y))
+(NotEqual (CMPWconst [0] x:(ADDconst [c] y))) && x.Uses == 1 => (NotEqual (CMNWconst [int32(c)] y))
+
+(Equal (CMPconst [0] z:(ADD x y))) && z.Uses == 1 => (Equal (CMN x y))
+(NotEqual (CMPconst [0] z:(ADD x y))) && z.Uses == 1 => (NotEqual (CMN x y))
+
+(Equal (CMPWconst [0] z:(ADD x y))) && z.Uses == 1 => (Equal (CMNW x y))
+(NotEqual (CMPWconst [0] z:(ADD x y))) && z.Uses == 1 => (NotEqual (CMNW x y))
+
+(Equal (CMPconst [0] z:(MADD a x y))) && z.Uses==1 => (Equal (CMN a (MUL <x.Type> x y)))
+(NotEqual (CMPconst [0] z:(MADD a x y))) && z.Uses==1 => (NotEqual (CMN a (MUL <x.Type> x y)))
+
+(Equal (CMPconst [0] z:(MSUB a x y))) && z.Uses==1 => (Equal (CMP a (MUL <x.Type> x y)))
+(NotEqual (CMPconst [0] z:(MSUB a x y))) && z.Uses==1 => (NotEqual (CMP a (MUL <x.Type> x y)))
+
+(Equal (CMPWconst [0] z:(MADDW a x y))) && z.Uses==1 => (Equal (CMNW a (MULW <x.Type> x y)))
+(NotEqual (CMPWconst [0] z:(MADDW a x y))) && z.Uses==1 => (NotEqual (CMNW a (MULW <x.Type> x y)))
+
+(Equal (CMPWconst [0] z:(MSUBW a x y))) && z.Uses==1 => (Equal (CMPW a (MULW <x.Type> x y)))
+(NotEqual (CMPWconst [0] z:(MSUBW a x y))) && z.Uses==1 => (NotEqual (CMPW a (MULW <x.Type> x y)))
+
+(CMPconst [c] y) && c < 0 && c != -1<<63 => (CMNconst [-c] y)
+(CMPWconst [c] y) && c < 0 && c != -1<<31 => (CMNWconst [-c] y)
+(CMNconst [c] y) && c < 0 && c != -1<<63 => (CMPconst [-c] y)
+(CMNWconst [c] y) && c < 0 && c != -1<<31 => (CMPWconst [-c] y)
+
 (EQ (CMPconst [0] x) yes no) => (Z x yes no)
 (NE (CMPconst [0] x) yes no) => (NZ x yes no)
 (EQ (CMPWconst [0] x) yes no) => (ZW x yes no)
index d39f69c22fcd92011cd370af6b3fbd399fdccc7a..b026532df3d4d2785221772a39dc11f974eca234 100644 (file)
@@ -2505,6 +2505,20 @@ func rewriteValueARM64_OpARM64CMNW(v *Value) bool {
 }
 func rewriteValueARM64_OpARM64CMNWconst(v *Value) bool {
        v_0 := v.Args[0]
+       // match: (CMNWconst [c] y)
+       // cond: c < 0 && c != -1<<31
+       // result: (CMPWconst [-c] y)
+       for {
+               c := auxIntToInt32(v.AuxInt)
+               y := v_0
+               if !(c < 0 && c != -1<<31) {
+                       break
+               }
+               v.reset(OpARM64CMPWconst)
+               v.AuxInt = int32ToAuxInt(-c)
+               v.AddArg(y)
+               return true
+       }
        // match: (CMNWconst (MOVDconst [x]) [y])
        // result: (FlagConstant [addFlags32(int32(x),y)])
        for {
@@ -2521,6 +2535,20 @@ func rewriteValueARM64_OpARM64CMNWconst(v *Value) bool {
 }
 func rewriteValueARM64_OpARM64CMNconst(v *Value) bool {
        v_0 := v.Args[0]
+       // match: (CMNconst [c] y)
+       // cond: c < 0 && c != -1<<63
+       // result: (CMPconst [-c] y)
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               y := v_0
+               if !(c < 0 && c != -1<<63) {
+                       break
+               }
+               v.reset(OpARM64CMPconst)
+               v.AuxInt = int64ToAuxInt(-c)
+               v.AddArg(y)
+               return true
+       }
        // match: (CMNconst (MOVDconst [x]) [y])
        // result: (FlagConstant [addFlags64(x,y)])
        for {
@@ -2866,6 +2894,20 @@ func rewriteValueARM64_OpARM64CMPW(v *Value) bool {
 }
 func rewriteValueARM64_OpARM64CMPWconst(v *Value) bool {
        v_0 := v.Args[0]
+       // match: (CMPWconst [c] y)
+       // cond: c < 0 && c != -1<<31
+       // result: (CMNWconst [-c] y)
+       for {
+               c := auxIntToInt32(v.AuxInt)
+               y := v_0
+               if !(c < 0 && c != -1<<31) {
+                       break
+               }
+               v.reset(OpARM64CMNWconst)
+               v.AuxInt = int32ToAuxInt(-c)
+               v.AddArg(y)
+               return true
+       }
        // match: (CMPWconst (MOVDconst [x]) [y])
        // result: (FlagConstant [subFlags32(int32(x),y)])
        for {
@@ -2906,6 +2948,20 @@ func rewriteValueARM64_OpARM64CMPWconst(v *Value) bool {
 }
 func rewriteValueARM64_OpARM64CMPconst(v *Value) bool {
        v_0 := v.Args[0]
+       // match: (CMPconst [c] y)
+       // cond: c < 0 && c != -1<<63
+       // result: (CMNconst [-c] y)
+       for {
+               c := auxIntToInt64(v.AuxInt)
+               y := v_0
+               if !(c < 0 && c != -1<<63) {
+                       break
+               }
+               v.reset(OpARM64CMNconst)
+               v.AuxInt = int64ToAuxInt(-c)
+               v.AddArg(y)
+               return true
+       }
        // match: (CMPconst (MOVDconst [x]) [y])
        // result: (FlagConstant [subFlags64(x,y)])
        for {
@@ -3985,6 +4041,242 @@ func rewriteValueARM64_OpARM64Equal(v *Value) bool {
                v.AddArg(v0)
                return true
        }
+       // match: (Equal (CMP x z:(NEG y)))
+       // cond: z.Uses == 1
+       // result: (Equal (CMN x y))
+       for {
+               if v_0.Op != OpARM64CMP {
+                       break
+               }
+               _ = v_0.Args[1]
+               x := v_0.Args[0]
+               z := v_0.Args[1]
+               if z.Op != OpARM64NEG {
+                       break
+               }
+               y := z.Args[0]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64Equal)
+               v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+               v0.AddArg2(x, y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (Equal (CMPW x z:(NEG y)))
+       // cond: z.Uses == 1
+       // result: (Equal (CMNW x y))
+       for {
+               if v_0.Op != OpARM64CMPW {
+                       break
+               }
+               _ = v_0.Args[1]
+               x := v_0.Args[0]
+               z := v_0.Args[1]
+               if z.Op != OpARM64NEG {
+                       break
+               }
+               y := z.Args[0]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64Equal)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+               v0.AddArg2(x, y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (Equal (CMPconst [0] x:(ADDconst [c] y)))
+       // cond: x.Uses == 1
+       // result: (Equal (CMNconst [c] y))
+       for {
+               if v_0.Op != OpARM64CMPconst || auxIntToInt64(v_0.AuxInt) != 0 {
+                       break
+               }
+               x := v_0.Args[0]
+               if x.Op != OpARM64ADDconst {
+                       break
+               }
+               c := auxIntToInt64(x.AuxInt)
+               y := x.Args[0]
+               if !(x.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64Equal)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags)
+               v0.AuxInt = int64ToAuxInt(c)
+               v0.AddArg(y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (Equal (CMPWconst [0] x:(ADDconst [c] y)))
+       // cond: x.Uses == 1
+       // result: (Equal (CMNWconst [int32(c)] y))
+       for {
+               if v_0.Op != OpARM64CMPWconst || auxIntToInt32(v_0.AuxInt) != 0 {
+                       break
+               }
+               x := v_0.Args[0]
+               if x.Op != OpARM64ADDconst {
+                       break
+               }
+               c := auxIntToInt64(x.AuxInt)
+               y := x.Args[0]
+               if !(x.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64Equal)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags)
+               v0.AuxInt = int32ToAuxInt(int32(c))
+               v0.AddArg(y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (Equal (CMPconst [0] z:(ADD x y)))
+       // cond: z.Uses == 1
+       // result: (Equal (CMN x y))
+       for {
+               if v_0.Op != OpARM64CMPconst || auxIntToInt64(v_0.AuxInt) != 0 {
+                       break
+               }
+               z := v_0.Args[0]
+               if z.Op != OpARM64ADD {
+                       break
+               }
+               y := z.Args[1]
+               x := z.Args[0]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64Equal)
+               v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+               v0.AddArg2(x, y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (Equal (CMPWconst [0] z:(ADD x y)))
+       // cond: z.Uses == 1
+       // result: (Equal (CMNW x y))
+       for {
+               if v_0.Op != OpARM64CMPWconst || auxIntToInt32(v_0.AuxInt) != 0 {
+                       break
+               }
+               z := v_0.Args[0]
+               if z.Op != OpARM64ADD {
+                       break
+               }
+               y := z.Args[1]
+               x := z.Args[0]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64Equal)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+               v0.AddArg2(x, y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (Equal (CMPconst [0] z:(MADD a x y)))
+       // cond: z.Uses==1
+       // result: (Equal (CMN a (MUL <x.Type> x y)))
+       for {
+               if v_0.Op != OpARM64CMPconst || auxIntToInt64(v_0.AuxInt) != 0 {
+                       break
+               }
+               z := v_0.Args[0]
+               if z.Op != OpARM64MADD {
+                       break
+               }
+               y := z.Args[2]
+               a := z.Args[0]
+               x := z.Args[1]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64Equal)
+               v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+               v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type)
+               v1.AddArg2(x, y)
+               v0.AddArg2(a, v1)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (Equal (CMPconst [0] z:(MSUB a x y)))
+       // cond: z.Uses==1
+       // result: (Equal (CMP a (MUL <x.Type> x y)))
+       for {
+               if v_0.Op != OpARM64CMPconst || auxIntToInt64(v_0.AuxInt) != 0 {
+                       break
+               }
+               z := v_0.Args[0]
+               if z.Op != OpARM64MSUB {
+                       break
+               }
+               y := z.Args[2]
+               a := z.Args[0]
+               x := z.Args[1]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64Equal)
+               v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
+               v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type)
+               v1.AddArg2(x, y)
+               v0.AddArg2(a, v1)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (Equal (CMPWconst [0] z:(MADDW a x y)))
+       // cond: z.Uses==1
+       // result: (Equal (CMNW a (MULW <x.Type> x y)))
+       for {
+               if v_0.Op != OpARM64CMPWconst || auxIntToInt32(v_0.AuxInt) != 0 {
+                       break
+               }
+               z := v_0.Args[0]
+               if z.Op != OpARM64MADDW {
+                       break
+               }
+               y := z.Args[2]
+               a := z.Args[0]
+               x := z.Args[1]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64Equal)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+               v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type)
+               v1.AddArg2(x, y)
+               v0.AddArg2(a, v1)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (Equal (CMPWconst [0] z:(MSUBW a x y)))
+       // cond: z.Uses==1
+       // result: (Equal (CMPW a (MULW <x.Type> x y)))
+       for {
+               if v_0.Op != OpARM64CMPWconst || auxIntToInt32(v_0.AuxInt) != 0 {
+                       break
+               }
+               z := v_0.Args[0]
+               if z.Op != OpARM64MSUBW {
+                       break
+               }
+               y := z.Args[2]
+               a := z.Args[0]
+               x := z.Args[1]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64Equal)
+               v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+               v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type)
+               v1.AddArg2(x, y)
+               v0.AddArg2(a, v1)
+               v.AddArg(v0)
+               return true
+       }
        // match: (Equal (FlagConstant [fc]))
        // result: (MOVDconst [b2i(fc.eq())])
        for {
@@ -16435,6 +16727,242 @@ func rewriteValueARM64_OpARM64NotEqual(v *Value) bool {
                v.AddArg(v0)
                return true
        }
+       // match: (NotEqual (CMP x z:(NEG y)))
+       // cond: z.Uses == 1
+       // result: (NotEqual (CMN x y))
+       for {
+               if v_0.Op != OpARM64CMP {
+                       break
+               }
+               _ = v_0.Args[1]
+               x := v_0.Args[0]
+               z := v_0.Args[1]
+               if z.Op != OpARM64NEG {
+                       break
+               }
+               y := z.Args[0]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64NotEqual)
+               v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+               v0.AddArg2(x, y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (NotEqual (CMPW x z:(NEG y)))
+       // cond: z.Uses == 1
+       // result: (NotEqual (CMNW x y))
+       for {
+               if v_0.Op != OpARM64CMPW {
+                       break
+               }
+               _ = v_0.Args[1]
+               x := v_0.Args[0]
+               z := v_0.Args[1]
+               if z.Op != OpARM64NEG {
+                       break
+               }
+               y := z.Args[0]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64NotEqual)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+               v0.AddArg2(x, y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (NotEqual (CMPconst [0] x:(ADDconst [c] y)))
+       // cond: x.Uses == 1
+       // result: (NotEqual (CMNconst [c] y))
+       for {
+               if v_0.Op != OpARM64CMPconst || auxIntToInt64(v_0.AuxInt) != 0 {
+                       break
+               }
+               x := v_0.Args[0]
+               if x.Op != OpARM64ADDconst {
+                       break
+               }
+               c := auxIntToInt64(x.AuxInt)
+               y := x.Args[0]
+               if !(x.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64NotEqual)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags)
+               v0.AuxInt = int64ToAuxInt(c)
+               v0.AddArg(y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (NotEqual (CMPWconst [0] x:(ADDconst [c] y)))
+       // cond: x.Uses == 1
+       // result: (NotEqual (CMNWconst [int32(c)] y))
+       for {
+               if v_0.Op != OpARM64CMPWconst || auxIntToInt32(v_0.AuxInt) != 0 {
+                       break
+               }
+               x := v_0.Args[0]
+               if x.Op != OpARM64ADDconst {
+                       break
+               }
+               c := auxIntToInt64(x.AuxInt)
+               y := x.Args[0]
+               if !(x.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64NotEqual)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags)
+               v0.AuxInt = int32ToAuxInt(int32(c))
+               v0.AddArg(y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (NotEqual (CMPconst [0] z:(ADD x y)))
+       // cond: z.Uses == 1
+       // result: (NotEqual (CMN x y))
+       for {
+               if v_0.Op != OpARM64CMPconst || auxIntToInt64(v_0.AuxInt) != 0 {
+                       break
+               }
+               z := v_0.Args[0]
+               if z.Op != OpARM64ADD {
+                       break
+               }
+               y := z.Args[1]
+               x := z.Args[0]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64NotEqual)
+               v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+               v0.AddArg2(x, y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (NotEqual (CMPWconst [0] z:(ADD x y)))
+       // cond: z.Uses == 1
+       // result: (NotEqual (CMNW x y))
+       for {
+               if v_0.Op != OpARM64CMPWconst || auxIntToInt32(v_0.AuxInt) != 0 {
+                       break
+               }
+               z := v_0.Args[0]
+               if z.Op != OpARM64ADD {
+                       break
+               }
+               y := z.Args[1]
+               x := z.Args[0]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64NotEqual)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+               v0.AddArg2(x, y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (NotEqual (CMPconst [0] z:(MADD a x y)))
+       // cond: z.Uses==1
+       // result: (NotEqual (CMN a (MUL <x.Type> x y)))
+       for {
+               if v_0.Op != OpARM64CMPconst || auxIntToInt64(v_0.AuxInt) != 0 {
+                       break
+               }
+               z := v_0.Args[0]
+               if z.Op != OpARM64MADD {
+                       break
+               }
+               y := z.Args[2]
+               a := z.Args[0]
+               x := z.Args[1]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64NotEqual)
+               v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+               v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type)
+               v1.AddArg2(x, y)
+               v0.AddArg2(a, v1)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (NotEqual (CMPconst [0] z:(MSUB a x y)))
+       // cond: z.Uses==1
+       // result: (NotEqual (CMP a (MUL <x.Type> x y)))
+       for {
+               if v_0.Op != OpARM64CMPconst || auxIntToInt64(v_0.AuxInt) != 0 {
+                       break
+               }
+               z := v_0.Args[0]
+               if z.Op != OpARM64MSUB {
+                       break
+               }
+               y := z.Args[2]
+               a := z.Args[0]
+               x := z.Args[1]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64NotEqual)
+               v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags)
+               v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type)
+               v1.AddArg2(x, y)
+               v0.AddArg2(a, v1)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (NotEqual (CMPWconst [0] z:(MADDW a x y)))
+       // cond: z.Uses==1
+       // result: (NotEqual (CMNW a (MULW <x.Type> x y)))
+       for {
+               if v_0.Op != OpARM64CMPWconst || auxIntToInt32(v_0.AuxInt) != 0 {
+                       break
+               }
+               z := v_0.Args[0]
+               if z.Op != OpARM64MADDW {
+                       break
+               }
+               y := z.Args[2]
+               a := z.Args[0]
+               x := z.Args[1]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64NotEqual)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+               v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type)
+               v1.AddArg2(x, y)
+               v0.AddArg2(a, v1)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (NotEqual (CMPWconst [0] z:(MSUBW a x y)))
+       // cond: z.Uses==1
+       // result: (NotEqual (CMPW a (MULW <x.Type> x y)))
+       for {
+               if v_0.Op != OpARM64CMPWconst || auxIntToInt32(v_0.AuxInt) != 0 {
+                       break
+               }
+               z := v_0.Args[0]
+               if z.Op != OpARM64MSUBW {
+                       break
+               }
+               y := z.Args[2]
+               a := z.Args[0]
+               x := z.Args[1]
+               if !(z.Uses == 1) {
+                       break
+               }
+               v.reset(OpARM64NotEqual)
+               v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags)
+               v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type)
+               v1.AddArg2(x, y)
+               v0.AddArg2(a, v1)
+               v.AddArg(v0)
+               return true
+       }
        // match: (NotEqual (FlagConstant [fc]))
        // result: (MOVDconst [b2i(fc.ne())])
        for {
index 6e4335562dd566ee822d2fce3724e444b7bc93bb..7d20beb5d61694022ff8ebb1593b3efa3fedaa82 100644 (file)
@@ -45,10 +45,6 @@ var complements = []obj.As{
        AADDW: ASUBW,
        ASUB:  AADD,
        ASUBW: AADDW,
-       ACMP:  ACMN,
-       ACMPW: ACMNW,
-       ACMN:  ACMP,
-       ACMNW: ACMPW,
 }
 
 // zrReplace is the set of instructions for which $0 in the From operand
@@ -382,12 +378,12 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
        // Rewrite negative immediates as positive immediates with
        // complementary instruction.
        switch p.As {
-       case AADD, ASUB, ACMP, ACMN:
+       case AADD, ASUB:
                if p.From.Type == obj.TYPE_CONST && p.From.Offset < 0 && p.From.Offset != -1<<63 {
                        p.From.Offset = -p.From.Offset
                        p.As = complements[p.As]
                }
-       case AADDW, ASUBW, ACMPW, ACMNW:
+       case AADDW, ASUBW:
                if p.From.Type == obj.TYPE_CONST && p.From.Offset < 0 && int32(p.From.Offset) != -1<<31 {
                        p.From.Offset = -p.From.Offset
                        p.As = complements[p.As]
index b1dba2482f20cf1a2a3504f3bd58c42bdcd3baa3..4b66044804418e59561ef49c4ee1d47e962aa64e 100644 (file)
@@ -665,3 +665,52 @@ func equalVarString8(a string) bool {
        // ppc64le:-".*memequal"
        return a[:8] == b
 }
+
+func cmpToCmn(a, b, c, d int) int {
+       var c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11 int
+       // arm64:`CMN`,-`CMP`
+       if a < -8 {
+               c1 = 1
+       }
+       // arm64:`CMN`,-`CMP`
+       if a+1 == 0 {
+               c2 = 1
+       }
+       // arm64:`CMN`,-`CMP`
+       if a+3 != 0 {
+               c3 = 1
+       }
+       // arm64:`CMN`,-`CMP`
+       if a+b == 0 {
+               c4 = 1
+       }
+       // arm64:`CMN`,-`CMP`
+       if b+c != 0 {
+               c5 = 1
+       }
+       // arm64:`CMN`,-`CMP`
+       if a == -c {
+               c6 = 1
+       }
+       // arm64:`CMN`,-`CMP`
+       if b != -d {
+               c7 = 1
+       }
+       // arm64:`CMN`,-`CMP`
+       if a*b+c == 0 {
+               c8 = 1
+       }
+       // arm64:`CMN`,-`CMP`
+       if a*c+b != 0 {
+               c9 = 1
+       }
+       // arm64:`CMP`,-`CMN`
+       if b*c-a == 0 {
+               c10 = 1
+       }
+       // arm64:`CMP`,-`CMN`
+       if a*d-b != 0 {
+               c11 = 1
+       }
+       return c1 + c2 + c3 + c4 + c5 + c6 + c7 + c8 + c9 + c10 + c11
+}