]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj/arm64: reclassify 32-bit/64-bit constants
authorfanzha02 <fannie.zhang@arm.com>
Fri, 22 Jun 2018 12:08:47 +0000 (12:08 +0000)
committerCherry Zhang <cherryyz@google.com>
Mon, 22 Oct 2018 14:23:23 +0000 (14:23 +0000)
Current assembler saves constants in Offset which type is int64,
causing 32-bit constants have a incorrect class. This CL reclassifies
constants when opcodes are 32-bit variant, like MOVW, ANDW and
ADDW, etc. Besides, this CL encodes some constants of ADDCON class
as MOVs instructions.

This CL changes the assembler behavior as follows.

1. go assembler ADDW $MOVCON, Rn, Rd
   previous version: MOVD $MOVCON, Rtmp; ADDW Rtmp, Rn, Rd
   current version: MOVW $MOVCON, Rtmp; ADDW Rtmp, Rn, Rd

2. go assembly MOVW $0xaaaaffff, R1
   previous version: treats $0xaaaaffff as VCON, encodes it as MOVW 0x994, R1 (loads it from pool).
   current version: treats $0xaaaaffff as MOVCON, and encodes it into MOVW instructions.

3. go assembly MOVD $0x210000, R1
   previous version: treats $0x210000 as ADDCON, loads it from pool
   current version: treats $0x210000 as MOVCON, and encodes it into MOVD instructions.

Add the test cases.

1. Binary size before/after.
binary                          size change
pkg/linux_arm64                 -1.534KB
pkg/tool/linux_arm64            -0.718KB
go                              -0.32KB
gofmt                           no change

2. go1 benchmark result.
name                     old time/op    new time/op    delta
BinaryTree17-8              6.26s ± 1%     6.28s ± 1%     ~     (p=0.105 n=10+10)
Fannkuch11-8                5.40s ± 0%     5.39s ± 0%   -0.29%  (p=0.028 n=9+10)
FmtFprintfEmpty-8          94.5ns ± 0%    95.0ns ± 0%   +0.51%  (p=0.000 n=10+9)
FmtFprintfString-8          163ns ± 1%     159ns ± 1%   -2.06%  (p=0.000 n=10+9)
FmtFprintfInt-8             200ns ± 1%     196ns ± 1%   -1.99%  (p=0.000 n=9+10)
FmtFprintfIntInt-8          292ns ± 3%     284ns ± 1%   -2.87%  (p=0.001 n=10+9)
FmtFprintfPrefixedInt-8     422ns ± 1%     420ns ± 1%   -0.59%  (p=0.015 n=10+10)
FmtFprintfFloat-8           458ns ± 0%     463ns ± 1%   +1.19%  (p=0.000 n=9+10)
FmtManyArgs-8              1.37µs ± 1%    1.35µs ± 1%   -1.85%  (p=0.000 n=10+10)
GobDecode-8                15.5ms ± 1%    15.3ms ± 1%   -1.82%  (p=0.000 n=10+10)
GobEncode-8                11.7ms ± 5%    11.7ms ± 2%     ~     (p=0.549 n=10+9)
Gzip-8                      622ms ± 0%     624ms ± 0%   +0.23%  (p=0.000 n=10+9)
Gunzip-8                   73.6ms ± 0%    73.8ms ± 1%     ~     (p=0.077 n=9+9)
HTTPClientServer-8          115µs ± 1%     115µs ± 1%     ~     (p=0.796 n=10+10)
JSONEncode-8               31.1ms ± 2%    28.7ms ± 1%   -7.98%  (p=0.000 n=10+9)
JSONDecode-8                145ms ± 0%     145ms ± 1%     ~     (p=0.447 n=9+10)
Mandelbrot200-8            9.67ms ± 0%    9.60ms ± 0%   -0.76%  (p=0.000 n=9+9)
GoParse-8                  7.56ms ± 1%    7.58ms ± 0%   +0.21%  (p=0.035 n=10+9)
RegexpMatchEasy0_32-8       208ns ±10%     222ns ± 0%     ~     (p=0.531 n=10+6)
RegexpMatchEasy0_1K-8       699ns ± 4%     694ns ± 4%     ~     (p=0.868 n=10+10)
RegexpMatchEasy1_32-8       186ns ± 8%     190ns ±12%     ~     (p=0.955 n=10+10)
RegexpMatchEasy1_1K-8      1.13µs ± 1%    1.05µs ± 2%   -6.64%  (p=0.000 n=10+10)
RegexpMatchMedium_32-8      316ns ± 7%     288ns ± 1%   -8.68%  (p=0.000 n=10+7)
RegexpMatchMedium_1K-8     90.2µs ± 0%    85.5µs ± 2%   -5.19%  (p=0.000 n=10+10)
RegexpMatchHard_32-8       5.53µs ± 0%    3.90µs ± 0%  -29.52%  (p=0.000 n=10+10)
RegexpMatchHard_1K-8        119µs ± 0%     124µs ± 0%   +4.29%  (p=0.000 n=9+10)
Revcomp-8                   1.07s ± 0%     1.07s ± 0%     ~     (p=0.094 n=9+9)
Template-8                  162ms ± 1%     160ms ± 2%     ~     (p=0.089 n=10+10)
TimeParse-8                 756ns ± 2%     763ns ± 1%     ~     (p=0.158 n=10+10)
TimeFormat-8                758ns ± 1%     746ns ± 1%   -1.52%  (p=0.000 n=10+10)

