]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: optimize arm64's comparison
authorBen Shi <powerman1st@163.com>
Thu, 19 Jul 2018 08:09:13 +0000 (08:09 +0000)
committerBen Shi <powerman1st@163.com>
Wed, 5 Sep 2018 02:51:28 +0000 (02:51 +0000)
Add more optimization with TST/CMN.

1. A tiny benchmark shows more than 12% improvement.
TSTCMN-4                    378µs ± 0%     332µs ± 0%  -12.15%  (p=0.000 n=30+27)
(https://github.com/benshi001/ugo1/blob/master/tstcmn_test.go)

2. There is little regression in the go1 benchmark, excluding noise.

name                     old time/op    new time/op    delta
BinaryTree17-4              19.1s ± 0%     19.1s ± 0%    ~     (p=0.994 n=28+29)
Fannkuch11-4                10.0s ± 0%     10.0s ± 0%    ~     (p=0.198 n=30+25)
FmtFprintfEmpty-4           233ns ± 0%     233ns ± 0%  +0.14%  (p=0.002 n=24+30)
FmtFprintfString-4          428ns ± 0%     428ns ± 0%    ~     (all equal)
FmtFprintfInt-4             472ns ± 0%     472ns ± 0%    ~     (all equal)
FmtFprintfIntInt-4          725ns ± 0%     725ns ± 0%    ~     (all equal)
FmtFprintfPrefixedInt-4     889ns ± 0%     888ns ± 0%    ~     (p=0.632 n=28+30)
FmtFprintfFloat-4          1.20µs ± 0%    1.20µs ± 0%  +0.05%  (p=0.001 n=18+30)
FmtManyArgs-4              3.00µs ± 0%    2.99µs ± 0%  -0.07%  (p=0.001 n=27+30)
GobDecode-4                42.1ms ± 0%    42.2ms ± 0%  +0.29%  (p=0.000 n=28+28)
GobEncode-4                38.6ms ± 9%    38.8ms ± 9%    ~     (p=0.912 n=30+30)
Gzip-4                      2.07s ± 1%     2.05s ± 1%  -0.64%  (p=0.000 n=29+30)
Gunzip-4                    175ms ± 0%     175ms ± 0%  -0.15%  (p=0.001 n=30+30)
HTTPClientServer-4          872µs ± 5%     880µs ± 6%    ~     (p=0.196 n=30+29)
JSONEncode-4               88.5ms ± 1%    89.8ms ± 1%  +1.49%  (p=0.000 n=23+24)
JSONDecode-4                393ms ± 1%     390ms ± 1%  -0.89%  (p=0.000 n=28+30)
Mandelbrot200-4            19.5ms ± 0%    19.5ms ± 0%    ~     (p=0.405 n=29+28)
GoParse-4                  19.9ms ± 0%    20.0ms ± 0%  +0.27%  (p=0.000 n=30+30)
RegexpMatchEasy0_32-4       431ns ± 0%     431ns ± 0%    ~     (p=1.000 n=30+30)
RegexpMatchEasy0_1K-4      1.61µs ± 0%    1.61µs ± 0%    ~     (p=0.527 n=26+26)
RegexpMatchEasy1_32-4       443ns ± 0%     443ns ± 0%    ~     (all equal)
RegexpMatchEasy1_1K-4      2.58µs ± 1%    2.58µs ± 1%    ~     (p=0.578 n=27+25)
RegexpMatchMedium_32-4      740ns ± 0%     740ns ± 0%    ~     (p=0.357 n=30+30)
RegexpMatchMedium_1K-4      223µs ± 0%     223µs ± 0%  +0.16%  (p=0.000 n=30+29)
RegexpMatchHard_32-4       12.3µs ± 0%    12.3µs ± 0%    ~     (p=0.236 n=27+27)
RegexpMatchHard_1K-4        371µs ± 0%     371µs ± 0%  +0.09%  (p=0.000 n=30+27)
Revcomp-4                   2.85s ± 0%     2.85s ± 0%    ~     (p=0.057 n=28+25)
Template-4                  408ms ± 1%     409ms ± 1%    ~     (p=0.117 n=29+29)
TimeParse-4                1.93µs ± 0%    1.93µs ± 0%    ~     (p=0.535 n=29+28)
TimeFormat-4               1.99µs ± 0%    1.99µs ± 0%    ~     (p=0.168 n=29+28)
[Geo mean]                  306µs          307µs       +0.07%

name                     old speed      new speed      delta
GobDecode-4              18.3MB/s ± 0%  18.2MB/s ± 0%  -0.31%  (p=0.000 n=28+29)
GobEncode-4              19.9MB/s ± 8%  19.8MB/s ± 9%    ~     (p=0.923 n=30+30)
Gzip-4                   9.39MB/s ± 1%  9.45MB/s ± 1%  +0.65%  (p=0.000 n=29+30)
Gunzip-4                  111MB/s ± 0%   111MB/s ± 0%  +0.15%  (p=0.001 n=30+30)
JSONEncode-4             21.9MB/s ± 1%  21.6MB/s ± 1%  -1.45%  (p=0.000 n=23+23)
JSONDecode-4             4.94MB/s ± 1%  4.98MB/s ± 1%  +0.84%  (p=0.000 n=27+30)
GoParse-4                2.91MB/s ± 0%  2.90MB/s ± 0%  -0.34%  (p=0.000 n=21+22)
RegexpMatchEasy0_32-4    74.1MB/s ± 0%  74.1MB/s ± 0%    ~     (p=0.469 n=29+28)
RegexpMatchEasy0_1K-4     634MB/s ± 0%   634MB/s ± 0%    ~     (p=0.978 n=24+28)
RegexpMatchEasy1_32-4    72.2MB/s ± 0%  72.2MB/s ± 0%    ~     (p=0.064 n=27+29)
RegexpMatchEasy1_1K-4     396MB/s ± 1%   396MB/s ± 1%    ~     (p=0.583 n=27+25)
RegexpMatchMedium_32-4   1.35MB/s ± 0%  1.35MB/s ± 0%    ~     (all equal)
RegexpMatchMedium_1K-4   4.60MB/s ± 0%  4.59MB/s ± 0%  -0.14%  (p=0.000 n=30+26)
RegexpMatchHard_32-4     2.61MB/s ± 0%  2.61MB/s ± 0%    ~     (all equal)
RegexpMatchHard_1K-4     2.76MB/s ± 0%  2.76MB/s ± 0%    ~     (all equal)
Revcomp-4                89.1MB/s ± 0%  89.1MB/s ± 0%    ~     (p=0.059 n=28+25)
Template-4               4.75MB/s ± 1%  4.75MB/s ± 1%    ~     (p=0.106 n=29+29)
[Geo mean]               18.3MB/s       18.3MB/s       -0.07%

Change-Id: I3cd76ce63e84b0c3cebabf9fa3573b76a7343899
Reviewed-on: https://go-review.googlesource.com/124935
Run-TryBot: Ben Shi <powerman1st@163.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
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
test/codegen/comparisons.go

index 374ece24e581db580223e186c8612fea832585e3..ede7ed3d7a093306c9a2c40feadab2926838758d 100644 (file)
 
 (EQ (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (EQ (TST x y) yes no)
 (NE (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (NE (TST x y) yes no)
+(LT (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (LT (TST x y) yes no)
+(LE (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (LE (TST x y) yes no)
+(GT (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (GT (TST x y) yes no)
+(GE (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (GE (TST x y) yes no)
+
 (EQ (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (EQ (TSTW x y) yes no)
 (NE (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (NE (TSTW x y) yes no)
+(LT (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (LT (TSTW x y) yes no)
+(LE (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (LE (TSTW x y) yes no)
+(GT (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (GT (TSTW x y) yes no)
+(GE (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (GE (TSTW x y) yes no)
 
 (EQ (CMPconst [0] x:(ANDconst [c] y)) yes no) && x.Uses == 1 -> (EQ (TSTconst [c] y) yes no)
 (NE (CMPconst [0] x:(ANDconst [c] y)) yes no) && x.Uses == 1 -> (NE (TSTconst [c] y) yes no)
 (GT (CMPconst [0] x:(ANDconst [c] y)) yes no) && x.Uses == 1 -> (GT (TSTconst [c] y) yes no)
 (GE (CMPconst [0] x:(ANDconst [c] y)) yes no) && x.Uses == 1 -> (GE (TSTconst [c] y) yes no)
 
+(EQ (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (EQ (CMNconst [c] y) yes no)
+(NE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (NE (CMNconst [c] y) yes no)
+(LT (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (LT (CMNconst [c] y) yes no)
+(LE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (LE (CMNconst [c] y) yes no)
+(GT (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (GT (CMNconst [c] y) yes no)
+(GE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (GE (CMNconst [c] y) yes no)
+
+(EQ (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (EQ (CMNWconst [c] y) yes no)
+(NE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (NE (CMNWconst [c] y) yes no)
+(LT (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (LT (CMNWconst [c] y) yes no)
+(LE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (LE (CMNWconst [c] y) yes no)
+(GT (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (GT (CMNWconst [c] y) yes no)
+(GE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (GE (CMNWconst [c] y) yes no)
+
 (EQ (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (EQ (CMN x y) yes no)
 (NE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (NE (CMN x y) yes no)
+(LT (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (LT (CMN x y) yes no)
+(LE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (LE (CMN x y) yes no)
+(GT (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (GT (CMN x y) yes no)
+(GE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (GE (CMN x y) yes no)
+
+(EQ (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (EQ (CMNW x y) yes no)
+(NE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (NE (CMNW x y) yes no)
+(LT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (LT (CMNW x y) yes no)
+(LE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (LE (CMNW x y) yes no)
+(GT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (GT (CMNW x y) yes no)
+(GE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (GE (CMNW x y) yes no)
+
 (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)
+(LT (CMP x z:(NEG y)) yes no) && z.Uses == 1 -> (LT (CMN x y) yes no)
+(LE (CMP x z:(NEG y)) yes no) && z.Uses == 1 -> (LE (CMN x y) yes no)
+(GT (CMP x z:(NEG y)) yes no) && z.Uses == 1 -> (GT (CMN x y) yes no)
+(GE (CMP x z:(NEG y)) yes no) && z.Uses == 1 -> (GE (CMN x y) yes no)
+
+(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)
+(LT (CMPW x z:(NEG y)) yes no) && z.Uses == 1 -> (LT (CMNW x y) yes no)
+(LE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 -> (LE (CMNW x y) yes no)
+(GT (CMPW x z:(NEG y)) yes no) && z.Uses == 1 -> (GT (CMNW x y) yes no)
+(GE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 -> (GE (CMNW x y) yes no)
 
 (EQ (CMPconst [0] x) yes no) -> (Z x yes no)
 (NE (CMPconst [0] x) yes no) -> (NZ x yes no)
 (OR  x (MOVDconst [c])) -> (ORconst  [c] x)
 (XOR x (MOVDconst [c])) -> (XORconst [c] x)
 (TST x (MOVDconst [c])) -> (TSTconst [c] x)
+(TSTW x (MOVDconst [c])) -> (TSTWconst [c] x)
 (CMN x (MOVDconst [c])) -> (CMNconst [c] x)
+(CMNW x (MOVDconst [c])) -> (CMNWconst [c] x)
 (BIC x (MOVDconst [c])) -> (ANDconst [^c] x)
 (EON x (MOVDconst [c])) -> (XORconst [^c] x)
 (ORN x (MOVDconst [c])) -> (ORconst  [^c] x)
index 2c434f4a740cc9060ed94e8dc2e6b4c280a16404..eb0ad530a1a4b3fa47dde7b98710a2fc746f63b3 100644 (file)
@@ -258,13 +258,13 @@ func init() {
                {name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", aux: "Int64", typ: "Flags"},   // arg0 compare to auxInt
                {name: "CMPW", argLength: 2, reg: gp2flags, asm: "CMPW", typ: "Flags"},                    // arg0 compare to arg1, 32 bit
                {name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", aux: "Int32", typ: "Flags"}, // arg0 compare to auxInt, 32 bit
-               {name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags"},                      // arg0 compare to -arg1
+               {name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags", commutative: true},   // arg0 compare to -arg1
                {name: "CMNconst", argLength: 1, reg: gp1flags, asm: "CMN", aux: "Int64", typ: "Flags"},   // arg0 compare to -auxInt
-               {name: "CMNW", argLength: 2, reg: gp2flags, asm: "CMNW", typ: "Flags"},                    // arg0 compare to -arg1, 32 bit
+               {name: "CMNW", argLength: 2, reg: gp2flags, asm: "CMNW", typ: "Flags", commutative: true}, // arg0 compare to -arg1, 32 bit
                {name: "CMNWconst", argLength: 1, reg: gp1flags, asm: "CMNW", aux: "Int32", typ: "Flags"}, // arg0 compare to -auxInt, 32 bit
-               {name: "TST", argLength: 2, reg: gp2flags, asm: "TST", typ: "Flags"},                      // arg0 & arg1 compare to 0
+               {name: "TST", argLength: 2, reg: gp2flags, asm: "TST", typ: "Flags", commutative: true},   // arg0 & arg1 compare to 0
                {name: "TSTconst", argLength: 1, reg: gp1flags, asm: "TST", aux: "Int64", typ: "Flags"},   // arg0 & auxInt compare to 0
-               {name: "TSTW", argLength: 2, reg: gp2flags, asm: "TSTW", typ: "Flags"},                    // arg0 & arg1 compare to 0, 32 bit
+               {name: "TSTW", argLength: 2, reg: gp2flags, asm: "TSTW", typ: "Flags", commutative: true}, // arg0 & arg1 compare to 0, 32 bit
                {name: "TSTWconst", argLength: 1, reg: gp1flags, asm: "TSTW", aux: "Int32", typ: "Flags"}, // arg0 & auxInt compare to 0, 32 bit
                {name: "FCMPS", argLength: 2, reg: fp2flags, asm: "FCMPS", typ: "Flags"},                  // arg0 compare to arg1, float32
                {name: "FCMPD", argLength: 2, reg: fp2flags, asm: "FCMPD", typ: "Flags"},                  // arg0 compare to arg1, float64
index 6243bfca4dabe268c92e14ddfa6ec3fcd02dea55..0ff15db91484214f7b7d5fb4286b6803b6a1c575 100644 (file)
@@ -15205,9 +15205,10 @@ var opcodeTable = [...]opInfo{
                },
        },
        {
-               name:   "CMN",
-               argLen: 2,
-               asm:    arm64.ACMN,
+               name:        "CMN",
+               argLen:      2,
+               commutative: true,
+               asm:         arm64.ACMN,
                reg: regInfo{
                        inputs: []inputInfo{
                                {0, 805044223}, // 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 g R30
@@ -15227,9 +15228,10 @@ var opcodeTable = [...]opInfo{
                },
        },
        {
-               name:   "CMNW",
-               argLen: 2,
-               asm:    arm64.ACMNW,
+               name:        "CMNW",
+               argLen:      2,
+               commutative: true,
+               asm:         arm64.ACMNW,
                reg: regInfo{
                        inputs: []inputInfo{
                                {0, 805044223}, // 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 g R30
@@ -15249,9 +15251,10 @@ var opcodeTable = [...]opInfo{
                },
        },
        {
-               name:   "TST",
-               argLen: 2,
-               asm:    arm64.ATST,
+               name:        "TST",
+               argLen:      2,
+               commutative: true,
+               asm:         arm64.ATST,
                reg: regInfo{
                        inputs: []inputInfo{
                                {0, 805044223}, // 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 g R30
@@ -15271,9 +15274,10 @@ var opcodeTable = [...]opInfo{
                },
        },
        {
-               name:   "TSTW",
-               argLen: 2,
-               asm:    arm64.ATSTW,
+               name:        "TSTW",
+               argLen:      2,
+               commutative: true,
+               asm:         arm64.ATSTW,
                reg: regInfo{
                        inputs: []inputInfo{
                                {0, 805044223}, // 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 g R30
index a84d1afdf43c0bd61a22f82bf12bc50ca26d8ee9..fbdf3529981a71bd8b4fc09ac9c05217a7ba50a4 100644 (file)
@@ -45,6 +45,8 @@ func rewriteValueARM64(v *Value) bool {
                return rewriteValueARM64_OpARM64BICshiftRL_0(v)
        case OpARM64CMN:
                return rewriteValueARM64_OpARM64CMN_0(v)
+       case OpARM64CMNW:
+               return rewriteValueARM64_OpARM64CMNW_0(v)
        case OpARM64CMNWconst:
                return rewriteValueARM64_OpARM64CMNWconst_0(v)
        case OpARM64CMNconst:
@@ -295,6 +297,8 @@ func rewriteValueARM64(v *Value) bool {
                return rewriteValueARM64_OpARM64SUBshiftRL_0(v)
        case OpARM64TST:
                return rewriteValueARM64_OpARM64TST_0(v)
+       case OpARM64TSTW:
+               return rewriteValueARM64_OpARM64TSTW_0(v)
        case OpARM64TSTWconst:
                return rewriteValueARM64_OpARM64TSTWconst_0(v)
        case OpARM64TSTconst:
@@ -2375,6 +2379,57 @@ func rewriteValueARM64_OpARM64CMN_0(v *Value) bool {
                v.AddArg(x)
                return true
        }
+       // match: (CMN (MOVDconst [c]) x)
+       // cond:
+       // result: (CMNconst [c] x)
+       for {
+               _ = v.Args[1]
+               v_0 := v.Args[0]
+               if v_0.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := v_0.AuxInt
+               x := v.Args[1]
+               v.reset(OpARM64CMNconst)
+               v.AuxInt = c
+               v.AddArg(x)
+               return true
+       }
+       return false
+}
+func rewriteValueARM64_OpARM64CMNW_0(v *Value) bool {
+       // match: (CMNW x (MOVDconst [c]))
+       // cond:
+       // result: (CMNWconst [c] x)
+       for {
+               _ = v.Args[1]
+               x := v.Args[0]
+               v_1 := v.Args[1]
+               if v_1.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := v_1.AuxInt
+               v.reset(OpARM64CMNWconst)
+               v.AuxInt = c
+               v.AddArg(x)
+               return true
+       }
+       // match: (CMNW (MOVDconst [c]) x)
+       // cond:
+       // result: (CMNWconst [c] x)
+       for {
+               _ = v.Args[1]
+               v_0 := v.Args[0]
+               if v_0.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := v_0.AuxInt
+               x := v.Args[1]
+               v.reset(OpARM64CMNWconst)
+               v.AuxInt = c
+               v.AddArg(x)
+               return true
+       }
        return false
 }
 func rewriteValueARM64_OpARM64CMNWconst_0(v *Value) bool {
@@ -25219,6 +25274,57 @@ func rewriteValueARM64_OpARM64TST_0(v *Value) bool {
                v.AddArg(x)
                return true
        }
+       // match: (TST (MOVDconst [c]) x)
+       // cond:
+       // result: (TSTconst [c] x)
+       for {
+               _ = v.Args[1]
+               v_0 := v.Args[0]
+               if v_0.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := v_0.AuxInt
+               x := v.Args[1]
+               v.reset(OpARM64TSTconst)
+               v.AuxInt = c
+               v.AddArg(x)
+               return true
+       }
+       return false
+}
+func rewriteValueARM64_OpARM64TSTW_0(v *Value) bool {
+       // match: (TSTW x (MOVDconst [c]))
+       // cond:
+       // result: (TSTWconst [c] x)
+       for {
+               _ = v.Args[1]
+               x := v.Args[0]
+               v_1 := v.Args[1]
+               if v_1.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := v_1.AuxInt
+               v.reset(OpARM64TSTWconst)
+               v.AuxInt = c
+               v.AddArg(x)
+               return true
+       }
+       // match: (TSTW (MOVDconst [c]) x)
+       // cond:
+       // result: (TSTWconst [c] x)
+       for {
+               _ = v.Args[1]
+               v_0 := v.Args[0]
+               if v_0.Op != OpARM64MOVDconst {
+                       break
+               }
+               c := v_0.AuxInt
+               x := v.Args[1]
+               v.reset(OpARM64TSTWconst)
+               v.AuxInt = c
+               v.AddArg(x)
+               return true
+       }
        return false
 }
 func rewriteValueARM64_OpARM64TSTWconst_0(v *Value) bool {
@@ -32789,6 +32895,62 @@ func rewriteBlockARM64(b *Block) bool {
                        b.Aux = nil
                        return true
                }
+               // match: (EQ (CMPconst [0] x:(ADDconst [c] y)) yes no)
+               // cond: x.Uses == 1
+               // result: (EQ (CMNconst [c] y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       x := v.Args[0]
+                       if x.Op != OpARM64ADDconst {
+                               break
+                       }
+                       c := x.AuxInt
+                       y := x.Args[0]
+                       if !(x.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64EQ
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags)
+                       v0.AuxInt = c
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (EQ (CMPWconst [0] x:(ADDconst [c] y)) yes no)
+               // cond: x.Uses == 1
+               // result: (EQ (CMNWconst [c] y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       x := v.Args[0]
+                       if x.Op != OpARM64ADDconst {
+                               break
+                       }
+                       c := x.AuxInt
+                       y := x.Args[0]
+                       if !(x.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64EQ
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags)
+                       v0.AuxInt = c
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
                // match: (EQ (CMPconst [0] z:(ADD x y)) yes no)
                // cond: z.Uses == 1
                // result: (EQ (CMN x y) yes no)
@@ -32818,6 +32980,35 @@ func rewriteBlockARM64(b *Block) bool {
                        b.Aux = nil
                        return true
                }
+               // match: (EQ (CMPWconst [0] z:(ADD x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (EQ (CMNW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64ADD {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64EQ
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
                // match: (EQ (CMP x z:(NEG y)) yes no)
                // cond: z.Uses == 1
                // result: (EQ (CMN x y) yes no)
@@ -32844,6 +33035,32 @@ func rewriteBlockARM64(b *Block) bool {
                        b.Aux = nil
                        return true
                }
+               // match: (EQ (CMPW x z:(NEG y)) yes no)
+               // cond: z.Uses == 1
+               // result: (EQ (CMNW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPW {
+                               break
+                       }
+                       _ = v.Args[1]
+                       x := v.Args[0]
+                       z := v.Args[1]
+                       if z.Op != OpARM64NEG {
+                               break
+                       }
+                       y := z.Args[0]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64EQ
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
                // match: (EQ (CMPconst [0] x) yes no)
                // cond:
                // result: (Z x yes no)
@@ -33158,6 +33375,64 @@ func rewriteBlockARM64(b *Block) bool {
                        b.Aux = nil
                        return true
                }
+               // match: (GE (CMPconst [0] z:(AND x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (GE (TST x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64AND {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GE
+                       v0 := b.NewValue0(v.Pos, OpARM64TST, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (GE (CMPWconst [0] z:(AND x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (GE (TSTW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64AND {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GE
+                       v0 := b.NewValue0(v.Pos, OpARM64TSTW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
                // match: (GE (CMPconst [0] x:(ANDconst [c] y)) yes no)
                // cond: x.Uses == 1
                // result: (GE (TSTconst [c] y) yes no)
@@ -33186,6 +33461,172 @@ func rewriteBlockARM64(b *Block) bool {
                        b.Aux = nil
                        return true
                }
+               // match: (GE (CMPconst [0] x:(ADDconst [c] y)) yes no)
+               // cond: x.Uses == 1
+               // result: (GE (CMNconst [c] y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       x := v.Args[0]
+                       if x.Op != OpARM64ADDconst {
+                               break
+                       }
+                       c := x.AuxInt
+                       y := x.Args[0]
+                       if !(x.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags)
+                       v0.AuxInt = c
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (GE (CMPWconst [0] x:(ADDconst [c] y)) yes no)
+               // cond: x.Uses == 1
+               // result: (GE (CMNWconst [c] y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       x := v.Args[0]
+                       if x.Op != OpARM64ADDconst {
+                               break
+                       }
+                       c := x.AuxInt
+                       y := x.Args[0]
+                       if !(x.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags)
+                       v0.AuxInt = c
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (GE (CMPconst [0] z:(ADD x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (GE (CMN x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64ADD {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (GE (CMPWconst [0] z:(ADD x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (GE (CMNW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64ADD {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (GE (CMP x z:(NEG y)) yes no)
+               // cond: z.Uses == 1
+               // result: (GE (CMN x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMP {
+                               break
+                       }
+                       _ = v.Args[1]
+                       x := v.Args[0]
+                       z := v.Args[1]
+                       if z.Op != OpARM64NEG {
+                               break
+                       }
+                       y := z.Args[0]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (GE (CMPW x z:(NEG y)) yes no)
+               // cond: z.Uses == 1
+               // result: (GE (CMNW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPW {
+                               break
+                       }
+                       _ = v.Args[1]
+                       x := v.Args[0]
+                       z := v.Args[1]
+                       if z.Op != OpARM64NEG {
+                               break
+                       }
+                       y := z.Args[0]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
                // match: (GE (CMPconst [0] z:(MADD a x y)) yes no)
                // cond: z.Uses==1
                // result: (GE (CMN a (MUL <x.Type> x y)) yes no)
@@ -33462,6 +33903,64 @@ func rewriteBlockARM64(b *Block) bool {
                        b.Aux = nil
                        return true
                }
+               // match: (GT (CMPconst [0] z:(AND x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (GT (TST x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64AND {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GT
+                       v0 := b.NewValue0(v.Pos, OpARM64TST, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (GT (CMPWconst [0] z:(AND x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (GT (TSTW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64AND {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GT
+                       v0 := b.NewValue0(v.Pos, OpARM64TSTW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
                // match: (GT (CMPconst [0] x:(ANDconst [c] y)) yes no)
                // cond: x.Uses == 1
                // result: (GT (TSTconst [c] y) yes no)
@@ -33490,6 +33989,172 @@ func rewriteBlockARM64(b *Block) bool {
                        b.Aux = nil
                        return true
                }
+               // match: (GT (CMPconst [0] x:(ADDconst [c] y)) yes no)
+               // cond: x.Uses == 1
+               // result: (GT (CMNconst [c] y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       x := v.Args[0]
+                       if x.Op != OpARM64ADDconst {
+                               break
+                       }
+                       c := x.AuxInt
+                       y := x.Args[0]
+                       if !(x.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GT
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags)
+                       v0.AuxInt = c
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (GT (CMPWconst [0] x:(ADDconst [c] y)) yes no)
+               // cond: x.Uses == 1
+               // result: (GT (CMNWconst [c] y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       x := v.Args[0]
+                       if x.Op != OpARM64ADDconst {
+                               break
+                       }
+                       c := x.AuxInt
+                       y := x.Args[0]
+                       if !(x.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GT
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags)
+                       v0.AuxInt = c
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (GT (CMPconst [0] z:(ADD x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (GT (CMN x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64ADD {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GT
+                       v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (GT (CMPWconst [0] z:(ADD x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (GT (CMNW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64ADD {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GT
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (GT (CMP x z:(NEG y)) yes no)
+               // cond: z.Uses == 1
+               // result: (GT (CMN x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMP {
+                               break
+                       }
+                       _ = v.Args[1]
+                       x := v.Args[0]
+                       z := v.Args[1]
+                       if z.Op != OpARM64NEG {
+                               break
+                       }
+                       y := z.Args[0]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GT
+                       v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (GT (CMPW x z:(NEG y)) yes no)
+               // cond: z.Uses == 1
+               // result: (GT (CMNW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPW {
+                               break
+                       }
+                       _ = v.Args[1]
+                       x := v.Args[0]
+                       z := v.Args[1]
+                       if z.Op != OpARM64NEG {
+                               break
+                       }
+                       y := z.Args[0]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64GT
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
                // match: (GT (CMPconst [0] z:(MADD a x y)) yes no)
                // cond: z.Uses==1
                // result: (GT (CMN a (MUL <x.Type> x y)) yes no)
@@ -33886,6 +34551,64 @@ func rewriteBlockARM64(b *Block) bool {
                        b.Aux = nil
                        return true
                }
+               // match: (LE (CMPconst [0] z:(AND x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (LE (TST x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64AND {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LE
+                       v0 := b.NewValue0(v.Pos, OpARM64TST, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (LE (CMPWconst [0] z:(AND x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (LE (TSTW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64AND {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LE
+                       v0 := b.NewValue0(v.Pos, OpARM64TSTW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
                // match: (LE (CMPconst [0] x:(ANDconst [c] y)) yes no)
                // cond: x.Uses == 1
                // result: (LE (TSTconst [c] y) yes no)
@@ -33914,6 +34637,172 @@ func rewriteBlockARM64(b *Block) bool {
                        b.Aux = nil
                        return true
                }
+               // match: (LE (CMPconst [0] x:(ADDconst [c] y)) yes no)
+               // cond: x.Uses == 1
+               // result: (LE (CMNconst [c] y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       x := v.Args[0]
+                       if x.Op != OpARM64ADDconst {
+                               break
+                       }
+                       c := x.AuxInt
+                       y := x.Args[0]
+                       if !(x.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags)
+                       v0.AuxInt = c
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (LE (CMPWconst [0] x:(ADDconst [c] y)) yes no)
+               // cond: x.Uses == 1
+               // result: (LE (CMNWconst [c] y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       x := v.Args[0]
+                       if x.Op != OpARM64ADDconst {
+                               break
+                       }
+                       c := x.AuxInt
+                       y := x.Args[0]
+                       if !(x.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags)
+                       v0.AuxInt = c
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (LE (CMPconst [0] z:(ADD x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (LE (CMN x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64ADD {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (LE (CMPWconst [0] z:(ADD x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (LE (CMNW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64ADD {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (LE (CMP x z:(NEG y)) yes no)
+               // cond: z.Uses == 1
+               // result: (LE (CMN x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMP {
+                               break
+                       }
+                       _ = v.Args[1]
+                       x := v.Args[0]
+                       z := v.Args[1]
+                       if z.Op != OpARM64NEG {
+                               break
+                       }
+                       y := z.Args[0]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (LE (CMPW x z:(NEG y)) yes no)
+               // cond: z.Uses == 1
+               // result: (LE (CMNW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPW {
+                               break
+                       }
+                       _ = v.Args[1]
+                       x := v.Args[0]
+                       z := v.Args[1]
+                       if z.Op != OpARM64NEG {
+                               break
+                       }
+                       y := z.Args[0]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
                // match: (LE (CMPconst [0] z:(MADD a x y)) yes no)
                // cond: z.Uses==1
                // result: (LE (CMN a (MUL <x.Type> x y)) yes no)
@@ -34156,6 +35045,64 @@ func rewriteBlockARM64(b *Block) bool {
                        b.Aux = nil
                        return true
                }
+               // match: (LT (CMPconst [0] z:(AND x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (LT (TST x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64AND {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LT
+                       v0 := b.NewValue0(v.Pos, OpARM64TST, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (LT (CMPWconst [0] z:(AND x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (LT (TSTW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64AND {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LT
+                       v0 := b.NewValue0(v.Pos, OpARM64TSTW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
                // match: (LT (CMPconst [0] x:(ANDconst [c] y)) yes no)
                // cond: x.Uses == 1
                // result: (LT (TSTconst [c] y) yes no)
@@ -34184,6 +35131,172 @@ func rewriteBlockARM64(b *Block) bool {
                        b.Aux = nil
                        return true
                }
+               // match: (LT (CMPconst [0] x:(ADDconst [c] y)) yes no)
+               // cond: x.Uses == 1
+               // result: (LT (CMNconst [c] y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       x := v.Args[0]
+                       if x.Op != OpARM64ADDconst {
+                               break
+                       }
+                       c := x.AuxInt
+                       y := x.Args[0]
+                       if !(x.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LT
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags)
+                       v0.AuxInt = c
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (LT (CMPWconst [0] x:(ADDconst [c] y)) yes no)
+               // cond: x.Uses == 1
+               // result: (LT (CMNWconst [c] y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       x := v.Args[0]
+                       if x.Op != OpARM64ADDconst {
+                               break
+                       }
+                       c := x.AuxInt
+                       y := x.Args[0]
+                       if !(x.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LT
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags)
+                       v0.AuxInt = c
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (LT (CMPconst [0] z:(ADD x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (LT (CMN x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64ADD {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LT
+                       v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (LT (CMPWconst [0] z:(ADD x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (LT (CMNW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64ADD {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LT
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (LT (CMP x z:(NEG y)) yes no)
+               // cond: z.Uses == 1
+               // result: (LT (CMN x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMP {
+                               break
+                       }
+                       _ = v.Args[1]
+                       x := v.Args[0]
+                       z := v.Args[1]
+                       if z.Op != OpARM64NEG {
+                               break
+                       }
+                       y := z.Args[0]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LT
+                       v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (LT (CMPW x z:(NEG y)) yes no)
+               // cond: z.Uses == 1
+               // result: (LT (CMNW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPW {
+                               break
+                       }
+                       _ = v.Args[1]
+                       x := v.Args[0]
+                       z := v.Args[1]
+                       if z.Op != OpARM64NEG {
+                               break
+                       }
+                       y := z.Args[0]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64LT
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
                // match: (LT (CMPconst [0] z:(MADD a x y)) yes no)
                // cond: z.Uses==1
                // result: (LT (CMN a (MUL <x.Type> x y)) yes no)
@@ -34547,6 +35660,62 @@ func rewriteBlockARM64(b *Block) bool {
                        b.Aux = nil
                        return true
                }
+               // match: (NE (CMPconst [0] x:(ADDconst [c] y)) yes no)
+               // cond: x.Uses == 1
+               // result: (NE (CMNconst [c] y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       x := v.Args[0]
+                       if x.Op != OpARM64ADDconst {
+                               break
+                       }
+                       c := x.AuxInt
+                       y := x.Args[0]
+                       if !(x.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64NE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags)
+                       v0.AuxInt = c
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
+               // match: (NE (CMPWconst [0] x:(ADDconst [c] y)) yes no)
+               // cond: x.Uses == 1
+               // result: (NE (CMNWconst [c] y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       x := v.Args[0]
+                       if x.Op != OpARM64ADDconst {
+                               break
+                       }
+                       c := x.AuxInt
+                       y := x.Args[0]
+                       if !(x.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64NE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags)
+                       v0.AuxInt = c
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
                // match: (NE (CMPconst [0] z:(ADD x y)) yes no)
                // cond: z.Uses == 1
                // result: (NE (CMN x y) yes no)
@@ -34576,6 +35745,35 @@ func rewriteBlockARM64(b *Block) bool {
                        b.Aux = nil
                        return true
                }
+               // match: (NE (CMPWconst [0] z:(ADD x y)) yes no)
+               // cond: z.Uses == 1
+               // result: (NE (CMNW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPWconst {
+                               break
+                       }
+                       if v.AuxInt != 0 {
+                               break
+                       }
+                       z := v.Args[0]
+                       if z.Op != OpARM64ADD {
+                               break
+                       }
+                       _ = z.Args[1]
+                       x := z.Args[0]
+                       y := z.Args[1]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64NE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
                // match: (NE (CMP x z:(NEG y)) yes no)
                // cond: z.Uses == 1
                // result: (NE (CMN x y) yes no)
@@ -34602,6 +35800,32 @@ func rewriteBlockARM64(b *Block) bool {
                        b.Aux = nil
                        return true
                }
+               // match: (NE (CMPW x z:(NEG y)) yes no)
+               // cond: z.Uses == 1
+               // result: (NE (CMNW x y) yes no)
+               for {
+                       v := b.Control
+                       if v.Op != OpARM64CMPW {
+                               break
+                       }
+                       _ = v.Args[1]
+                       x := v.Args[0]
+                       z := v.Args[1]
+                       if z.Op != OpARM64NEG {
+                               break
+                       }
+                       y := z.Args[0]
+                       if !(z.Uses == 1) {
+                               break
+                       }
+                       b.Kind = BlockARM64NE
+                       v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags)
+                       v0.AddArg(x)
+                       v0.AddArg(y)
+                       b.SetControl(v0)
+                       b.Aux = nil
+                       return true
+               }
                // match: (NE (CMPconst [0] x) yes no)
                // cond:
                // result: (NZ x yes no)
index 22d06363ba182325819077a8971891eb2f6a0219..8475b130c20680eb9a8089cfcace497a6415de4e 100644 (file)
@@ -158,13 +158,39 @@ func CmpZero4(a int64, ptr *int) {
        }
 }
 
-func CmpToZero(a, b int32) int32 {
-       if a&b < 0 { // arm:`TST`,-`AND`
+func CmpToZero(a, b, d int32) int32 {
+       // arm:`TST`,-`AND`
+       // arm64:`TSTW`,-`AND`
+       c0 := a&b < 0
+       // arm:`CMN`,-`ADD`
+       // arm64:`CMNW`,-`ADD`
+       c1 := a+b < 0
+       // arm:`TEQ`,-`XOR`
+       c2 := a^b < 0
+       // arm64:`TST`,-`AND`
+       c3 := int64(a)&int64(b) < 0
+       // arm64:`CMN`,-`ADD`
+       c4 := int64(a)+int64(b) < 0
+       // not optimized to CMNW/CMN due to further use of b+d
+       // arm64:`ADD`,-`CMNW`
+       c5 := b+d == 0
+       // not optimized to TSTW/TST due to further use of a&d
+       // arm64:`AND`,-`TSTW`
+       c6 := a&d >= 0
+       if c0 {
                return 1
-       } else if a+b < 0 { // arm:`CMN`,-`ADD`
+       } else if c1 {
                return 2
-       } else if a^b < 0 { // arm:`TEQ`,-`XOR`
+       } else if c2 {
                return 3
+       } else if c3 {
+               return 4
+       } else if c4 {
+               return 5
+       } else if c5 {
+               return b + d
+       } else if c6 {
+               return a & d
        } else {
                return 0
        }