]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: optimize cmp to cmn under conditions < and >= on arm64
authorerifan01 <eric.fang@arm.com>
Tue, 14 Mar 2023 01:25:07 +0000 (09:25 +0800)
committerEric Fang <eric.fang@arm.com>
Fri, 24 Mar 2023 01:19:09 +0000 (01:19 +0000)
Under the right conditions we can optimize cmp comparisons to cmn
comparisons, such as:
func foo(a, b int) int {
  var c int
  if a + b < 0 {
   c = 1
  }
  return c
}

Previously it's compiled as:
  ADD     R1, R0, R1
  CMP     $0, R1
  CSET    LT, R0
With this CL it's compiled as:
  CMN     R1, R0
  CSET    MI, R0
Here we need to pay attention to the overflow situation of a+b, the MI
flag means N==1, which doesn't honor the overflow flag V, its value
depends only on the sign of the result. So it has the same semantic of
the Go code, so it's correct.

Similarly, this CL also optimizes the case of >= comparison
using the PL conditional flag.

Change-Id: I47179faba5b30cca84ea69bafa2ad5241bf6dfba
Reviewed-on: https://go-review.googlesource.com/c/go/+/476116
Run-TryBot: Eric Fang <eric.fang@arm.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: David Chase <drchase@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/compile/internal/arm64/ssa.go
src/cmd/compile/internal/ssa/_gen/ARM64.rules
src/cmd/compile/internal/ssa/_gen/ARM64Ops.go
src/cmd/compile/internal/ssa/opGen.go
src/cmd/compile/internal/ssa/rewriteARM64.go
src/cmd/compile/internal/ssa/rewriteCond_test.go
test/codegen/comparisons.go

index f32f923a8416f9342616537d0cd501a5f1ee47f1..e98cc11dc2092c4046687ee796a4179233fb4871 100644 (file)
@@ -1105,7 +1105,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
                ssa.OpARM64NotLessThanF,
                ssa.OpARM64NotLessEqualF,
                ssa.OpARM64NotGreaterThanF,
-               ssa.OpARM64NotGreaterEqualF:
+               ssa.OpARM64NotGreaterEqualF,
+               ssa.OpARM64LessThanNoov,
+               ssa.OpARM64GreaterEqualNoov:
                // generate boolean values using CSET
                p := s.Prog(arm64.ACSET)
                p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
