mirror of
https://github.com/golang/go
synced 2024-11-23 12:20:12 -07:00
cmd/internal/obj/arm64: add support for a series of load/store with register offset instrucitons
The patch adds support for arm64 instructions LDRB, LDRH, LDRSB, LDRSH, LDRSW, STR, STRB and STRH with register offset. Test cases are also added. Change-Id: I8d17fddd2963c0bc366e12b00bac49b93f3f0957 Reviewed-on: https://go-review.googlesource.com/91575 Reviewed-by: Cherry Zhang <cherryyz@google.com> Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
e0ac5f540b
commit
604028568e
28
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
28
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
@ -107,6 +107,34 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
|||||||
MOVD (R2)(R6<<3), R4 // 447866f8
|
MOVD (R2)(R6<<3), R4 // 447866f8
|
||||||
MOVD (R3)(R7.SXTX<<3), R8 // 68f867f8
|
MOVD (R3)(R7.SXTX<<3), R8 // 68f867f8
|
||||||
MOVWU (R5)(R4.UXTW), R10 // aa4864b8
|
MOVWU (R5)(R4.UXTW), R10 // aa4864b8
|
||||||
|
MOVBU (R3)(R9.UXTW), R8 // 68486938
|
||||||
|
MOVBU (R5)(R8), R10 // MOVBU (R5)(R8*1), R10 // aa686838
|
||||||
|
MOVHU (R2)(R7.SXTW<<1), R11 // 4bd86778
|
||||||
|
MOVHU (R1)(R2<<1), R5 // 25786278
|
||||||
|
MOVB (R9)(R3.UXTW), R6 // 2649a338
|
||||||
|
MOVB (R10)(R6), R15 // MOVB (R10)(R6*1), R15 // 4f69a638
|
||||||
|
MOVH (R5)(R7.SXTX<<1), R18 // b2f8a778
|
||||||
|
MOVH (R8)(R4<<1), R10 // 0a79a478
|
||||||
|
MOVW (R9)(R8.SXTW<<2), R19 // 33d9a8b8
|
||||||
|
MOVW (R1)(R4.SXTX), R11 // 2be8a4b8
|
||||||
|
MOVW (R1)(R4.SXTX), ZR // 3fe8a4b8
|
||||||
|
MOVW (R2)(R5), R12 // MOVW (R2)(R5*1), R12 // 4c68a5b8
|
||||||
|
MOVD R5, (R2)(R6<<3) // 457826f8
|
||||||
|
MOVD R9, (R6)(R7.SXTX<<3) // c9f827f8
|
||||||
|
MOVD ZR, (R6)(R7.SXTX<<3) // dff827f8
|
||||||
|
MOVW R8, (R2)(R3.UXTW<<2) // 485823b8
|
||||||
|
MOVW R7, (R3)(R4.SXTW) // 67c824b8
|
||||||
|
MOVB R4, (R2)(R6.SXTX) // 44e82638
|
||||||
|
MOVB R8, (R3)(R9.UXTW) // 68482938
|
||||||
|
MOVB R10, (R5)(R8) // MOVB R10, (R5)(R8*1) // aa682838
|
||||||
|
MOVH R11, (R2)(R7.SXTW<<1) // 4bd82778
|
||||||
|
MOVH R5, (R1)(R2<<1) // 25782278
|
||||||
|
MOVH R7, (R2)(R5.SXTX<<1) // 47f82578
|
||||||
|
MOVH R8, (R3)(R6.UXTW) // 68482678
|
||||||
|
MOVB (R29)(R30<<0), R14 // ae7bbe38
|
||||||
|
MOVB (R29)(R30), R14 // MOVB (R29)(R30*1), R14 // ae6bbe38
|
||||||
|
MOVB R4, (R2)(R6.SXTX) // 44e82638
|
||||||
|
|
||||||
// LTYPE1 imsr ',' spreg ','
|
// LTYPE1 imsr ',' spreg ','
|
||||||
// {
|
// {
|
||||||
// outcode($1, &$2, $4, &nullgen);
|
// outcode($1, &$2, $4, &nullgen);
|
||||||
|
@ -14,6 +14,8 @@ TEXT errors(SB),$0
|
|||||||
MOVD (R3)(R7.SXTX<<2), R8 // ERROR "invalid index shift amount"
|
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.UXTW<<3), R10 // ERROR "invalid index shift amount"
|
||||||
MOVWU (R5)(R4<<1), R10 // ERROR "invalid index shift amount"
|
MOVWU (R5)(R4<<1), R10 // ERROR "invalid index shift amount"
|
||||||
|
MOVB (R5)(R4.SXTW<<5), R10 // ERROR "invalid index shift amount"
|
||||||
|
MOVH R5, (R6)(R2<<3) // ERROR "invalid index shift amount"
|
||||||
VLD1 (R8)(R13), [V2.B16] // ERROR "illegal combination"
|
VLD1 (R8)(R13), [V2.B16] // ERROR "illegal combination"
|
||||||
VLD1 8(R9), [V2.B16] // ERROR "illegal combination"
|
VLD1 8(R9), [V2.B16] // ERROR "illegal combination"
|
||||||
VST1 [V1.B16], (R8)(R13) // ERROR "illegal combination"
|
VST1 [V1.B16], (R8)(R13) // ERROR "illegal combination"
|
||||||
|
@ -448,6 +448,15 @@ var optab = []Optab{
|
|||||||
/* load with shifted or extended register offset */
|
/* load with shifted or extended register offset */
|
||||||
{AMOVD, C_ROFF, C_NONE, C_REG, 98, 4, 0, 0, 0},
|
{AMOVD, C_ROFF, C_NONE, C_REG, 98, 4, 0, 0, 0},
|
||||||
{AMOVW, C_ROFF, C_NONE, C_REG, 98, 4, 0, 0, 0},
|
{AMOVW, C_ROFF, C_NONE, C_REG, 98, 4, 0, 0, 0},
|
||||||
|
{AMOVH, C_ROFF, C_NONE, C_REG, 98, 4, 0, 0, 0},
|
||||||
|
{AMOVB, C_ROFF, C_NONE, C_REG, 98, 4, 0, 0, 0},
|
||||||
|
{AMOVBU, C_ROFF, C_NONE, C_REG, 98, 4, 0, 0, 0},
|
||||||
|
|
||||||
|
/* store with extended register offset */
|
||||||
|
{AMOVD, C_REG, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
|
||||||
|
{AMOVW, C_REG, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
|
||||||
|
{AMOVH, C_REG, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
|
||||||
|
{AMOVB, C_REG, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
|
||||||
|
|
||||||
/* pre/post-indexed/signed-offset load/store register pair
|
/* pre/post-indexed/signed-offset load/store register pair
|
||||||
(unscaled, signed 10-bit quad-aligned and long offset) */
|
(unscaled, signed 10-bit quad-aligned and long offset) */
|
||||||
@ -2367,10 +2376,19 @@ func (c *ctxt7) checkoffset(p *obj.Prog, as obj.As) {
|
|||||||
|
|
||||||
/* checkShiftAmount checks whether the index shift amount is valid */
|
/* checkShiftAmount checks whether the index shift amount is valid */
|
||||||
/* for load with register offset instructions */
|
/* for load with register offset instructions */
|
||||||
func (c *ctxt7) checkShiftAmount(p *obj.Prog, as obj.As) {
|
func (c *ctxt7) checkShiftAmount(p *obj.Prog, a *obj.Addr) {
|
||||||
amount := (p.From.Index >> 5) & 7
|
var amount int16
|
||||||
switch as {
|
amount = (a.Index >> 5) & 7
|
||||||
case AMOVWU:
|
switch p.As {
|
||||||
|
case AMOVB, AMOVBU:
|
||||||
|
if amount != 0 {
|
||||||
|
c.ctxt.Diag("invalid index shift amount: %v", p)
|
||||||
|
}
|
||||||
|
case AMOVH, AMOVHU:
|
||||||
|
if amount != 1 && amount != 0 {
|
||||||
|
c.ctxt.Diag("invalid index shift amount: %v", p)
|
||||||
|
}
|
||||||
|
case AMOVW, AMOVWU:
|
||||||
if amount != 2 && amount != 0 {
|
if amount != 2 && amount != 0 {
|
||||||
c.ctxt.Diag("invalid index shift amount: %v", p)
|
c.ctxt.Diag("invalid index shift amount: %v", p)
|
||||||
}
|
}
|
||||||
@ -2914,7 +2932,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
|||||||
c.ctxt.Diag("REGTMP used in large offset store: %v", p)
|
c.ctxt.Diag("REGTMP used in large offset store: %v", p)
|
||||||
}
|
}
|
||||||
o1 = c.omovlit(AMOVD, p, &p.To, REGTMP)
|
o1 = c.omovlit(AMOVD, p, &p.To, REGTMP)
|
||||||
o2 = c.olsxrr(p, int32(c.opstrr(p, p.As)), int(p.From.Reg), r, REGTMP)
|
o2 = c.olsxrr(p, int32(c.opstrr(p, p.As, false)), int(p.From.Reg), r, REGTMP)
|
||||||
|
|
||||||
case 31: /* movT L(R), R -> ldrT */
|
case 31: /* movT L(R), R -> ldrT */
|
||||||
// if offset L can be split into hi+lo, and both fit into instructions, do
|
// if offset L can be split into hi+lo, and both fit into instructions, do
|
||||||
@ -4293,7 +4311,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
|||||||
case 98: /* MOVD (Rn)(Rm.SXTW[<<amount]),Rd */
|
case 98: /* MOVD (Rn)(Rm.SXTW[<<amount]),Rd */
|
||||||
if p.From.Offset != 0 {
|
if p.From.Offset != 0 {
|
||||||
// extended or shifted offset register.
|
// extended or shifted offset register.
|
||||||
c.checkShiftAmount(p, p.As)
|
c.checkShiftAmount(p, &p.From)
|
||||||
o1 = c.opldrr(p, p.As, true)
|
o1 = c.opldrr(p, p.As, true)
|
||||||
o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
|
o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
|
||||||
} else {
|
} else {
|
||||||
@ -4303,10 +4321,23 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
|||||||
}
|
}
|
||||||
o1 |= uint32(p.From.Reg&31) << 5
|
o1 |= uint32(p.From.Reg&31) << 5
|
||||||
rt := int(p.To.Reg)
|
rt := int(p.To.Reg)
|
||||||
if p.To.Type == obj.TYPE_NONE {
|
|
||||||
rt = REGZERO
|
|
||||||
}
|
|
||||||
o1 |= uint32(rt & 31)
|
o1 |= uint32(rt & 31)
|
||||||
|
|
||||||
|
case 99: /* MOVD Rt, (Rn)(Rm.SXTW[<<amount]) */
|
||||||
|
if p.To.Offset != 0 {
|
||||||
|
// extended or shifted offset register.
|
||||||
|
c.checkShiftAmount(p, &p.To)
|
||||||
|
o1 = c.opstrr(p, p.As, true)
|
||||||
|
o1 |= uint32(p.To.Offset) /* includes reg, op, etc */
|
||||||
|
} else {
|
||||||
|
// (Rn)(Rm), no extension or shift.
|
||||||
|
o1 = c.opstrr(p, p.As, false)
|
||||||
|
o1 |= uint32(p.To.Index&31) << 16
|
||||||
|
}
|
||||||
|
o1 |= uint32(p.To.Reg&31) << 5
|
||||||
|
rf := int(p.From.Reg)
|
||||||
|
o1 |= uint32(rf & 31)
|
||||||
|
|
||||||
}
|
}
|
||||||
out[0] = o1
|
out[0] = o1
|
||||||
out[1] = o2
|
out[1] = o2
|
||||||
@ -5668,20 +5699,25 @@ func (c *ctxt7) opldrr(p *obj.Prog, a obj.As, extension bool) uint32 {
|
|||||||
|
|
||||||
// opstrr returns the ARM64 opcode encoding corresponding to the obj.As opcode
|
// opstrr returns the ARM64 opcode encoding corresponding to the obj.As opcode
|
||||||
// for store instruction with register offset.
|
// for store instruction with register offset.
|
||||||
func (c *ctxt7) opstrr(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) opstrr(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.To.Offset.
|
||||||
|
}
|
||||||
switch a {
|
switch a {
|
||||||
case AMOVD:
|
case AMOVD:
|
||||||
return 0x1a<<10 | 0x1<<21 | 0x1f<<27
|
return OptionS<<10 | 0x1<<21 | 0x1f<<27
|
||||||
case AMOVW, AMOVWU:
|
case AMOVW, AMOVWU:
|
||||||
return 0x1a<<10 | 0x1<<21 | 0x17<<27
|
return OptionS<<10 | 0x1<<21 | 0x17<<27
|
||||||
case AMOVH, AMOVHU:
|
case AMOVH, AMOVHU:
|
||||||
return 0x1a<<10 | 0x1<<21 | 0x0f<<27
|
return OptionS<<10 | 0x1<<21 | 0x0f<<27
|
||||||
case AMOVB, AMOVBU:
|
case AMOVB, AMOVBU:
|
||||||
return 0x1a<<10 | 0x1<<21 | 0x07<<27
|
return OptionS<<10 | 0x1<<21 | 0x07<<27
|
||||||
case AFMOVS:
|
case AFMOVS:
|
||||||
return 0x1a<<10 | 0x1<<21 | 0x17<<27 | 1<<26
|
return OptionS<<10 | 0x1<<21 | 0x17<<27 | 1<<26
|
||||||
case AFMOVD:
|
case AFMOVD:
|
||||||
return 0x1a<<10 | 0x1<<21 | 0x1f<<27 | 1<<26
|
return OptionS<<10 | 0x1<<21 | 0x1f<<27 | 1<<26
|
||||||
}
|
}
|
||||||
c.ctxt.Diag("bad opstrr %v\n%v", a, p)
|
c.ctxt.Diag("bad opstrr %v\n%v", a, p)
|
||||||
return 0
|
return 0
|
||||||
|
@ -35,10 +35,17 @@ Go Assembly for ARM64 Reference Manual
|
|||||||
LDXPW (<Rn>), (<Rt1>, <Rt2>)
|
LDXPW (<Rn>), (<Rt1>, <Rt2>)
|
||||||
Loads two 32-bit words from memory, and writes them to Rt1 and Rt2.
|
Loads two 32-bit words from memory, and writes them to Rt1 and Rt2.
|
||||||
|
|
||||||
MOVD|MOVW: Load Register (register offset)
|
MOVD|MOVW|MOVH|MOVHU|MOVB|MOVBU: Load Register (register offset)
|
||||||
MOVD (Rn)(Rm.UXTW<<3), Rt
|
MOVD (Rn)(Rm.UXTW<<3), Rt
|
||||||
MOVD (Rn)(Rm.SXTX), Rt
|
MOVD (Rn)(Rm.SXTX), Rt
|
||||||
|
MOVD (Rn)(Rm<<3), Rt
|
||||||
MOVD (Rn)(Rm), Rt
|
MOVD (Rn)(Rm), Rt
|
||||||
|
MOVB|MOVBU (Rn)(Rm.UXTW), Rt
|
||||||
|
|
||||||
|
MOVD|MOVW|MOVH|MOVB: Stote Register (register offset)
|
||||||
|
MOVD Rt, (Rn)(Rm.UXTW<<3)
|
||||||
|
MOVD Rt, (Rn)(Rm.SXTX)
|
||||||
|
MOVD Rt, (Rn)(Rm)
|
||||||
|
|
||||||
PRFM: Prefetch Memory (immediate)
|
PRFM: Prefetch Memory (immediate)
|
||||||
PRFM imm(Rn), <prfop>
|
PRFM imm(Rn), <prfop>
|
||||||
|
Loading…
Reference in New Issue
Block a user