From cf53990b18750e77963e5cf075c5a921d384b33b Mon Sep 17 00:00:00 2001 From: eric fang Date: Wed, 7 Sep 2022 08:34:52 +0000 Subject: [PATCH] cmd/compile: Add some CMP and CMN optimization rules on arm64 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 Reviewed-by: Keith Randall Reviewed-by: Cherry Mui TryBot-Result: Gopher Robot Run-TryBot: Eric Fang --- src/cmd/compile/internal/ssa/gen/ARM64.rules | 37 ++ src/cmd/compile/internal/ssa/rewriteARM64.go | 528 +++++++++++++++++++ src/cmd/internal/obj/arm64/obj7.go | 8 +- test/codegen/comparisons.go | 49 ++ 4 files changed, 616 insertions(+), 6 deletions(-) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules index a70600918b..3392644e7d 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules @@ -742,10 +742,47 @@ (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 y))) +(NotEqual (CMPconst [0] z:(MADD a x y))) && z.Uses==1 => (NotEqual (CMN a (MUL x y))) + +(Equal (CMPconst [0] z:(MSUB a x y))) && z.Uses==1 => (Equal (CMP a (MUL x y))) +(NotEqual (CMPconst [0] z:(MSUB a x y))) && z.Uses==1 => (NotEqual (CMP a (MUL x y))) + +(Equal (CMPWconst [0] z:(MADDW a x y))) && z.Uses==1 => (Equal (CMNW a (MULW x y))) +(NotEqual (CMPWconst [0] z:(MADDW a x y))) && z.Uses==1 => (NotEqual (CMNW a (MULW x y))) + +(Equal (CMPWconst [0] z:(MSUBW a x y))) && z.Uses==1 => (Equal (CMPW a (MULW x y))) +(NotEqual (CMPWconst [0] z:(MSUBW a x y))) && z.Uses==1 => (NotEqual (CMPW a (MULW 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) diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index d39f69c22f..b026532df3 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -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 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 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 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 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 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 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 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 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 { diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go index 6e4335562d..7d20beb5d6 100644 --- a/src/cmd/internal/obj/arm64/obj7.go +++ b/src/cmd/internal/obj/arm64/obj7.go @@ -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] diff --git a/test/codegen/comparisons.go b/test/codegen/comparisons.go index b1dba2482f..4b66044804 100644 --- a/test/codegen/comparisons.go +++ b/test/codegen/comparisons.go @@ -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 +} -- 2.50.0