aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/asm/internal
diff options
context:
space:
mode:
authorfanzha02 <fannie.zhang@arm.com>2017-12-08 08:19:32 +0000
committerBrad Fitzpatrick <bradfitz@golang.org>2018-04-09 18:20:41 +0000
commit31700b83b5d9bdc2ddc474fd72b809a7b585d6da (patch)
treefe4f875dfd824522743ad9d912d1c414fd582879 /src/cmd/asm/internal
parent14393c5cd4fed812c87ba45fe4e2b8d07c02e8fa (diff)
downloadgo-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/internal')
-rw-r--r--src/cmd/asm/internal/arch/arm64.go88
-rw-r--r--src/cmd/asm/internal/asm/parse.go50
-rw-r--r--src/cmd/asm/internal/asm/testdata/arm64.s8
-rw-r--r--src/cmd/asm/internal/asm/testdata/arm64error.s13
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