Commit 9bf521b2 authored by Ben Shi's avatar Ben Shi Committed by Cherry Zhang

cmd/internal/obj/arm: support BFX/BFXU instructions

BFX extracts given bits from the source register, sign extends them
to 32-bit, and writes to destination register. BFXU does the similar
operation with zero extention.

They were introduced in ARMv6T2.

Change-Id: I6822ebf663497a87a662d3645eddd7c611de2b1e
Reviewed-on: https://go-review.googlesource.com/56071
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarCherry Zhang <cherryyz@google.com>
parent 07ec4385
...@@ -122,6 +122,15 @@ func IsARMMRC(op obj.As) bool { ...@@ -122,6 +122,15 @@ func IsARMMRC(op obj.As) bool {
return false return false
} }
// IsARMBFX reports whether the op is arm.BFX or arm.BFXU
func IsARMBFX(op obj.As) bool {
switch op {
case arm.ABFX, arm.ABFXU:
return true
}
return false
}
// IsARMFloatCmp reports whether the op is a floating comparison instruction. // IsARMFloatCmp reports whether the op is a floating comparison instruction.
func IsARMFloatCmp(op obj.As) bool { func IsARMFloatCmp(op obj.As) bool {
switch op { switch op {
......
...@@ -564,6 +564,13 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { ...@@ -564,6 +564,13 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.To = a[2] prog.To = a[2]
break break
} }
if arch.IsARMBFX(op) {
// a[0] and a[1] must be constants, a[2] must be a register
prog.From = a[0]
prog.From3 = newAddr(a[1])
prog.To = a[2]
break
}
// Otherwise the 2nd operand (a[1]) must be a register. // Otherwise the 2nd operand (a[1]) must be a register.
prog.From = a[0] prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1]) prog.Reg = p.getRegister(prog, op, &a[1])
...@@ -635,7 +642,16 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { ...@@ -635,7 +642,16 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
return return
} }
case 4: case 4:
if p.arch.Family == sys.ARM && arch.IsARMMULA(op) { if p.arch.Family == sys.ARM {
if arch.IsARMBFX(op) {
// a[0] and a[1] must be constants, a[2] and a[3] must be registers
prog.From = a[0]
prog.From3 = newAddr(a[1])
prog.Reg = p.getRegister(prog, op, &a[2])
prog.To = a[3]
break
}
if arch.IsARMMULA(op) {
// All must be registers. // All must be registers.
p.getRegister(prog, op, &a[0]) p.getRegister(prog, op, &a[0])
r1 := p.getRegister(prog, op, &a[1]) r1 := p.getRegister(prog, op, &a[1])
...@@ -648,6 +664,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { ...@@ -648,6 +664,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.Reg = r1 prog.Reg = r1
break break
} }
}
if p.arch.Family == sys.AMD64 { if p.arch.Family == sys.AMD64 {
// 4 operand instruction have form ymm1, ymm2, ymm3/m256, imm8 // 4 operand instruction have form ymm1, ymm2, ymm3/m256, imm8
// So From3 is always just a register, so we store imm8 in Offset field, // So From3 is always just a register, so we store imm8 in Offset field,
......
...@@ -1007,6 +1007,12 @@ jmp_label_3: ...@@ -1007,6 +1007,12 @@ jmp_label_3:
SWI $65535 // ffff00ef SWI $65535 // ffff00ef
SWI // 000000ef SWI // 000000ef
// BFX/BFXU
BFX $16, $8, R1, R2 // BFX $16, R1, $8, R2 // 5124afe7
BFX $29, $2, R8 // 5881bce7
BFXU $16, $8, R1, R2 // BFXU $16, R1, $8, R2 // 5124efe7
BFXU $29, $2, R8 // 5881fce7
// synthetic arithmatic // synthetic arithmatic
ADD $0xffffffaa, R2, R3 // ADD $4294967210, R2, R3 // 55b0e0e30b3082e0 ADD $0xffffffaa, R2, R3 // ADD $4294967210, R2, R3 // 55b0e0e30b3082e0
ADD $0xffffff55, R5 // ADD $4294967125, R5 // aab0e0e30b5085e0 ADD $0xffffff55, R5 // ADD $4294967125, R5 // aab0e0e30b5085e0
......
...@@ -124,5 +124,12 @@ TEXT errors(SB),$0 ...@@ -124,5 +124,12 @@ TEXT errors(SB),$0
MOVFW CPSR, R2 // ERROR "illegal combination" MOVFW CPSR, R2 // ERROR "illegal combination"
MOVDW R1, CPSR // ERROR "illegal combination" MOVDW R1, CPSR // ERROR "illegal combination"
MOVFW R1, CPSR // ERROR "illegal combination" MOVFW R1, CPSR // ERROR "illegal combination"
BFX $12, $41, R2, R3 // ERROR "wrong width or LSB"
BFX $12, $-2, R2 // ERROR "wrong width or LSB"
BFXU $40, $4, R2, R3 // ERROR "wrong width or LSB"
BFXU $-40, $4, R2 // ERROR "wrong width or LSB"
BFX $-2, $4, R2, R3 // ERROR "wrong width or LSB"
BFXU $4, R2, R5, R2 // ERROR "missing or wrong LSB"
BFXU $4, R2, R5 // ERROR "missing or wrong LSB"
END END
...@@ -294,6 +294,9 @@ const ( ...@@ -294,6 +294,9 @@ const (
AREVSH AREVSH
ARBIT ARBIT
ABFX
ABFXU
AMULWT AMULWT
AMULWB AMULWB
AMULBB AMULBB
......
...@@ -107,6 +107,8 @@ var Anames = []string{ ...@@ -107,6 +107,8 @@ var Anames = []string{
"REV16", "REV16",
"REVSH", "REVSH",
"RBIT", "RBIT",
"BFX",
"BFXU",
"MULWT", "MULWT",
"MULWB", "MULWB",
"MULBB", "MULBB",
......
...@@ -180,6 +180,8 @@ var optab = []Optab{ ...@@ -180,6 +180,8 @@ var optab = []Optab{
{ADIVHW, C_REG, C_REG, C_REG, 105, 4, 0, 0, 0}, {ADIVHW, C_REG, C_REG, C_REG, 105, 4, 0, 0, 0},
{ADIVHW, C_REG, C_NONE, C_REG, 105, 4, 0, 0, 0}, {ADIVHW, C_REG, C_NONE, C_REG, 105, 4, 0, 0, 0},
{AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0, 0, 0}, {AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0, 0, 0},
{ABFX, C_LCON, C_REG, C_REG, 18, 4, 0, 0, 0}, // width in From, LSB in From3
{ABFX, C_LCON, C_NONE, C_REG, 18, 4, 0, 0, 0}, // width in From, LSB in From3
{AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0}, {AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
{AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0}, {AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0},
{AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0}, {AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
...@@ -1691,6 +1693,9 @@ func buildop(ctxt *obj.Link) { ...@@ -1691,6 +1693,9 @@ func buildop(ctxt *obj.Link) {
opset(AMMULA, r0) opset(AMMULA, r0)
opset(AMMULS, r0) opset(AMMULS, r0)
case ABFX:
opset(ABFXU, r0)
case ACLZ: case ACLZ:
opset(AREV, r0) opset(AREV, r0)
opset(AREV16, r0) opset(AREV16, r0)
...@@ -2038,6 +2043,24 @@ func (c *ctxt5) asmout(p *obj.Prog, o *Optab, out []uint32) { ...@@ -2038,6 +2043,24 @@ func (c *ctxt5) asmout(p *obj.Prog, o *Optab, out []uint32) {
r := int(p.Reg) r := int(p.Reg)
o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12 o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12
case 18: /* BFX/BFXU */
o1 = c.oprrr(p, p.As, int(p.Scond))
rt := int(p.To.Reg)
r := int(p.Reg)
if r == 0 {
r = rt
}
if p.From3 == nil || p.From3.Type != obj.TYPE_CONST {
c.ctxt.Diag("%v: missing or wrong LSB", p)
break
}
lsb := p.From3.Offset
width := p.From.Offset
if lsb < 0 || lsb > 31 || width <= 0 || (lsb+width) > 31 {
c.ctxt.Diag("%v: wrong width or LSB", p)
}
o1 |= (uint32(r)&15)<<0 | (uint32(rt)&15)<<12 | uint32(lsb)<<7 | uint32(width-1)<<16
case 20: /* mov/movb/movbu R,O(R) */ case 20: /* mov/movb/movbu R,O(R) */
c.aclass(&p.To) c.aclass(&p.To)
...@@ -2911,6 +2934,12 @@ func (c *ctxt5) oprrr(p *obj.Prog, a obj.As, sc int) uint32 { ...@@ -2911,6 +2934,12 @@ func (c *ctxt5) oprrr(p *obj.Prog, a obj.As, sc int) uint32 {
case -ACMP: // cmp imm case -ACMP: // cmp imm
return o | 0x3<<24 | 0x5<<20 return o | 0x3<<24 | 0x5<<20
case ABFX:
return o | 0x3d<<21 | 0x5<<4
case ABFXU:
return o | 0x3f<<21 | 0x5<<4
// CLZ doesn't support .nil // CLZ doesn't support .nil
case ACLZ: case ACLZ:
return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4 return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment