diff options
| author | fanzha02 <fannie.zhang@arm.com> | 2017-12-08 08:19:32 +0000 |
|---|---|---|
| committer | Brad Fitzpatrick <bradfitz@golang.org> | 2018-04-09 18:20:41 +0000 |
| commit | 31700b83b5d9bdc2ddc474fd72b809a7b585d6da (patch) | |
| tree | fe4f875dfd824522743ad9d912d1c414fd582879 /src/cmd/asm | |
| parent | 14393c5cd4fed812c87ba45fe4e2b8d07c02e8fa (diff) | |
| download | go-31700b83b5d9bdc2ddc474fd72b809a7b585d6da.tar.xz | |
cmd/internal/obj/arm64: add assembler support for load with register offset
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>
Diffstat (limited to 'src/cmd/asm')
| -rw-r--r-- | src/cmd/asm/internal/arch/arm64.go | 88 | ||||
| -rw-r--r-- | src/cmd/asm/internal/asm/parse.go | 50 | ||||
| -rw-r--r-- | src/cmd/asm/internal/asm/testdata/arm64.s | 8 | ||||
| -rw-r--r-- | src/cmd/asm/internal/asm/testdata/arm64error.s | 13 |
4 files changed, 120 insertions, 39 deletions
diff --git a/src/cmd/asm/internal/arch/arm64.go b/src/cmd/asm/internal/arch/arm64.go index af45f421e9..3941e36372 100644 --- a/src/cmd/asm/internal/arch/arm64.go +++ b/src/cmd/asm/internal/arch/arm64.go @@ -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 } diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go index 833693ba21..0ac1f04c10 100644 --- a/src/cmd/asm/internal/asm/parse.go +++ b/src/cmd/asm/internal/asm/parse.go @@ -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 { diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index 8ee2e01615..0860cbbf22 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -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); diff --git a/src/cmd/asm/internal/asm/testdata/arm64error.s b/src/cmd/asm/internal/asm/testdata/arm64error.s index 37e9442eca..4a1142e8a8 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64error.s +++ b/src/cmd/asm/internal/asm/testdata/arm64error.s @@ -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 |
