]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj/arm64: fix the bug of incorrect handling negative offset of LDP...
authorfanzha02 <fannie.zhang@arm.com>
Wed, 21 Mar 2018 10:49:24 +0000 (10:49 +0000)
committerCherry Zhang <cherryyz@google.com>
Fri, 13 Apr 2018 15:37:21 +0000 (15:37 +0000)
The current assembler will report error when the negative offset is in
the range of [-256, 0) and is not the multiples of 4/8.

The fix introduces C_NSAUTO_8, C_NSAUTO_4 and C_NAUTO4K. C_NPAUTO
includes C_NSAUTO_8 instead of C_NSAUTO, C_NAUTO4K includes C_NSAUTO_8,
C_NSAUTO_4 and C_NSAUTO. So that assembler will encode the negative offset
that is greater than -4095 and is not the multiples of 4/8 as two instructions.

Add the test cases.

Fixed #24471

Change-Id: I42f34e3b8a9fc52c9e8b41504294271aafade639
Reviewed-on: https://go-review.googlesource.com/102635
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/asm/internal/asm/testdata/arm64.s
src/cmd/internal/obj/arm64/a.out.go
src/cmd/internal/obj/arm64/anames7.go
src/cmd/internal/obj/arm64/asm7.go

index ec32e0ff34aa6699c6e2dfe2cf3cf848ae1a665c..b5d44ebe50f62b356b30f84ea0dbf2211de5be57 100644 (file)
@@ -540,8 +540,12 @@ again:
        LDP     1024(RSP), (R1, R2) // fb031091610b40a9
        LDP.W   8(RSP), (R1, R2)    // e18bc0a9
        LDP.P   8(RSP), (R1, R2)    // e18bc0a8
+       LDP     -31(R0), (R1, R2)   // 1b7c00d1610b40a9
+       LDP     -4(R0), (R1, R2)    // 1b1000d1610b40a9
+       LDP     -8(R0), (R1, R2)    // 01887fa9
        LDP     x(SB), (R1, R2)
        LDP     x+8(SB), (R1, R2)
+       LDPW    -5(R0), (R1, R2)    // 1b1400d1610b4029
        LDPW    (R0), (R1, R2)      // 01084029
        LDPW    4(R0), (R1, R2)     // 01884029
        LDPW    -4(R0), (R1, R2)    // 01887f29
@@ -579,6 +583,7 @@ again:
        STP.W   (R3, R4), 8(R5)     // a39080a9
        STP.P   (R3, R4), 8(R5)     // a39080a8
        STP     (R3, R4), -8(R5)    // a3903fa9
+       STP     (R3, R4), -4(R5)    // bb1000d1631300a9
        STP     (R3, R4), 11(R0)    // 1b2c0091631300a9
        STP     (R3, R4), 1024(R0)  // 1b001091631300a9
        STP     (R3, R4), (RSP)     // e31300a9
@@ -595,6 +600,7 @@ again:
        STPW.W  (R3, R4), 4(R5)     // a3908029
        STPW.P  (R3, R4), 4(R5)     // a3908028
        STPW    (R3, R4), -4(R5)    // a3903f29
+       STPW    (R3, R4), -5(R5)    // bb1400d163130029
        STPW    (R3, R4), 11(R0)    // 1b2c009163130029
        STPW    (R3, R4), 1024(R0)  // 1b00109163130029
        STPW    (R3, R4), (RSP)     // e3130029