name                     old speed      new speed      delta
GobDecode-8              49.4MB/s ± 1%  50.3MB/s ± 1%   +1.84%  (p=0.000 n=10+10)
GobEncode-8              65.6MB/s ± 5%  65.4MB/s ± 2%     ~     (p=0.549 n=10+9)
Gzip-8                   31.2MB/s ± 0%  31.1MB/s ± 0%   -0.24%  (p=0.000 n=9+9)
Gunzip-8                  264MB/s ± 0%   263MB/s ± 1%     ~     (p=0.073 n=9+9)
JSONEncode-8             62.3MB/s ± 2%  67.7MB/s ± 1%   +8.67%  (p=0.000 n=10+9)
JSONDecode-8             13.4MB/s ± 0%  13.4MB/s ± 1%     ~     (p=0.508 n=9+10)
GoParse-8                7.66MB/s ± 1%  7.64MB/s ± 0%   -0.23%  (p=0.049 n=10+9)
RegexpMatchEasy0_32-8     154MB/s ± 9%   143MB/s ± 3%     ~     (p=0.303 n=10+7)
RegexpMatchEasy0_1K-8    1.46GB/s ± 4%  1.47GB/s ± 4%     ~     (p=0.912 n=10+10)
RegexpMatchEasy1_32-8     172MB/s ± 9%   170MB/s ±12%     ~     (p=0.971 n=10+10)
RegexpMatchEasy1_1K-8     908MB/s ± 1%   972MB/s ± 2%   +7.12%  (p=0.000 n=10+10)
RegexpMatchMedium_32-8   3.17MB/s ± 7%  3.46MB/s ± 1%   +9.14%  (p=0.000 n=10+7)
RegexpMatchMedium_1K-8   11.3MB/s ± 0%  12.0MB/s ± 2%   +5.51%  (p=0.000 n=10+10)
RegexpMatchHard_32-8     5.78MB/s ± 0%  8.21MB/s ± 0%  +41.93%  (p=0.000 n=9+10)
RegexpMatchHard_1K-8     8.62MB/s ± 0%  8.27MB/s ± 0%   -4.11%  (p=0.000 n=9+10)
Revcomp-8                 237MB/s ± 0%   237MB/s ± 0%     ~     (p=0.081 n=9+9)
Template-8               12.0MB/s ± 1%  12.1MB/s ± 2%     ~     (p=0.072 n=10+10)

Change-Id: I080801f520366b42d5f9699954bd33106976a81b
Reviewed-on: https://go-review.googlesource.com/c/120661
Run-TryBot: Ben Shi <powerman1st@163.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 079c620f9be8c17b5ff01d51589cb1d0939d4439..12c7adbd04a224ba77c3de3c155ea95d1308d67d 100644 (file)
@@ -191,6 +191,11 @@ TEXT       foo(SB), DUPOK|NOSPLIT, $-8
        FMOVD   F4, (R2)(R6)       // FMOVD F4, (R2)(R6*1)    // 446826fc
        FMOVD   F4, (R2)(R6<<3)                               // 447826fc
 
