]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/obj/arm64: add assembler support for load with register offset
authorfanzha02 <fannie.zhang@arm.com>
Fri, 8 Dec 2017 08:19:32 +0000 (08:19 +0000)
committerBrad Fitzpatrick <bradfitz@golang.org>
Mon, 9 Apr 2018 18:20:41 +0000 (18:20 +0000)
The patch adds support for LDR(register offset) instruction.
And add the test cases and negative tests.

Change-Id: I5b32c6a5065afc4571116d4896f7ebec3c0416d3
Reviewed-on: https://go-review.googlesource.com/87955
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/asm/internal/arch/arm64.go
src/cmd/asm/internal/asm/parse.go
src/cmd/asm/internal/asm/testdata/arm64.s
src/cmd/asm/internal/asm/testdata/arm64error.s
src/cmd/internal/obj/arm64/a.out.go
src/cmd/internal/obj/arm64/asm7.go
src/cmd/internal/obj/arm64/doc.go
src/cmd/internal/obj/arm64/list7.go
src/cmd/internal/obj/util.go

index af45f421e98a3b7f56acc3f3ec3cdd72fdb1531e..3941e363729e3ba8eabe0d4cb8bd8dd90daefc8f 100644 (file)
@@ -121,12 +121,18 @@ func arm64RegisterNumber(name string, n int16) (int16, bool) {
        return 0, false
 }
 