index 30102041099f3e288e38713c5485aa2d780072bc..70cc522a463f1b9712e598b3f837ecd5cd4a2e3d 100644 (file)
@@ -425,8 +425,11 @@ const (
        C_LBRA
 
        C_ZAUTO      // 0(RSP)
-       C_NPAUTO     // -512 <= x < 0, 0 mod 8
+       C_NSAUTO_8   // -256 <= x < 0, 0 mod 8
+       C_NSAUTO_4   // -256 <= x < 0, 0 mod 4
        C_NSAUTO     // -256 <= x < 0
+       C_NPAUTO     // -512 <= x < 0, 0 mod 8
+       C_NAUTO4K    // -4095 <= x < 0
        C_PSAUTO_8   // 0 to 255, 0 mod 8
        C_PSAUTO_4   // 0 to 255, 0 mod 4
        C_PSAUTO     // 0 to 255
@@ -450,9 +453,12 @@ const (
        C_SEXT16 // 0 to 65520
        C_LEXT
 
-       C_ZOREG  // 0(R)
-       C_NPOREG // must mirror NPAUTO, etc
+       C_ZOREG    // 0(R)
+       C_NSOREG_8 // must mirror C_NSAUTO_8, etc
+       C_NSOREG_4
        C_NSOREG
+       C_NPOREG
+       C_NOREG4K
        C_PSOREG_8
        C_PSOREG_4
        C_PSOREG
index a0ff54024a03cb73541b47f4ba1a32f35db413bd..92f0cec94271b17aa6336e4992d0a38a95d4b462 100644 (file)
@@ -37,8 +37,11 @@ var cnames7 = []string{
        "SBRA",
        "LBRA",
        "ZAUTO",
-       "NPAUTO",
+       "NSAUTO_8",
+       "NSAUTO_4",
        "NSAUTO",
+       "NPAUTO",
+       "NAUTO4K",
        "PSAUTO_8",
        "PSAUTO_4",
        "PSAUTO",
@@ -61,8 +64,11 @@ var cnames7 = []string{
        "SEXT16",
        "LEXT",
        "ZOREG",
-       "NPOREG",
+       "NSOREG_8",
+       "NSOREG_4",
        "NSOREG",
+       "NPOREG",
+       "NOREG4K",
        "PSOREG_8",
        "PSOREG_4",
        "PSOREG",
index 043a16c45af767313c47f2c90f23d85d883625a3..3f1aee8c2beda5d89d1cbd811e000f49bc5eaa6c 100644 (file)
@@ -473,6 +473,9 @@ var optab = []Optab{
        {ALDP, C_UAUTO4K, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
        {ALDP, C_UAUTO4K, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE},
        {ALDP, C_UAUTO4K, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST},
+       {ALDP, C_NAUTO4K, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
+       {ALDP, C_NAUTO4K, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE},
+       {ALDP, C_NAUTO4K, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST},
        {ALDP, C_LAUTO, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, 0},
        {ALDP, C_LAUTO, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPRE},
        {ALDP, C_LAUTO, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPOST},
@@ -485,6 +488,9 @@ var optab = []Optab{
        {ALDP, C_UOREG4K, C_NONE, C_PAIR, 74, 8, 0, 0, 0},
        {ALDP, C_UOREG4K, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE},
        {ALDP, C_UOREG4K, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST},
+       {ALDP, C_NOREG4K, C_NONE, C_PAIR, 74, 8, 0, 0, 0},
+       {ALDP, C_NOREG4K, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE},
+       {ALDP, C_NOREG4K, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST},
        {ALDP, C_LOREG, C_NONE, C_PAIR, 75, 12, 0, LFROM, 0},
        {ALDP, C_LOREG, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPRE},
        {ALDP, C_LOREG, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPOST},
@@ -499,6 +505,9 @@ var optab = []Optab{
        {ASTP, C_PAIR, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, 0},
        {ASTP, C_PAIR, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPRE},
        {ASTP, C_PAIR, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPOST},
+       {ASTP, C_PAIR, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, 0},
+       {ASTP, C_PAIR, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPRE},
+       {ASTP, C_PAIR, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPOST},
        {ASTP, C_PAIR, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, 0},
        {ASTP, C_PAIR, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPRE},
        {ASTP, C_PAIR, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPOST},
@@ -511,59 +520,74 @@ var optab = []Optab{
        {ASTP, C_PAIR, C_NONE, C_UOREG4K, 76, 8, 0, 0, 0},
        {ASTP, C_PAIR, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPRE},
        {ASTP, C_PAIR, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPOST},
+       {ASTP, C_PAIR, C_NONE, C_NOREG4K, 76, 8, 0, 0, 0},
+       {ASTP, C_PAIR, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPRE},
+       {ASTP, C_PAIR, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPOST},
        {ASTP, C_PAIR, C_NONE, C_LOREG, 77, 12, 0, LTO, 0},
        {ASTP, C_PAIR, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPRE},
        {ASTP, C_PAIR, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPOST},
        {ASTP, C_PAIR, C_NONE, C_ADDR, 87, 12, 0, 0, 0},
 
        // differ from LDP/STP for C_NSAUTO_4/C_PSAUTO_4/C_NSOREG_4/C_PSOREG_4
-       {ALDPW, C_NSAUTO, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
-       {ALDPW, C_NSAUTO, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
-       {ALDPW, C_NSAUTO, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
+       {ALDPW, C_NSAUTO_4, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
+       {ALDPW, C_NSAUTO_4, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
+       {ALDPW, C_NSAUTO_4, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
        {ALDPW, C_PSAUTO_4, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
        {ALDPW, C_PSAUTO_4, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
        {ALDPW, C_PSAUTO_4, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
        {ALDPW, C_UAUTO4K, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
        {ALDPW, C_UAUTO4K, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE},
        {ALDPW, C_UAUTO4K, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST},
+       {ALDPW, C_NAUTO4K, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
+       {ALDPW, C_NAUTO4K, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE},
+       {ALDPW, C_NAUTO4K, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST},
        {ALDPW, C_LAUTO, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, 0},
        {ALDPW, C_LAUTO, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPRE},
        {ALDPW, C_LAUTO, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPOST},
-       {ALDPW, C_NSOREG, C_NONE, C_PAIR, 66, 4, 0, 0, 0},
-       {ALDPW, C_NSOREG, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE},
-       {ALDPW, C_NSOREG, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST},
+       {ALDPW, C_NSOREG_4, C_NONE, C_PAIR, 66, 4, 0, 0, 0},
+       {ALDPW, C_NSOREG_4, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE},
+       {ALDPW, C_NSOREG_4, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST},
        {ALDPW, C_PSOREG_4, C_NONE, C_PAIR, 66, 4, 0, 0, 0},
        {ALDPW, C_PSOREG_4, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE},
        {ALDPW, C_PSOREG_4, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST},
        {ALDPW, C_UOREG4K, C_NONE, C_PAIR, 74, 8, 0, 0, 0},
        {ALDPW, C_UOREG4K, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE},
        {ALDPW, C_UOREG4K, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST},
+       {ALDPW, C_NOREG4K, C_NONE, C_PAIR, 74, 8, 0, 0, 0},
+       {ALDPW, C_NOREG4K, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE},
+       {ALDPW, C_NOREG4K, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST},
        {ALDPW, C_LOREG, C_NONE, C_PAIR, 75, 12, 0, LFROM, 0},
        {ALDPW, C_LOREG, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPRE},
        {ALDPW, C_LOREG, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPOST},
        {ALDPW, C_ADDR, C_NONE, C_PAIR, 88, 12, 0, 0, 0},
 
-       {ASTPW, C_PAIR, C_NONE, C_NSAUTO, 67, 4, REGSP, 0, 0},
-       {ASTPW, C_PAIR, C_NONE, C_NSAUTO, 67, 4, REGSP, 0, C_XPRE},
-       {ASTPW, C_PAIR, C_NONE, C_NSAUTO, 67, 4, REGSP, 0, C_XPOST},
+       {ASTPW, C_PAIR, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, 0},
+       {ASTPW, C_PAIR, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, C_XPRE},
+       {ASTPW, C_PAIR, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, C_XPOST},
        {ASTPW, C_PAIR, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, 0},
        {ASTPW, C_PAIR, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, C_XPRE},
        {ASTPW, C_PAIR, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, C_XPOST},
        {ASTPW, C_PAIR, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, 0},
        {ASTPW, C_PAIR, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPRE},
        {ASTPW, C_PAIR, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPOST},
+       {ASTPW, C_PAIR, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, 0},
+       {ASTPW, C_PAIR, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPRE},
+       {ASTPW, C_PAIR, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPOST},
        {ASTPW, C_PAIR, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, 0},
        {ASTPW, C_PAIR, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPRE},
        {ASTPW, C_PAIR, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPOST},
-       {ASTPW, C_PAIR, C_NONE, C_NSOREG, 67, 4, 0, 0, 0},
-       {ASTPW, C_PAIR, C_NONE, C_NSOREG, 67, 4, 0, 0, C_XPRE},
-       {ASTPW, C_PAIR, C_NONE, C_NSOREG, 67, 4, 0, 0, C_XPOST},
+       {ASTPW, C_PAIR, C_NONE, C_NSOREG_4, 67, 4, 0, 0, 0},
+       {ASTPW, C_PAIR, C_NONE, C_NSOREG_4, 67, 4, 0, 0, C_XPRE},
+       {ASTPW, C_PAIR, C_NONE, C_NSOREG_4, 67, 4, 0, 0, C_XPOST},
        {ASTPW, C_PAIR, C_NONE, C_PSOREG_4, 67, 4, 0, 0, 0},
        {ASTPW, C_PAIR, C_NONE, C_PSOREG_4, 67, 4, 0, 0, C_XPRE},
        {ASTPW, C_PAIR, C_NONE, C_PSOREG_4, 67, 4, 0, 0, C_XPOST},
        {ASTPW, C_PAIR, C_NONE, C_UOREG4K, 76, 8, 0, 0, 0},
        {ASTPW, C_PAIR, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPRE},
        {ASTPW, C_PAIR, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPOST},
+       {ASTPW, C_PAIR, C_NONE, C_NOREG4K, 76, 8, 0, 0, 0},
+       {ASTPW, C_PAIR, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPRE},
+       {ASTPW, C_PAIR, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPOST},
        {ASTPW, C_PAIR, C_NONE, C_LOREG, 77, 12, 0, LTO, 0},
        {ASTPW, C_PAIR, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPRE},
        {ASTPW, C_PAIR, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPOST},
@@ -996,8 +1020,11 @@ func (c *ctxt7) addpool(p *obj.Prog, a *obj.Addr) {
                C_UAUTO16K_8,
                C_UAUTO16K,
                C_UAUTO32K,
+               C_NSAUTO_8,
+               C_NSAUTO_4,
                C_NSAUTO,
                C_NPAUTO,
+               C_NAUTO4K,
                C_LAUTO,
                C_PPOREG,
                C_PSOREG,
@@ -1013,8 +1040,11 @@ func (c *ctxt7) addpool(p *obj.Prog, a *obj.Addr) {
                C_UOREG16K_8,
                C_UOREG16K,
                C_UOREG32K,
+               C_NSOREG_8,
+               C_NSOREG_4,
                C_NSOREG,
                C_NPOREG,
+               C_NOREG4K,
                C_LOREG,
                C_LACON,
                C_LCON,
@@ -1221,12 +1251,21 @@ func autoclass(l int64) int {
        }
 
        if l < 0 {
+               if l >= -256 && (l&7) == 0 {
+                       return C_NSAUTO_8
+               }
+               if l >= -256 && (l&3) == 0 {
+                       return C_NSAUTO_4
+               }
                if l >= -256 {
                        return C_NSAUTO
                }
                if l >= -512 && (l&7) == 0 {
                        return C_NPAUTO
                }
+               if l >= -4095 {
+                       return C_NAUTO4K
+               }
                return C_LAUTO
        }
 
@@ -1649,63 +1688,113 @@ func cmp(a int, b int) bool {
                        return true
                }
 
+       case C_NSAUTO_4:
+               if b == C_NSAUTO_8 {
+                       return true
+               }
+
+       case C_NSAUTO:
+               switch b {
+               case C_NSAUTO_4, C_NSAUTO_8:
+                       return true
+               }
+
+       case C_NPAUTO:
+               switch b {
+               case C_NSAUTO_8:
+                       return true
+               }
+
+       case C_NAUTO4K:
+               switch b {
+               case C_NSAUTO_8, C_NSAUTO_4, C_NSAUTO, C_NPAUTO:
+                       return true
+               }
+
        case C_PSAUTO_8:
                if b == C_ZAUTO {
                        return true
                }
 
        case C_PSAUTO_4:
-               if b == C_ZAUTO || b == C_PSAUTO_8 {
+               switch b {
+               case C_ZAUTO, C_PSAUTO_8:
                        return true
                }
 
        case C_PSAUTO:
-               if b == C_ZAUTO || b == C_PSAUTO_8 || b == C_PSAUTO_4 {
+               switch b {
+               case C_ZAUTO, C_PSAUTO_8, C_PSAUTO_4:
                        return true
                }
 
        case C_PPAUTO:
-               if b == C_ZAUTO || b == C_PSAUTO_8 {
+               switch b {
+               case C_ZAUTO, C_PSAUTO_8:
                        return true
                }
 
        case C_UAUTO4K:
                switch b {
-               case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8:
+               case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8,
+                       C_PPAUTO, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8:
                        return true
                }
 
        case C_UAUTO8K:
                switch b {
-               case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO8K_4, C_UAUTO8K_8:
+               case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO,
+                       C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO8K_4, C_UAUTO8K_8:
                        return true
                }
 
        case C_UAUTO16K:
                switch b {
-               case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO8K_4, C_UAUTO8K_8, C_UAUTO16K_8:
+               case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO,
+                       C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO8K_4, C_UAUTO8K_8, C_UAUTO16K_8:
                        return true
                }
 
        case C_UAUTO32K:
                switch b {
-               case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO, C_UAUTO4K_8, C_UAUTO8K_8, C_UAUTO16K_8:
+               case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8,
+                       C_PPAUTO, C_UAUTO4K_8, C_UAUTO8K_8, C_UAUTO16K_8:
                        return true
                }
 
-       case C_NPAUTO:
-               return cmp(C_NSAUTO, b)
-
        case C_LAUTO:
                switch b {
-               case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO,
+               case C_ZAUTO, C_NSAUTO, C_NSAUTO_4, C_NSAUTO_8, C_NPAUTO,
+                       C_NAUTO4K, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO,
                        C_UAUTO4K, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8,
                        C_UAUTO8K, C_UAUTO8K_4, C_UAUTO8K_8,
                        C_UAUTO16K, C_UAUTO16K_8,
                        C_UAUTO32K:
                        return true
                }
-               return cmp(C_NPAUTO, b)
+
+       case C_NSOREG_4:
+               if b == C_NSOREG_8 {
+                       return true
+               }
+
+       case C_NSOREG:
+               switch b {
+               case C_NSOREG_4, C_NSOREG_8:
+                       return true
+               }
+
+       case C_NPOREG:
+               switch b {
+               case C_NSOREG_8:
+                       return true
+               }
+
+       case C_NOREG4K:
+               switch b {
+               case C_NSOREG_8, C_NSOREG_4, C_NSOREG, C_NPOREG:
+                       return true
+               }
 
        case C_PSOREG_4:
                switch b {
@@ -1727,41 +1816,44 @@ func cmp(a int, b int) bool {
 
        case C_UOREG4K:
                switch b {
-               case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG, C_PPOREG, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8:
+               case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
+                       C_PPOREG, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8:
                        return true
                }
 
        case C_UOREG8K:
                switch b {
-               case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG, C_PPOREG, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8, C_UOREG8K_4, C_UOREG8K_8:
+               case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
+                       C_PPOREG, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8,
+                       C_UOREG8K_4, C_UOREG8K_8:
                        return true
                }
 
        case C_UOREG16K:
                switch b {
-               case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG, C_PPOREG, C_UOREG4K_4, C_UOREG4K_8, C_UOREG8K_4, C_UOREG8K_8, C_UOREG16K_8:
+               case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
+                       C_PPOREG, C_UOREG4K_4, C_UOREG4K_8, C_UOREG8K_4,
+                       C_UOREG8K_8, C_UOREG16K_8:
                        return true
                }
 
        case C_UOREG32K:
                switch b {
-               case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG, C_PPOREG, C_UOREG4K_8, C_UOREG8K_8, C_UOREG16K_8:
+               case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
+                       C_PPOREG, C_UOREG4K_8, C_UOREG8K_8, C_UOREG16K_8:
                        return true
                }
 
-       case C_NPOREG:
-               return cmp(C_NSOREG, b)
-
        case C_LOREG:
                switch b {
-               case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG, C_PPOREG,
+               case C_ZOREG, C_NSOREG, C_NSOREG_4, C_NSOREG_8, C_NPOREG,
+                       C_NOREG4K, C_PSOREG_4, C_PSOREG_8, C_PSOREG, C_PPOREG,
                        C_UOREG4K, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8,
                        C_UOREG8K, C_UOREG8K_4, C_UOREG8K_8,
                        C_UOREG16K, C_UOREG16K_8,
                        C_UOREG32K:
                        return true
                }
-               return cmp(C_NPOREG, b)
 
        case C_LBRA:
                if b == C_SBRA {
@@ -3614,20 +3706,29 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                o1 |= (uint32(imm5&0x1f) << 16) | (uint32(rf&31) << 5) | uint32(rt&31)
 
        case 74:
-               //      add $O, R, Rtmp
+               //      add $O, R, Rtmp or sub $O, R, Rtmp
                //      ldp (Rtmp), (R1, R2)
                r := int(p.From.Reg)
                if r == obj.REG_NONE {
                        r = int(o.param)
                }
                if r == obj.REG_NONE {
-                       c.ctxt.Diag("invalid ldp source: %v\n", p)
+                       c.ctxt.Diag("invalid ldp source: %v", p)
                }
                v := int32(c.regoff(&p.From))
-               if v < 0 || v > 4095 {
-                       c.ctxt.Diag("offset out of range%v\n", p)
+
+               if v > 0 {
+                       if v > 4095 {
+                               c.ctxt.Diag("offset out of range: %v", p)
+                       }
+                       o1 = c.oaddi(p, int32(c.opirr(p, AADD)), v, r, REGTMP)
+               }
+               if v < 0 {
+                       if v < -4095 {
+                               c.ctxt.Diag("offset out of range: %v", p)
+                       }
+                       o1 = c.oaddi(p, int32(c.opirr(p, ASUB)), -v, r, REGTMP)
                }
-               o1 = c.oaddi(p, int32(c.opirr(p, AADD)), v, r, REGTMP)
                o2 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.To.Reg), uint32(p.To.Offset), 1)
 
        case 75:
@@ -3639,7 +3740,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                        r = int(o.param)
                }
                if r == obj.REG_NONE {
-                       c.ctxt.Diag("invalid ldp source: %v\n", p)
+                       c.ctxt.Diag("invalid ldp source: %v", p)
                }
                o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
                o2 = c.opxrrr(p, AADD, false)
@@ -3649,20 +3750,28 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                o3 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.To.Reg), uint32(p.To.Offset), 1)
 
        case 76:
-               //      add $O, R, Rtmp
+               //      add $O, R, Rtmp or sub $O, R, Rtmp
                //      stp (R1, R2), (Rtmp)
                r := int(p.To.Reg)
                if r == obj.REG_NONE {
                        r = int(o.param)
                }
                if r == obj.REG_NONE {
-                       c.ctxt.Diag("invalid stp destination: %v\n", p)
+                       c.ctxt.Diag("invalid stp destination: %v", p)
                }
                v := int32(c.regoff(&p.To))
-               if v < 0 || v > 4095 {
-                       c.ctxt.Diag("offset out of range%v\n", p)
+               if v > 0 {
+                       if v > 4095 {
+                               c.ctxt.Diag("offset out of range: %v", p)
+                       }
+                       o1 = c.oaddi(p, int32(c.opirr(p, AADD)), v, r, REGTMP)
+               }
+               if v < 0 {
+                       if v < -4095 {
+                               c.ctxt.Diag("offset out of range: %v", p)
+                       }
+                       o1 = c.oaddi(p, int32(c.opirr(p, ASUB)), -v, r, REGTMP)
                }
-               o1 = c.oaddi(p, int32(c.opirr(p, AADD)), v, r, REGTMP)
                o2 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.From.Reg), uint32(p.From.Offset), 0)
 
        case 77:
@@ -3674,7 +3783,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                        r = int(o.param)
                }
                if r == obj.REG_NONE {
-                       c.ctxt.Diag("invalid stp destination: %v\n", p)
+                       c.ctxt.Diag("invalid stp destination: %v", p)
                }
                o1 = c.omovlit(AMOVD, p, &p.To, REGTMP)
                o2 = c.opxrrr(p, AADD, false)