+       CMPW    $40960, R0                      // 1f284071
+       CMPW    $27745, R2                      // 3b8c8d525f001b6b
+       CMNW    $0x3fffffc0, R2                 // CMNW $1073741760, R2                   // fb5f1a325f001b2b
+       CMPW    $0xffff0, R1                    // CMPW $1048560, R1                      // fb3f1c323f001b6b
+       ADD     $0x3fffffffc000, R5             // ADD  $70368744161280, R5               // fb7f72b2a5001b8b
 //     LTYPE1 imsr ',' spreg ','
 //     {
 //             outcode($1, &$2, $4, &nullgen);
@@ -226,6 +231,16 @@ TEXT       foo(SB), DUPOK|NOSPLIT, $-8
        ANDS    $0x22220000, R3, R4   // ANDS $572653568, R3, R4  // 5b44a4d264001bea
        BICS    $0x22220000, R3, R4   // BICS $572653568, R3, R4  // 5b44a4d264003bea
 
+       EOR     $0xe03fffffffffffff, R20, R22       // EOR      $-2287828610704211969, R20, R22 // 96e243d2
+       TSTW    $0x600000006, R1                    // TSTW     $25769803782, R1                // 3f041f72
+       ANDS    $0xffff, R2                         // ANDS     $65535, R2                      // 423c40f2
+       AND     $0x7fffffff, R3                     // AND      $2147483647, R3                 // 63784092
+       ANDS    $0x0ffffffff80000000, R2            // ANDS     $-2147483648, R2                // 428061f2
+       AND     $0xfffff, R2                        // AND      $1048575, R2                    // 424c4092
+       ANDW    $0xf00fffff, R1                     // ANDW     $4027580415, R1                 // 215c0412
+       ANDSW   $0xff00ffff, R1                     // ANDSW    $4278255615, R1                 // 215c0872
+       TSTW    $0xff00ff, R1                       // TSTW     $16711935, R1                   // 3f9c0072
+
        AND     $8, R0, RSP // 1f007d92
        ORR     $8, R0, RSP // 1f007db2
        EOR     $8, R0, RSP // 1f007dd2
@@ -233,6 +248,19 @@ TEXT       foo(SB), DUPOK|NOSPLIT, $-8
        ORN     $8, R0, RSP // 1ff87cb2
        EON     $8, R0, RSP // 1ff87cd2
 
+       MOVD    $0x3fffffffc000, R0           // MOVD   $70368744161280, R0         // e07f72b2
+       MOVW    $0xaaaa0000, R1               // MOVW   $2863267840, R1             // 4155b552
+       MOVW    $0xaaaaffff, R1               // MOVW   $2863333375, R1             // a1aaaa12
+       MOVW    $0xaaaa, R1                   // MOVW   $43690, R1                  // 41559552
+       MOVW    $0xffffaaaa, R1               // MOVW   $4294945450, R1             // a1aa8a12
+       MOVW    $0xffff0000, R1               // MOVW   $4294901760, R1             // e1ffbf52
+       MOVD    $0xffff00000000000, R1        // MOVD   $1152903912420802560, R1    // e13f54b2
+       MOVD    $0x11110000, R1               // MOVD   $286326784, R1              // 2122a2d2
+       MOVD    $0, R1                        // 010080d2
+       MOVD    $-1, R1                       // 01008092
+       MOVD    $0x210000, R0                 // MOVD   $2162688, R0                 // 2004a0d2
+       MOVD    $0xffffffffffffaaaa, R1       // MOVD   $-21846, R1                  // a1aa8a92
+
 //
 // CLS
 //
@@ -428,7 +456,7 @@ TEXT        foo(SB), DUPOK|NOSPLIT, $-8
        CMP     R22.SXTX, RSP // ffe336eb
 
        CMP     $0x22220000, RSP  // CMP $572653568, RSP   // 5b44a4d2ff633beb