+// rm is the Rm register value, o is the extension, amount is the left shift value.
+func roff(rm uint32, o uint32, amount int16) int64 {
+       return int64((rm&31)<<16 | o<<13 | uint32(amount)<<10)
+}
+
 // ARM64RegisterExtension parses an ARM64 register with extension or arrangement.
 func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, isIndex bool) error {
        rm := uint32(reg)
+       Rnum := (reg & 31) + int16(num<<5)
        if isAmount {
                if num < 0 || num > 7 {
-                       return errors.New("shift amount out of range")
+                       return errors.New("index shift amount is out of range")
                }
        }
        switch ext {
@@ -134,50 +140,96 @@ func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, i
                if !isAmount {
                        return errors.New("invalid register extension")
                }
-               a.Reg = arm64.REG_UXTB + (reg & 31) + num<<5
-               a.Offset = int64(((rm & 31) << 16) | (uint32(num) << 10))
+               if a.Type == obj.TYPE_MEM {
+                       return errors.New("invalid shift for the register offset addressing mode")
+               }
+               a.Reg = arm64.REG_UXTB + Rnum
+               a.Offset = roff(rm, 0, num)
        case "UXTH":
                if !isAmount {
                        return errors.New("invalid register extension")
                }
-               a.Reg = arm64.REG_UXTH + (reg & 31) + num<<5
-               a.Offset = int64(((rm & 31) << 16) | (1 << 13) | (uint32(num) << 10))
+               if a.Type == obj.TYPE_MEM {
+                       return errors.New("invalid shift for the register offset addressing mode")
+               }
+               a.Reg = arm64.REG_UXTH + Rnum
+               a.Offset = roff(rm, 1, num)
        case "UXTW":
                if !isAmount {
                        return errors.New("invalid register extension")
                }
-               a.Reg = arm64.REG_UXTW + (reg & 31) + num<<5
-               a.Offset = int64(((rm & 31) << 16) | (2 << 13) | (uint32(num) << 10))
+               // effective address of memory is a base register value and an offset register value.
+               if a.Type == obj.TYPE_MEM {
+                       a.Index = arm64.REG_UXTW + Rnum
+                       if num == 0 {
+                               a.Offset = roff(rm, 2, 2)
+                       } else {
+                               a.Offset = roff(rm, 2, 6)
+                       }
+               } else {
+                       a.Reg = arm64.REG_UXTW + Rnum
+                       a.Offset = roff(rm, 2, num)
+               }
        case "UXTX":
                if !isAmount {
                        return errors.New("invalid register extension")
                }
-               a.Reg = arm64.REG_UXTX + (reg & 31) + num<<5
-               a.Offset = int64(((rm & 31) << 16) | (3 << 13) | (uint32(num) << 10))
+               if a.Type == obj.TYPE_MEM {
+                       return errors.New("invalid shift for the register offset addressing mode")
+               }
+               a.Reg = arm64.REG_UXTX + Rnum
+               a.Offset = roff(rm, 3, num)
        case "SXTB":
                if !isAmount {
                        return errors.New("invalid register extension")
                }
-               a.Reg = arm64.REG_SXTB + (reg & 31) + num<<5
-               a.Offset = int64(((rm & 31) << 16) | (4 << 13) | (uint32(num) << 10))
+               a.Reg = arm64.REG_SXTB + Rnum
+               a.Offset = roff(rm, 4, num)
        case "SXTH":
                if !isAmount {
                        return errors.New("invalid register extension")
                }
-               a.Reg = arm64.REG_SXTH + (reg & 31) + num<<5
-               a.Offset = int64(((rm & 31) << 16) | (5 << 13) | (uint32(num) << 10))
+               if a.Type == obj.TYPE_MEM {
+                       return errors.New("invalid shift for the register offset addressing mode")
+               }
+               a.Reg = arm64.REG_SXTH + Rnum
+               a.Offset = roff(rm, 5, num)
        case "SXTW":
                if !isAmount {
                        return errors.New("invalid register extension")
                }
-               a.Reg = arm64.REG_SXTW + (reg & 31) + num<<5
-               a.Offset = int64(((rm & 31) << 16) | (6 << 13) | (uint32(num) << 10))
+               if a.Type == obj.TYPE_MEM {
+                       a.Index = arm64.REG_SXTW + Rnum
+                       if num == 0 {
+                               a.Offset = roff(rm, 6, 2)
+                       } else {
+                               a.Offset = roff(rm, 6, 6)
+                       }
+               } else {
+                       a.Reg = arm64.REG_SXTW + Rnum
+                       a.Offset = roff(rm, 6, num)
+               }
        case "SXTX":
                if !isAmount {
                        return errors.New("invalid register extension")
                }
-               a.Reg = arm64.REG_SXTX + (reg & 31) + num<<5
-               a.Offset = int64(((rm & 31) << 16) | (7 << 13) | (uint32(num) << 10))
+               if a.Type == obj.TYPE_MEM {
+                       a.Index = arm64.REG_SXTX + Rnum
+                       if num == 0 {
+                               a.Offset = roff(rm, 7, 2)
+                       } else {
+                               a.Offset = roff(rm, 7, 6)
+                       }
+               } else {
+                       a.Reg = arm64.REG_SXTX + Rnum
+                       a.Offset = roff(rm, 7, num)
+               }
+       case "LSL":
+               if !isAmount {
+                       return errors.New("invalid register extension")
+               }
+               a.Index = arm64.REG_LSL + Rnum
+               a.Offset = roff(rm, 3, 6)
        case "B8":
                if isIndex {
                        return errors.New("invalid register extension")
@@ -250,7 +302,7 @@ func ARM64RegisterExtension(a *obj.Addr, ext string, reg, num int16, isAmount, i
        default:
                return errors.New("unsupported register extension type: " + ext)
        }
-       a.Type = obj.TYPE_REG
+
        return nil
 }
 
index 833693ba2179a308f5783a2afc4295e35baadffa..0ac1f04c10e63b0684d084797d3a0455beb48655 100644 (file)
@@ -322,6 +322,7 @@ func (p *Parser) operand(a *obj.Addr) {
                                p.get(')')
                        }
                } else if p.atRegisterExtension() {
+                       a.Type = obj.TYPE_REG
                        p.registerExtension(a, tok.String(), prefix)
                        p.expectOperandEnd()
                        return
@@ -604,12 +605,20 @@ func (p *Parser) registerExtension(a *obj.Addr, name string, prefix rune) {
                return
        }
 
-       p.get('.')
-       tok := p.next()
-       ext := tok.String()
        isIndex := false
        num := int16(0)
        isAmount := true // Amount is zero by default
+       ext := ""
+       if p.peek() == lex.LSH {
+               // (Rn)(Rm<<2), the shifted offset register.
+               ext = "LSL"
+       } else {
+               // (Rn)(Rm.UXTW<1), the extended offset register.
+               // Rm.UXTW<<3, the extended register.
+               p.get('.')
+               tok := p.next()
+               ext = tok.String()
+       }
        if p.peek() == lex.LSH {
                // parses left shift amount applied after extension: <<Amount
                p.get(lex.LSH)
@@ -714,8 +723,8 @@ func (p *Parser) setPseudoRegister(addr *obj.Addr, reg string, isStatic bool, pr
 }
 
 // registerIndirect parses the general form of a register indirection.
-// It is can be (R1), (R2*scale), or (R1)(R2*scale) where R1 may be a simple
-// register or register pair R:R or (R, R) or (R+R).
+// It is can be (R1), (R2*scale), (R1)(R2*scale), (R1)(R2.SXTX<<3) or (R1)(R2<<3)
+// where R1 may be a simple register or register pair R:R or (R, R) or (R+R).
 // Or it might be a pseudo-indirection like (FP).
 // We are sitting on the opening parenthesis.
 func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) {
@@ -783,19 +792,26 @@ func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) {
                // General form (R)(R*scale).
                p.next()
                tok := p.next()
-               r1, r2, scale, ok = p.register(tok.String(), 0)
-               if !ok {
-                       p.errorf("indirect through non-register %s", tok)
-               }
-               if r2 != 0 {
-                       p.errorf("unimplemented two-register form")
-               }
-               a.Index = r1
-               if scale == 0 && p.arch.Family == sys.ARM64 {
-                       // scale is 1 by default for ARM64
-                       a.Scale = 1
+               if p.atRegisterExtension() {
+                       p.registerExtension(a, tok.String(), prefix)
+               } else if p.atRegisterShift() {
+                       // (R1)(R2<<3)
+                       p.registerExtension(a, tok.String(), prefix)
                } else {
-                       a.Scale = int16(scale)
+                       r1, r2, scale, ok = p.register(tok.String(), 0)
+                       if !ok {
+                               p.errorf("indirect through non-register %s", tok)
+                       }
+                       if r2 != 0 {
+                               p.errorf("unimplemented two-register form")
+                       }
+                       a.Index = r1
+                       if scale == 0 && p.arch.Family == sys.ARM64 {
+                               // scale is 1 by default for ARM64
+                               a.Scale = 1
+                       } else {
+                               a.Scale = int16(scale)
+                       }
                }
                p.get(')')
        } else if scale != 0 {
index 8ee2e016153b48f16bc7e45800569fd487602278..0860cbbf22f34da51abe0e3f944901423c354118 100644 (file)
@@ -100,7 +100,13 @@ TEXT       foo(SB), DUPOK|NOSPLIT, $-8
        VSHL    $8, V1.H8, V2.H8                // 2254184f
        VSHL    $2, V1.B8, V2.B8                // 22540a0f
        VSHL    $2, V1.B16, V2.B16              // 22540a4f
-
+       MOVD    (R2)(R6.SXTW), R4               // 44c866f8
+       MOVD    (R3)(R6), R5                    // MOVD (R3)(R6*1), R5                  // 656866f8
+       MOVD    (R2)(R6), R4                    // MOVD (R2)(R6*1), R4                  // 446866f8
+       MOVWU   (R19)(R18<<2), R18              // 727a72b8
+       MOVD    (R2)(R6<<3), R4                 // 447866f8
+       MOVD    (R3)(R7.SXTX<<3), R8            // 68f867f8
+       MOVWU   (R5)(R4.UXTW), R10              // aa4864b8
 //     LTYPE1 imsr ',' spreg ','
 //     {
 //             outcode($1, &$2, $4, &nullgen);
index 37e9442eca6e7f0de92cbb45bde6711817ed124f..4a1142e8a8cb33d20e05fc8e88dbaf121f850c4f 100644 (file)
@@ -5,12 +5,15 @@
 TEXT errors(SB),$0
        AND     $1, RSP                                          // ERROR "illegal combination"
        ANDS    $1, R0, RSP                                      // ERROR "illegal combination"
-       MOVD.P  300(R2), R3                                      // ERROR "offset out of range [-255,254]"
-       MOVD.P  R3, 344(R2)                                      // ERROR "offset out of range [-255,254]"
        ADDSW   R7->32, R14, R13                                 // ERROR "shift amount out of range 0 to 31"
-       BICW    R7@>33, R5, R16                                  // ERROR "shift amount out of range 0 to 31"
        ADD     R1.UXTB<<5, R2, R3                               // ERROR "shift amount out of range 0 to 4"
        ADDS    R1.UXTX<<7, R2, R3                               // ERROR "shift amount out of range 0 to 4"
+       BICW    R7@>33, R5, R16                                  // ERROR "shift amount out of range 0 to 31"
+       MOVD.P  300(R2), R3                                      // ERROR "offset out of range [-255,254]"
+       MOVD.P  R3, 344(R2)                                      // ERROR "offset out of range [-255,254]"
+       MOVD    (R3)(R7.SXTX<<2), R8                             // ERROR "invalid index shift amount"
+       MOVWU   (R5)(R4.UXTW<<3), R10                            // ERROR "invalid index shift amount"
+       MOVWU   (R5)(R4<<1), R10                                 // ERROR "invalid index shift amount"
        VLD1    (R8)(R13), [V2.B16]                              // ERROR "illegal combination"
        VLD1    8(R9), [V2.B16]                                  // ERROR "illegal combination"
        VST1    [V1.B16], (R8)(R13)                              // ERROR "illegal combination"
@@ -72,4 +75,8 @@ TEXT errors(SB),$0
        VRBIT   V1.H4, V2.H4                                     // ERROR "invalid arrangement"
        VUSHR   $56, V1.D2, V2.H4                                // ERROR "invalid arrangement"
        VUSHR   $127, V1.D2, V2.D2                               // ERROR "shift out of range"
+       VLD1.P  (R8)(R9.SXTX<<2), [V2.B16]                       // ERROR "invalid extended register"
+       VLD1.P  (R8)(R9<<2), [V2.B16]                            // ERROR "invalid extended register"
+       VST1.P  [V1.B16], (R8)(R9.UXTW)                          // ERROR "invalid extended register"
+       VST1.P  [V1.B16], (R8)(R9<<1)                            // ERROR "invalid extended register"
        RET
index 1b5d93d52a3a00bcb340c6dd45ee8658834e412e..0f03b0593043f33ef87af03cc2d5d858407bb066 100644 (file)
@@ -178,6 +178,8 @@ const (
 // constants to indicate extended register conversion. When checking,
 // you should subtract obj.RBaseARM64 first. From this difference, bit 11
 // indicates extended register, bits 8-10 select the conversion mode.
+// REG_LSL is the index shift specifier, bit 9 indicates shifted offset register.
+const REG_LSL = obj.RBaseARM64 + 1<<9
 const REG_EXT = obj.RBaseARM64 + 1<<11
 
 const (
index 45d793ce5934a467abec3162831479110e9d6202..85eb5fe53238c41a5fc2d7274930514e9fedec3d 100644 (file)
@@ -445,6 +445,10 @@ var optab = []Optab{
        {AFMOVD, C_FREG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
        {AVMOVS, C_VREG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
 
+       /* load with shifted or extended register offset */
+       {AMOVD, C_ROFF, C_NONE, C_REG, 98, 4, 0, 0, 0},
+       {AMOVW, C_ROFF, C_NONE, C_REG, 98, 4, 0, 0, 0},
+
        /* pre/post-indexed/signed-offset load/store register pair
           (unscaled, signed 10-bit quad-aligned and long offset) */
        {ALDP, C_NPAUTO, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
@@ -1027,6 +1031,10 @@ func (c *ctxt7) regoff(a *obj.Addr) uint32 {
        return uint32(c.instoffset)
 }
 
+func isRegShiftOrExt(a *obj.Addr) bool {
+       return (a.Index-obj.RBaseARM64)&REG_EXT != 0 || (a.Index-obj.RBaseARM64)&REG_LSL != 0
+}
+
 // Maximum PC-relative displacement.
 // The actual limit is ±2²⁰, but we are conservative
 // to avoid needing to recompute the literal pool flush points
@@ -1379,8 +1387,13 @@ func (c *ctxt7) aclass(a *obj.Addr) int {
                case obj.NAME_NONE:
                        if a.Index != 0 {
                                if a.Offset != 0 {
+                                       if isRegShiftOrExt(a) {
+                                               // extended or shifted register offset, (Rn)(Rm.UXTW<<2) or (Rn)(Rm<<2).
+                                               return C_ROFF
+                                       }
                                        return C_GOK
                                }
+                               // register offset, (Rn)(Rm)
                                return C_ROFF
                        }
                        c.instoffset = a.Offset
@@ -2317,7 +2330,7 @@ func (c *ctxt7) checkindex(p *obj.Prog, index, maxindex int) {
        }
 }
 
-/* checkoffset checks whether the immediate offset is valid for VLD1.P and VST1.P*/
+/* checkoffset checks whether the immediate offset is valid for VLD1.P and VST1.P */
 func (c *ctxt7) checkoffset(p *obj.Prog, as obj.As) {
        var offset, list, n int64
        switch as {
@@ -2352,6 +2365,23 @@ func (c *ctxt7) checkoffset(p *obj.Prog, as obj.As) {
        }
 }
 
+/* checkShiftAmount checks whether the index shift amount is valid */
+/* for load with register offset instructions */
+func (c *ctxt7) checkShiftAmount(p *obj.Prog, as obj.As) {
+       amount := (p.From.Index >> 5) & 7
+       switch as {
+       case AMOVWU:
+               if amount != 2 && amount != 0 {
+                       c.ctxt.Diag("invalid index shift amount: %v", p)
+               }
+
+       case AMOVD:
+               if amount != 3 && amount != 0 {
+                       c.ctxt.Diag("invalid index shift amount: %v", p)
+               }
+       }
+}
+
 func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
        o1 := uint32(0)
        o2 := uint32(0)
@@ -2928,7 +2958,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                        c.ctxt.Diag("REGTMP used in large offset load: %v", p)
                }
                o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
-               o2 = c.olsxrr(p, int32(c.opldrr(p, p.As)), int(p.To.Reg), r, REGTMP)
+               o2 = c.olsxrr(p, int32(c.opldrr(p, p.As, false)), int(p.To.Reg), r, REGTMP)
 
        case 32: /* mov $con, R -> movz/movn */
                o1 = c.omovconst(p.As, p, &p.From, int(p.To.Reg))
@@ -3706,6 +3736,9 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                                o1 |= 0x1f << 16
                        } else {
                                // register offset variant
+                               if isRegShiftOrExt(&p.From) {
+                                       c.ctxt.Diag("invalid extended register op: %v\n", p)
+                               }
                                o1 |= uint32(p.From.Index&31) << 16
                        }
                }
@@ -3799,6 +3832,9 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                                o1 |= 0x1f << 16
                        } else {
                                // register offset variant
+                               if isRegShiftOrExt(&p.To) {
+                                       c.ctxt.Diag("invalid extended register: %v\n", p)
+                               }
                                o1 |= uint32(p.To.Index&31) << 16
                        }
                }
@@ -3903,6 +3939,30 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
        case 90:
                o1 = 0xbea71700
 
+       case 91: /* prfm imm(Rn), <prfop | $imm5> */
+               imm := uint32(p.From.Offset)
+               r := p.From.Reg
+               v := uint32(0xff)
+               if p.To.Type == obj.TYPE_CONST {
+                       v = uint32(p.To.Offset)
+                       if v > 31 {
+                               c.ctxt.Diag("illegal prefetch operation\n%v", p)
+                       }
+               } else {
+                       for i := 0; i < len(prfopfield); i++ {
+                               if prfopfield[i].reg == p.To.Reg {
+                                       v = prfopfield[i].enc
+                                       break
+                               }
+                       }
+                       if v == 0xff {
+                               c.ctxt.Diag("illegal prefetch operation:\n%v", p)
+                       }
+               }
+
+               o1 = c.opldrpp(p, p.As)
+               o1 |= (uint32(r&31) << 5) | (uint32((imm>>3)&0xfff) << 10) | (uint32(v & 31))
+
        case 92: /* vmov Vn.<T>[index], Vd.<T>[index] */
                rf := int(p.From.Reg)
                rt := int(p.To.Reg)
@@ -3944,32 +4004,6 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                }
                o1 |= (uint32(imm5&0x1f) << 16) | (uint32(imm4&0xf) << 11) | (uint32(rf&31) << 5) | uint32(rt&31)
 
-               break
-
-       case 91: /* prfm imm(Rn), <prfop | $imm5> */
-               imm := uint32(p.From.Offset)
-               r := p.From.Reg
-               v := uint32(0xff)
-               if p.To.Type == obj.TYPE_CONST {
-                       v = uint32(p.To.Offset)
-                       if v > 31 {
-                               c.ctxt.Diag("illegal prefetch operation\n%v", p)
-                       }
-               } else {
-                       for i := 0; i < len(prfopfield); i++ {
-                               if prfopfield[i].reg == p.To.Reg {
-                                       v = prfopfield[i].enc
-                                       break
-                               }
-                       }
-                       if v == 0xff {
-                               c.ctxt.Diag("illegal prefetch operation:\n%v", p)
-                       }
-               }
-
-               o1 = c.opldrpp(p, p.As)
-               o1 |= (uint32(r&31) << 5) | ((imm >> 3) & 0xfff << 10) | (v & 31)
-
        case 93: /* vpmull{2} Vm.<T>, Vn.<T>, Vd */
                af := int((p.From.Reg >> 5) & 15)
                at := int((p.To.Reg >> 5) & 15)
@@ -4255,6 +4289,24 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
                }
 
                o1 |= (uint32(Q&1) << 30) | (uint32(r&31) << 16) | ((opcode & 7) << 13) | (uint32(S&1) << 12) | (uint32(size&3) << 10) | (uint32(rf&31) << 5) | uint32(rt&31)
+
+       case 98: /* MOVD (Rn)(Rm.SXTW[<<amount]),Rd */
+               if p.From.Offset != 0 {
+                       // extended or shifted offset register.
+                       c.checkShiftAmount(p, p.As)
+                       o1 = c.opldrr(p, p.As, true)
+                       o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
+               } else {
+                       // (Rn)(Rm), no extension or shift.
+                       o1 = c.opldrr(p, p.As, false)
+                       o1 |= uint32(p.From.Index&31) << 16
+               }
+               o1 |= uint32(p.From.Reg&31) << 5
+               rt := int(p.To.Reg)
+               if p.To.Type == obj.TYPE_NONE {
+                       rt = REGZERO
+               }
+               o1 |= uint32(rt & 31)
        }
        out[0] = o1
        out[1] = o2
@@ -5584,26 +5636,31 @@ func (c *ctxt7) olsxrr(p *obj.Prog, o int32, r int, r1 int, r2 int) uint32 {
 
 // opldrr returns the ARM64 opcode encoding corresponding to the obj.As opcode
 // for load instruction with register offset.
-func (c *ctxt7) opldrr(p *obj.Prog, a obj.As) uint32 {
+// The offset register can be (Rn)(Rm.UXTW<<2) or (Rn)(Rm<<2) or (Rn)(Rm).
+func (c *ctxt7) opldrr(p *obj.Prog, a obj.As, extension bool) uint32 {
+       OptionS := uint32(0x1a)
+       if extension {
+               OptionS = uint32(0) // option value and S value have been encoded into p.From.Offset.
+       }
        switch a {
        case AMOVD:
-               return 0x1a<<10 | 0x3<<21 | 0x1f<<27
+               return OptionS<<10 | 0x3<<21 | 0x1f<<27
        case AMOVW:
-               return 0x1a<<10 | 0x5<<21 | 0x17<<27
+               return OptionS<<10 | 0x5<<21 | 0x17<<27
        case AMOVWU:
-               return 0x1a<<10 | 0x3<<21 | 0x17<<27
+               return OptionS<<10 | 0x3<<21 | 0x17<<27
        case AMOVH:
-               return 0x1a<<10 | 0x5<<21 | 0x0f<<27
+               return OptionS<<10 | 0x5<<21 | 0x0f<<27
        case AMOVHU:
-               return 0x1a<<10 | 0x3<<21 | 0x0f<<27
+               return OptionS<<10 | 0x3<<21 | 0x0f<<27
        case AMOVB:
-               return 0x1a<<10 | 0x5<<21 | 0x07<<27
+               return OptionS<<10 | 0x5<<21 | 0x07<<27
        case AMOVBU:
-               return 0x1a<<10 | 0x3<<21 | 0x07<<27
+               return OptionS<<10 | 0x3<<21 | 0x07<<27
        case AFMOVS:
-               return 0x1a<<10 | 0x3<<21 | 0x17<<27 | 1<<26
+               return OptionS<<10 | 0x3<<21 | 0x17<<27 | 1<<26
        case AFMOVD:
-               return 0x1a<<10 | 0x3<<21 | 0x1f<<27 | 1<<26
+               return OptionS<<10 | 0x3<<21 | 0x1f<<27 | 1<<26
        }
        c.ctxt.Diag("bad opldrr %v\n%v", a, p)
        return 0
index 918814ea38b66373affc1aadbc1cc3897141b9df..4e7cb0177e4a062b1c1642444805370d42981b56 100644 (file)
@@ -10,14 +10,6 @@ Go Assembly for ARM64 Reference Manual
 
 1. Alphabetical list of basic instructions
     // TODO
-    PRFM: Prefetch Memory (immediate)
-     PRFM      imm(Rn), <prfop>
-      prfop is the prefetch operation and can have the following values:
-      PLDL1KEEP, PLDL1STRM, PLDL2KEEP, PLDL2STRM, PLDL3KEEP, PLDL3STRM,
-      PLIL1KEEP, PLIL1STRM, PLIL2KEEP, PLIL2STRM, PLIL3KEEP, PLIL3STRM,
-      PSTL1KEEP, PSTL1STRM, PSTL2KEEP, PSTL2STRM, PSTL3KEEP, PSTL3STRM.
-     PRFM      imm(Rn), $imm
-      $imm prefetch operation is encoded as an immediate.
 
     LDARB: Load-Acquire Register Byte
       LDARB    (<Rn>), <Rd>
@@ -43,6 +35,20 @@ Go Assembly for ARM64 Reference Manual
       LDXPW    (<Rn>), (<Rt1>, <Rt2>)
         Loads two 32-bit words from memory, and writes them to Rt1 and Rt2.
 
+    MOVD|MOVW: Load Register (register offset)
+      MOVD     (Rn)(Rm.UXTW<<3), Rt
+      MOVD     (Rn)(Rm.SXTX), Rt
+      MOVD     (Rn)(Rm), Rt
+
+    PRFM: Prefetch Memory (immediate)
+      PRFM     imm(Rn), <prfop>
+        prfop is the prefetch operation and can have the following values:
+        PLDL1KEEP, PLDL1STRM, PLDL2KEEP, PLDL2STRM, PLDL3KEEP, PLDL3STRM,
+        PLIL1KEEP, PLIL1STRM, PLIL2KEEP, PLIL2STRM, PLIL3KEEP, PLIL3STRM,
+        PSTL1KEEP, PSTL1STRM, PSTL2KEEP, PSTL2STRM, PSTL3KEEP, PSTL3STRM.
+      PRFM     imm(Rn), $imm
+        $imm prefetch operation is encoded as an immediate.
+
     STLRB: Store-Release Register Byte
       STLRB    <Rd>, (<Rn>)
         Stores a byte from Rd to a memory location from Rn.
index 1bf20ae71b34b836b2f18ee333f0407ec37ecd1f..093af6cb065dbd27a413a505dffa64e96ba8c6db 100644 (file)
@@ -223,6 +223,9 @@ func rconv(r int) string {
                } else {
                        return fmt.Sprintf("%s.SXTX", regname(r))
                }
+       // bits 0-4 indicate register, bits 5-7 indicate shift amount, bit 8 equals to 0.
+       case REG_LSL <= r && r < (REG_LSL+1<<8):
+               return fmt.Sprintf("R%d<<%d", r&31, (r>>5)&7)
        case REG_ARNG <= r && r < REG_ELEM:
                return fmt.Sprintf("V%d.%s", r&31, arrange((r>>5)&15))
        case REG_ELEM <= r && r < REG_ELEM_END:
index 3fc6113112c7c1d80c963e31a469d5cbf1307371..2d457fd5035cce0b8f09031dbce946e6a1a2b39f 100644 (file)
@@ -214,7 +214,12 @@ func Dconv(p *Prog, a *Addr) string {
        case TYPE_MEM:
                str = Mconv(a)
                if a.Index != REG_NONE {
-                       str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
+                       if a.Scale == 0 {
+                               // arm64 shifted or extended register offset, scale = 0.
+                               str += fmt.Sprintf("(%v)", Rconv(int(a.Index)))
+                       } else {
+                               str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
+                       }
                }
 
        case TYPE_CONST:
@@ -294,7 +299,17 @@ func Mconv(a *Addr) string {
                case a.Offset == 0:
                        str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
                case a.Offset != 0:
-                       str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
+                       switch objabi.GOARCH {
+                       case "arm64":
+                               // the register and the extension/shift are encoded in a.Offset.
+                               if a.Index != 0 {
+                                       str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
+                                       return str
+                               }
+                               fallthrough
+                       default:
+                               str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
+                       }
                }
 
                // Note: a.Reg == REG_NONE encodes the default base register for the NAME_ type.