@@ -1196,6 +1198,9 @@ var condBits = map[ssa.Op]arm64.SpecialOperand{
        ssa.OpARM64NotLessEqualF:    arm64.SPOP_HI, // Greater than or unordered
        ssa.OpARM64NotGreaterThanF:  arm64.SPOP_LE, // Less than, equal to or unordered
        ssa.OpARM64NotGreaterEqualF: arm64.SPOP_LT, // Less than or unordered
+
+       ssa.OpARM64LessThanNoov:     arm64.SPOP_MI, // Less than but without honoring overflow
+       ssa.OpARM64GreaterEqualNoov: arm64.SPOP_PL, // Greater than or equal to but without honoring overflow
 }
 
 var blockJump = map[ssa.BlockKind]struct {
index 747bd020f157a46581b252646ccf8387ce44087d..78c24afaa8b46732d3898d338626875ef0e8c18c 100644 (file)
 ((Equal|NotEqual) (CMPW x z:(NEG y))) && z.Uses == 1 => ((Equal|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|NotEqual) (CMPconst  [0] x:(ADDconst [c] y))) && x.Uses == 1 => ((Equal|NotEqual) (CMNconst [c] y))
-((Equal|NotEqual) (CMPWconst [0] x:(ADDconst [c] y))) && x.Uses == 1 => ((Equal|NotEqual) (CMNWconst [int32(c)] y))
-((Equal|NotEqual) (CMPconst  [0] z:(ADD        x y))) && z.Uses == 1 => ((Equal|NotEqual) (CMN x y))
-((Equal|NotEqual) (CMPWconst [0] z:(ADD        x y))) && z.Uses == 1 => ((Equal|NotEqual) (CMNW x y))
-((Equal|NotEqual) (CMPconst  [0] z:(MADD     a x y))) && z.Uses == 1 => ((Equal|NotEqual) (CMN a (MUL <x.Type> x y)))
-((Equal|NotEqual) (CMPconst  [0] z:(MSUB     a x y))) && z.Uses == 1 => ((Equal|NotEqual) (CMP a (MUL <x.Type> x y)))
-((Equal|NotEqual) (CMPWconst [0] z:(MADDW    a x y))) && z.Uses == 1 => ((Equal|NotEqual) (CMNW a (MULW <x.Type> x y)))
-((Equal|NotEqual) (CMPWconst [0] z:(MSUBW    a x y))) && z.Uses == 1 => ((Equal|NotEqual) (CMPW a (MULW <x.Type> x y)))
+// TODO: add support for LE, GT, overflow needs to be considered.
+((Equal|NotEqual|LessThan|GreaterEqual) (CMPconst  [0] x:(ADDconst [c] y))) && x.Uses == 1 => ((Equal|NotEqual|LessThanNoov|GreaterEqualNoov) (CMNconst [c] y))
+((Equal|NotEqual|LessThan|GreaterEqual) (CMPWconst [0] x:(ADDconst [c] y))) && x.Uses == 1 => ((Equal|NotEqual|LessThanNoov|GreaterEqualNoov) (CMNWconst [int32(c)] y))
+((Equal|NotEqual|LessThan|GreaterEqual) (CMPconst  [0] z:(ADD        x y))) && z.Uses == 1 => ((Equal|NotEqual|LessThanNoov|GreaterEqualNoov) (CMN  x y))
+((Equal|NotEqual|LessThan|GreaterEqual) (CMPWconst [0] z:(ADD        x y))) && z.Uses == 1 => ((Equal|NotEqual|LessThanNoov|GreaterEqualNoov) (CMNW x y))
+((Equal|NotEqual|LessThan|GreaterEqual) (CMPconst  [0] z:(MADD     a x y))) && z.Uses == 1 => ((Equal|NotEqual|LessThanNoov|GreaterEqualNoov) (CMN  a (MUL  <x.Type> x y)))
+((Equal|NotEqual|LessThan|GreaterEqual) (CMPconst  [0] z:(MSUB     a x y))) && z.Uses == 1 => ((Equal|NotEqual|LessThanNoov|GreaterEqualNoov) (CMP  a (MUL  <x.Type> x y)))
+((Equal|NotEqual|LessThan|GreaterEqual) (CMPWconst [0] z:(MADDW    a x y))) && z.Uses == 1 => ((Equal|NotEqual|LessThanNoov|GreaterEqualNoov) (CMNW a (MULW <x.Type> x y)))
+((Equal|NotEqual|LessThan|GreaterEqual) (CMPWconst [0] z:(MSUBW    a x y))) && z.Uses == 1 => ((Equal|NotEqual|LessThanNoov|GreaterEqualNoov) (CMPW a (MULW <x.Type> x y)))
 
 ((CMPconst|CMNconst)   [c] y) && c < 0 && c != -1<<63 => ((CMNconst|CMPconst)   [-c] y)
 ((CMPWconst|CMNWconst) [c] y) && c < 0 && c != -1<<31 => ((CMNWconst|CMPWconst) [-c] y)
index ca5b929ad7dbdf2efc087bf3102fefd6b32e4474..ca8e52e210e6de9402705f4f4b6e5a08b90b4034 100644 (file)
@@ -514,6 +514,9 @@ func init() {
                {name: "NotLessEqualF", argLength: 1, reg: readflags},    // bool, true flags encode floating-point x>y || x is unordered with y, false otherwise.
                {name: "NotGreaterThanF", argLength: 1, reg: readflags},  // bool, true flags encode floating-point x<=y || x is unordered with y, false otherwise.
                {name: "NotGreaterEqualF", argLength: 1, reg: readflags}, // bool, true flags encode floating-point x<y || x is unordered with y, false otherwise.
+               {name: "LessThanNoov", argLength: 1, reg: readflags},     // bool, true flags encode signed x<y but without honoring overflow, false otherwise.
+               {name: "GreaterEqualNoov", argLength: 1, reg: readflags}, // bool, true flags encode signed x>=y but without honoring overflow, false otherwise.
+
                // duffzero
                // arg0 = address of memory to zero
                // arg1 = mem
index 2c1c0dc567502e31a2a20ed52ee5e8435d56efd6..2f51869c248c20f0fcc129ad8ea37fdd8f676faa 100644 (file)
@@ -1670,6 +1670,8 @@ const (
        OpARM64NotLessEqualF
        OpARM64NotGreaterThanF
        OpARM64NotGreaterEqualF
+       OpARM64LessThanNoov
+       OpARM64GreaterEqualNoov
        OpARM64DUFFZERO
        OpARM64LoweredZero
        OpARM64DUFFCOPY
@@ -22276,6 +22278,24 @@ var opcodeTable = [...]opInfo{
                        },
                },
        },
+       {
+               name:   "LessThanNoov",
+               argLen: 1,
+               reg: regInfo{
+                       outputs: []outputInfo{
+                               {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+                       },
+               },
+       },
+       {
+               name:   "GreaterEqualNoov",
+               argLen: 1,
+               reg: regInfo{
+                       outputs: []outputInfo{
+                               {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+                       },
+               },
+       },
        {
                name:           "DUFFZERO",
                auxType:        auxInt64,
index b8c3c2c318f83ac2ffc7784a439e7ca6a738249c..bd3a3a390c5097d8e868ccb3cc25f1d900a04786 100644 (file)
@@ -5721,6 +5721,196 @@ func rewriteValueARM64_OpARM64GreaterEqual(v *Value) bool {
                v.AddArg(v0)
                return true
        }
+       // match: (GreaterEqual (CMPconst [0] x:(ADDconst [c] y)))
+       // cond: x.Uses == 1
+       // result: (GreaterEqualNoov (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(OpARM64GreaterEqualNoov)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags)
+               v0.AuxInt = int64ToAuxInt(c)
+               v0.AddArg(y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (GreaterEqual (CMPWconst [0] x:(ADDconst [c] y)))
+       // cond: x.Uses == 1
+       // result: (GreaterEqualNoov (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(OpARM64GreaterEqualNoov)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags)
+               v0.AuxInt = int32ToAuxInt(int32(c))
+               v0.AddArg(y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (GreaterEqual (CMPconst [0] z:(ADD x y)))
+       // cond: z.Uses == 1
+       // result: (GreaterEqualNoov (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(OpARM64GreaterEqualNoov)
+               v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+               v0.AddArg2(x, y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (GreaterEqual (CMPWconst [0] z:(ADD x y)))
+       // cond: z.Uses == 1
+       // result: (GreaterEqualNoov (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(OpARM64GreaterEqualNoov)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+               v0.AddArg2(x, y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (GreaterEqual (CMPconst [0] z:(MADD a x y)))
+       // cond: z.Uses == 1
+       // result: (GreaterEqualNoov (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(OpARM64GreaterEqualNoov)
+               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: (GreaterEqual (CMPconst [0] z:(MSUB a x y)))
+       // cond: z.Uses == 1
+       // result: (GreaterEqualNoov (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(OpARM64GreaterEqualNoov)
+               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: (GreaterEqual (CMPWconst [0] z:(MADDW a x y)))
+       // cond: z.Uses == 1
+       // result: (GreaterEqualNoov (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(OpARM64GreaterEqualNoov)
+               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: (GreaterEqual (CMPWconst [0] z:(MSUBW a x y)))
+       // cond: z.Uses == 1
+       // result: (GreaterEqualNoov (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(OpARM64GreaterEqualNoov)
+               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: (GreaterEqual (FlagConstant [fc]))
        // result: (MOVDconst [b2i(fc.ge())])
        for {
@@ -6245,6 +6435,196 @@ func rewriteValueARM64_OpARM64LessThan(v *Value) bool {
                v.AddArg(v0)
                return true
        }
+       // match: (LessThan (CMPconst [0] x:(ADDconst [c] y)))
+       // cond: x.Uses == 1
+       // result: (LessThanNoov (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(OpARM64LessThanNoov)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags)
+               v0.AuxInt = int64ToAuxInt(c)
+               v0.AddArg(y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (LessThan (CMPWconst [0] x:(ADDconst [c] y)))
+       // cond: x.Uses == 1
+       // result: (LessThanNoov (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(OpARM64LessThanNoov)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags)
+               v0.AuxInt = int32ToAuxInt(int32(c))
+               v0.AddArg(y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (LessThan (CMPconst [0] z:(ADD x y)))
+       // cond: z.Uses == 1
+       // result: (LessThanNoov (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(OpARM64LessThanNoov)
+               v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+               v0.AddArg2(x, y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (LessThan (CMPWconst [0] z:(ADD x y)))
+       // cond: z.Uses == 1
+       // result: (LessThanNoov (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(OpARM64LessThanNoov)
+               v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+               v0.AddArg2(x, y)
+               v.AddArg(v0)
+               return true
+       }
+       // match: (LessThan (CMPconst [0] z:(MADD a x y)))
+       // cond: z.Uses == 1
+       // result: (LessThanNoov (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(OpARM64LessThanNoov)
+               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: (LessThan (CMPconst [0] z:(MSUB a x y)))
+       // cond: z.Uses == 1
+       // result: (LessThanNoov (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(OpARM64LessThanNoov)
+               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: (LessThan (CMPWconst [0] z:(MADDW a x y)))
+       // cond: z.Uses == 1
+       // result: (LessThanNoov (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(OpARM64LessThanNoov)
+               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: (LessThan (CMPWconst [0] z:(MSUBW a x y)))
+       // cond: z.Uses == 1
+       // result: (LessThanNoov (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(OpARM64LessThanNoov)
+               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: (LessThan (FlagConstant [fc]))
        // result: (MOVDconst [b2i(fc.lt())])
        for {
index ca74ed59471de32746be2b0464e9b11eb80fa60b..eb5c1de6de735be5082411731ef9b130e4ccea26 100644 (file)
@@ -36,6 +36,7 @@ var crTests = []struct {
        {"AddConst64", testAddConst64},
        {"AddConst32", testAddConst32},
        {"AddVar64", testAddVar64},
+       {"AddVar64Cset", testAddVar64Cset},
        {"AddVar32", testAddVar32},
        {"MAddVar64", testMAddVar64},
        {"MAddVar32", testMAddVar32},
@@ -198,6 +199,41 @@ func testAddVar64(t *testing.T) {
        }
 }
 
+// var + var, cset
+func testAddVar64Cset(t *testing.T) {
+       var a int
+       if x64+v64 < 0 {
+               a = 1
+       }
+       if a != 1 {
+               t.Errorf("'%#x + %#x < 0' failed", x64, v64)
+       }
+
+       a = 0
+       if y64+v64_n >= 0 {
+               a = 1
+       }
+       if a != 1 {
+               t.Errorf("'%#x + %#x >= 0' failed", y64, v64_n)
+       }
+
+       a = 1
+       if x64+v64 >= 0 {
+               a = 0
+       }
+       if a == 0 {
+               t.Errorf("'%#x + %#x >= 0' failed", x64, v64)
+       }
+
+       a = 1
+       if y64+v64_n < 0 {
+               a = 0
+       }
+       if a == 0 {
+               t.Errorf("'%#x + %#x < 0' failed", y64, v64_n)
+       }
+}
+
 // 32-bit var+var
 func testAddVar32(t *testing.T) {
        if x32+v32 < 0 {
index ee732e06d9acaf1f03b0de3383d5e6f0a6a585d3..99589c4ce8762819a04312975f20b8097f94f651 100644 (file)
@@ -456,6 +456,7 @@ func CmpToZero_ex5(e, f int32, u uint32) int {
        }
        return 0
 }
+
 func UintLtZero(a uint8, b uint16, c uint32, d uint64) int {
        // amd64: -`(TESTB|TESTW|TESTL|TESTQ|JCC|JCS)`
        // arm64: -`(CMPW|CMP|BHS|BLO)`
@@ -704,3 +705,45 @@ func cmpToCmn(a, b, c, d int) int {
        }
        return c1 + c2 + c3 + c4 + c5 + c6 + c7 + c8 + c9 + c10 + c11
 }
+
+func cmpToCmnLessThan(a, b, c, d int) int {
+       var c1, c2, c3, c4 int
+       // arm64:`CMN`,`CSET\tMI`,-`CMP`
+       if a+1 < 0 {
+               c1 = 1
+       }
+       // arm64:`CMN`,`CSET\tMI`,-`CMP`
+       if a+b < 0 {
+               c2 = 1
+       }
+       // arm64:`CMN`,`CSET\tMI`,-`CMP`
+       if a*b+c < 0 {
+               c3 = 1
+       }
+       // arm64:`CMP`,`CSET\tMI`,-`CMN`
+       if a-b*c < 0 {
+               c4 = 1
+       }
+       return c1 + c2 + c3 + c4
+}
+
+func cmpToCmnGreaterThanEqual(a, b, c, d int) int {
+       var c1, c2, c3, c4 int
+       // arm64:`CMN`,`CSET\tPL`,-`CMP`
+       if a+1 >= 0 {
+               c1 = 1
+       }
+       // arm64:`CMN`,`CSET\tPL`,-`CMP`
+       if a+b >= 0 {
+               c2 = 1
+       }
+       // arm64:`CMN`,`CSET\tPL`,-`CMP`
+       if a*b+c >= 0 {
+               c3 = 1
+       }
+       // arm64:`CMP`,`CSET\tPL`,-`CMN`
+       if a-b*c >= 0 {
+               c4 = 1
+       }
+       return c1 + c2 + c3 + c4
+}