-       CMPW    $0x22220000, RSP  // CMPW $572653568, RSP  // 5b44a4d2ff633b6b
+       CMPW    $0x22220000, RSP  // CMPW $572653568, RSP  // 5b44a452ff633b6b
 
 // TST
        TST     $15, R2                               // 5f0c40f2
index 37df688b21a6994a9aa27c61c009cc9383ceb0d5..c4c75e41d418fe255394d2d067931b88251306c2 100644 (file)
@@ -407,6 +407,7 @@ const (
        C_ABCON0   // could be C_ADDCON0 or C_BITCON
        C_ADDCON0  // 12-bit unsigned, unshifted
        C_ABCON    // could be C_ADDCON or C_BITCON
+       C_AMCON    // could be C_ADDCON or C_MOVCON
        C_ADDCON   // 12-bit unsigned, shifted left by 0 or 12
        C_MBCON    // could be C_MOVCON or C_BITCON
        C_MOVCON   // generated by a 16-bit constant, optionally inverted and/or shifted by multiple of 16
index a768f2cbefdd338cec4fdc93d01bd1682ce06be1..f8fdc68c1e1ad60b9bb337449c2337e8a1309801 100644 (file)
@@ -23,6 +23,7 @@ var cnames7 = []string{
        "ABCON0",
        "ADDCON0",
        "ABCON",
+       "AMCON",
        "ADDCON",
        "MBCON",
        "MOVCON",
index 3056455f31410f4b259e8c972692cd6d9cea4c7c..6a6e81807ac2deb932dacc582f474b82f56c9e00 100644 (file)
@@ -164,6 +164,10 @@ func OPBIT(x uint32) uint32 {
        return 1<<30 | 0<<29 | 0xD6<<21 | 0<<16 | x<<10
 }
 
+func MOVCONST(d int64, s int, rt int) uint32 {
+       return uint32(((d>>uint(s*16))&0xFFFF)<<5) | uint32(s)&3<<21 | uint32(rt&31)
+}
+
 const (
        LFROM = 1 << 0
        LTO   = 1 << 1
@@ -272,12 +276,10 @@ var optab = []Optab{
        /* MOVs that become MOVK/MOVN/MOVZ/ADD/SUB/OR */
        {AMOVW, C_MOVCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
        {AMOVD, C_MOVCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
-
-       // TODO: these don't work properly.
-       // { AMOVW,             C_ADDCON,       C_NONE, C_REG,          2, 4, 0 , 0},
-       // { AMOVD,             C_ADDCON,       C_NONE, C_REG,          2, 4, 0 , 0},
        {AMOVW, C_BITCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
        {AMOVD, C_BITCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
+       {AMOVW, C_LCON, C_NONE, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
+       {AMOVD, C_VCON, C_NONE, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
 
        {AMOVK, C_VCON, C_NONE, C_NONE, C_REG, 33, 4, 0, 0, 0},
        {AMOVD, C_AACON, C_NONE, C_NONE, C_REG, 4, 4, REGFROM, 0, 0},
@@ -318,9 +320,7 @@ var optab = []Optab{
        {AWORD, C_NONE, C_NONE, C_NONE, C_LCON, 14, 4, 0, 0, 0},
        {AWORD, C_NONE, C_NONE, C_NONE, C_LEXT, 14, 4, 0, 0, 0},
        {AWORD, C_NONE, C_NONE, C_NONE, C_ADDR, 14, 4, 0, 0, 0},
-       {AMOVW, C_VCON, C_NONE, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
        {AMOVW, C_VCONADDR, C_NONE, C_NONE, C_REG, 68, 8, 0, 0, 0},
-       {AMOVD, C_VCON, C_NONE, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
        {AMOVD, C_VCONADDR, C_NONE, C_NONE, C_REG, 68, 8, 0, 0, 0},
        {AMOVB, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
        {AMOVBU, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
@@ -1105,6 +1105,23 @@ func isSTXPop(op obj.As) bool {
        return false
 }
 
+func isANDWop(op obj.As) bool {
+       switch op {
+       case AANDW, AORRW, AEORW, AANDSW, ATSTW,
+               ABICW, AEONW, AORNW, ABICSW:
+               return true
+       }
+       return false
+}
+
+func isADDWop(op obj.As) bool {
+       switch op {
+       case AADDW, AADDSW, ASUBW, ASUBSW, ACMNW, ACMPW:
+               return true
+       }
+       return false
+}
+
 func isRegShiftOrExt(a *obj.Addr) bool {
        return (a.Index-obj.RBaseARM64)&REG_EXT != 0 || (a.Index-obj.RBaseARM64)&REG_LSL != 0
 }
@@ -1411,6 +1428,52 @@ func rclass(r int16) int {
        return C_GOK
 }
 
+// con32class reclassifies the constant of 32-bit instruction. Becuase the constant type is 32-bit,
+// but saved in Offset which type is int64, con32class treats it as uint32 type and reclassifies it.
+func (c *ctxt7) con32class(a *obj.Addr) int {
+       v := uint32(a.Offset)
+       if v == 0 {
+               return C_ZCON
+       }
+       if isaddcon(int64(v)) {
+               if v <= 0xFFF {
+                       if isbitcon(uint64(v)) {
+                               return C_ABCON0
+                       }
+                       return C_ADDCON0
+               }
+               if isbitcon(uint64(v)) {
+                       return C_ABCON
+               }
+               return C_ADDCON
+       }
+
+       t := movcon(int64(v))
+       if t >= 0 {
+               if isbitcon(uint64(v)) {
+                       return C_MBCON
+               }
+               return C_MOVCON
+       }
+
+       t = movcon(int64(^v))
+       if t >= 0 {
+               if isbitcon(uint64(v)) {
+                       return C_MBCON
+               }
+               return C_MOVCON
+       }
+
+       if isbitcon(uint64(v)) {
+               return C_BITCON
+       }
+
+       if 0 <= v && v <= 0xffffff {
+               return C_ADDCON2
+       }
+       return C_LCON
+}
+
 func (c *ctxt7) aclass(a *obj.Addr) int {
        switch a.Type {
        case obj.TYPE_NONE:
@@ -1517,6 +1580,12 @@ func (c *ctxt7) aclass(a *obj.Addr) int {
                                if isbitcon(uint64(v)) {
                                        return C_ABCON
                                }
+                               if movcon(v) >= 0 {
+                                       return C_AMCON
+                               }
+                               if movcon(^v) >= 0 {
+                                       return C_AMCON
+                               }
                                return C_ADDCON
                        }
 
@@ -1609,6 +1678,34 @@ func (c *ctxt7) oplook(p *obj.Prog) *Optab {
                }
                a1 = a0 + 1
                p.From.Class = int8(a1)
+               // more specific classification of 32-bit integers
+               if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE {
+                       if p.As == AMOVW || isADDWop(p.As) {
+                               ra0 := c.con32class(&p.From)
+                               // do not break C_ADDCON2 when S bit is set
+                               if (p.As == AADDSW || p.As == ASUBSW) && ra0 == C_ADDCON2 {
+                                       ra0 = C_LCON
+                               }
+                               a1 = ra0 + 1
+                               p.From.Class = int8(a1)
+                       }
+                       if isANDWop(p.As) {
+                               switch p.As {
+                               case AANDW, AORRW, AEORW, AANDSW, ATSTW:
+                                       // For 32-bit logical instruction with constant,
+                                       // rewrite the high 32-bit to be a copy of the low
+                                       // 32-bit, so that the BITCON test can be shared
+                                       // for both 32-bit and 64-bit.
+                                       if a0 == C_BITCON {
+                                               break
+                                       }
+                                       fallthrough
+                               default:
+                                       a1 = c.con32class(&p.From) + 1
+                                       p.From.Class = int8(a1)
+                               }
+                       }
+               }
        }
 
        a1--
@@ -1679,7 +1776,7 @@ func cmp(a int, b int) bool {
                }
 
        case C_ADDCON:
-               if b == C_ZCON || b == C_ABCON0 || b == C_ADDCON0 || b == C_ABCON {
+               if b == C_ZCON || b == C_ABCON0 || b == C_ADDCON0 || b == C_ABCON || b == C_AMCON {
                        return true
                }
 
@@ -1689,7 +1786,7 @@ func cmp(a int, b int) bool {
                }
 
        case C_MOVCON:
-               if b == C_MBCON || b == C_ZCON || b == C_ADDCON0 {
+               if b == C_MBCON || b == C_ZCON || b == C_ADDCON0 || b == C_AMCON {
                        return true
                }
 
@@ -1699,7 +1796,7 @@ func cmp(a int, b int) bool {
                }
 
        case C_LCON:
-               if b == C_ZCON || b == C_BITCON || b == C_ADDCON || b == C_ADDCON0 || b == C_ABCON || b == C_ABCON0 || b == C_MBCON || b == C_MOVCON || b == C_ADDCON2 {
+               if b == C_ZCON || b == C_BITCON || b == C_ADDCON || b == C_ADDCON0 || b == C_ABCON || b == C_ABCON0 || b == C_MBCON || b == C_MOVCON || b == C_ADDCON2 || b == C_AMCON {
                        return true
                }
 
@@ -3501,8 +3598,8 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                if r == 0 {
                        r = rt
                }
-               o1 = c.oaddi(p, int32(op), int32(c.regoff(&p.From)) & 0x000fff, r, rt)
-               o2 = c.oaddi(p, int32(op), int32(c.regoff(&p.From)) & 0xfff000, rt, rt)
+               o1 = c.oaddi(p, int32(op), int32(c.regoff(&p.From))&0x000fff, r, rt)
+               o2 = c.oaddi(p, int32(op), int32(c.regoff(&p.From))&0xfff000, rt, rt)
 
        case 50: /* sys/sysl */
                o1 = c.opirr(p, p.As)
@@ -3670,7 +3767,11 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                if p.Reg == REGTMP {
                        c.ctxt.Diag("cannot use REGTMP as source: %v\n", p)
                }
-               o1 = c.omovconst(AMOVD, p, &p.From, REGTMP)
+               if isADDWop(p.As) || isANDWop(p.As) {
+                       o1 = c.omovconst(AMOVW, p, &p.From, REGTMP)
+               } else {
+                       o1 = c.omovconst(AMOVD, p, &p.From, REGTMP)
+               }
 
                rt := int(p.To.Reg)
                if p.To.Type == obj.TYPE_NONE {
@@ -6195,31 +6296,37 @@ func (c *ctxt7) omovconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int) (o1 uint3
                return o1
        }
 
-       r := 32
-       if as == AMOVD {
-               r = 64
+       if as == AMOVW {
+               d := uint32(a.Offset)
+               s := movcon(int64(d))
+               if s < 0 || 16*s >= 32 {
+                       d = ^d
+                       s = movcon(int64(d))
+                       if s < 0 || 16*s >= 32 {
+                               c.ctxt.Diag("impossible 32-bit move wide: %#x\n%v", uint32(a.Offset), p)
+                       }
+                       o1 = c.opirr(p, AMOVNW)
+               } else {
+                       o1 = c.opirr(p, AMOVZW)
+               }
+               o1 |= MOVCONST(int64(d), s, rt)
        }
-       d := a.Offset
-       s := movcon(d)
-       if s < 0 || s >= r {
-               d = ^d
-               s = movcon(d)
-               if s < 0 || s >= r {
-                       c.ctxt.Diag("impossible move wide: %#x\n%v", uint64(a.Offset), p)
-               }
-               if as == AMOVD {
+       if as == AMOVD {
+               d := a.Offset
+               s := movcon(d)
+               if s < 0 || 16*s >= 64 {
+                       d = ^d
+                       s = movcon(d)
+                       if s < 0 || 16*s >= 64 {
+                               c.ctxt.Diag("impossible 64-bit move wide: %#x\n%v", uint64(a.Offset), p)
+                       }
                        o1 = c.opirr(p, AMOVN)
                } else {
-                       o1 = c.opirr(p, AMOVNW)
-               }
-       } else {
-               if as == AMOVD {
                        o1 = c.opirr(p, AMOVZ)
-               } else {
-                       o1 = c.opirr(p, AMOVZW)
                }
+               o1 |= MOVCONST(d, s, rt)
        }
-       o1 |= uint32((((d >> uint(s*16)) & 0xFFFF) << 5) | int64((uint32(s)&3)<<21) | int64(rt&31))
+
        return o1
 }