mirror of
https://github.com/golang/go
synced 2024-11-19 12:54:45 -07:00
[dev.cc] cm/asm: fix up arm after cross-check with 5a
As with the previous round for ppc64, this CL fixes a couple of things that 5a supported but asm did not, both simple. 1) Allow condition code on MRC instruction; this was marked as a TODO. 2) Allow R(n) notation in ARM register shifts. The code needs a rethink but the tests we're leading toward will make the rewrite easier to test and trust. Change-Id: I5b52ad25d177a74cf07e089dddfeeab21863c424 Reviewed-on: https://go-review.googlesource.com/5422 Reviewed-by: Russ Cox <rsc@golang.org>
This commit is contained in:
parent
c11dadc503
commit
5d111b898a
@ -150,7 +150,7 @@ func ARMConditionCodes(prog *obj.Prog, cond string) bool {
|
||||
if cond == "" {
|
||||
return true
|
||||
}
|
||||
bits, ok := parseARMCondition(cond)
|
||||
bits, ok := ParseARMCondition(cond)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
@ -163,10 +163,10 @@ func ARMConditionCodes(prog *obj.Prog, cond string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// parseARMCondition parses the conditions attached to an ARM instruction.
|
||||
// ParseARMCondition parses the conditions attached to an ARM instruction.
|
||||
// The input is a single string consisting of period-separated condition
|
||||
// codes, such as ".P.W". An initial period is ignored.
|
||||
func parseARMCondition(cond string) (uint8, bool) {
|
||||
func ParseARMCondition(cond string) (uint8, bool) {
|
||||
if strings.HasPrefix(cond, ".") {
|
||||
cond = cond[1:]
|
||||
}
|
||||
|
@ -586,10 +586,15 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
|
||||
// Strange special case: MCR, MRC.
|
||||
// TODO: Move this to arch? (It will be hard to disentangle.)
|
||||
prog.To.Type = obj.TYPE_CONST
|
||||
bits, ok := uint8(0), false
|
||||
if cond != "" {
|
||||
p.errorf("TODO: can't handle ARM condition code for instruction %s", p.arch.Aconv(op))
|
||||
// Cond is handled specially for this instruction.
|
||||
bits, ok = arch.ParseARMCondition(cond)
|
||||
if !ok {
|
||||
p.errorf("unrecognized condition code .%q", cond)
|
||||
}
|
||||
cond = ""
|
||||
}
|
||||
cond = ""
|
||||
// First argument is a condition code as a constant.
|
||||
x0 := p.getConstant(prog, op, &a[0])
|
||||
x1 := p.getConstant(prog, op, &a[1])
|
||||
@ -605,7 +610,7 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
|
||||
prog.To.Offset =
|
||||
(0xe << 24) | // opcode
|
||||
(op1 << 20) | // MCR/MRC
|
||||
((0 ^ arm.C_SCOND_XOR) << 28) | // scond TODO; should use cond.
|
||||
((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond
|
||||
((x0 & 15) << 8) | //coprocessor number
|
||||
((x1 & 7) << 21) | // coprocessor operation
|
||||
((x2 & 15) << 12) | // ARM register
|
||||
|
@ -155,6 +155,7 @@ var amd64OperandTests = []operandTest{
|
||||
{"DI", "DI"},
|
||||
{"DX", "DX"},
|
||||
{"R10", "R10"},
|
||||
{"R10", "R10"},
|
||||
{"R11", "R11"},
|
||||
{"R12", "R12"},
|
||||
{"R13", "R13"},
|
||||
@ -282,7 +283,8 @@ var armOperandTests = []operandTest{
|
||||
{"R13", "R13"},
|
||||
{"R14", "R14"},
|
||||
{"R15", "R15"},
|
||||
{"R1<<2(R0)", "R1<<2(R0)"},
|
||||
{"R1<<2(R3)", "R1<<2(R3)"},
|
||||
{"R(1)<<2(R(3))", "R1<<2(R3)"},
|
||||
{"R2", "R2"},
|
||||
{"R3", "R3"},
|
||||
{"R4", "R4"},
|
||||
|
@ -273,7 +273,7 @@ func (p *Parser) operand(a *obj.Addr) bool {
|
||||
|
||||
// Register: R1
|
||||
if tok.ScanToken == scanner.Ident && p.atStartOfRegister(name) {
|
||||
if lex.IsRegisterShift(p.peek()) {
|
||||
if p.atRegisterShift() {
|
||||
// ARM shifted register such as R1<<R2 or R1>>2.
|
||||
a.Type = obj.TYPE_SHIFT
|
||||
a.Offset = p.registerShift(tok.String(), prefix)
|
||||
@ -381,6 +381,25 @@ func (p *Parser) atStartOfRegister(name string) bool {
|
||||
return p.arch.RegisterPrefix[name] && p.peek() == '('
|
||||
}
|
||||
|
||||
// atRegisterShift reports whether we are at the start of an ARM shifted register.
|
||||
// We have consumed the register or R prefix.
|
||||
func (p *Parser) atRegisterShift() bool {
|
||||
// ARM only.
|
||||
if p.arch.Thechar != '5' {
|
||||
return false
|
||||
}
|
||||
// R1<<...
|
||||
if lex.IsRegisterShift(p.peek()) {
|
||||
return true
|
||||
}
|
||||
// R(1)<<... Ugly check. TODO: Rethink how we handle ARM register shifts to be
|
||||
// less special.
|
||||
if p.peek() != '(' || len(p.input)-p.inputPos < 4 {
|
||||
return false
|
||||
}
|
||||
return p.at('(', scanner.Int, ')') && lex.IsRegisterShift(p.input[p.inputPos+3].ScanToken)
|
||||
}
|
||||
|
||||
// registerReference parses a register given either the name, R10, or a parenthesized form, SPR(10).
|
||||
func (p *Parser) registerReference(name string) (int16, bool) {
|
||||
r, present := p.arch.Register[name]
|
||||
@ -655,7 +674,7 @@ func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) {
|
||||
|
||||
// registerList parses an ARM register list expression, a list of registers in [].
|
||||
// There may be comma-separated ranges or individual registers, as in
|
||||
// [R1,R3-R5,R7]. Only R0 through R15 may appear.
|
||||
// [R1,R3-R5]. Only R0 through R15 may appear.
|
||||
// The opening bracket has been consumed.
|
||||
func (p *Parser) registerList(a *obj.Addr) {
|
||||
// One range per loop.
|
||||
@ -917,3 +936,16 @@ func (p *Parser) have(token lex.ScanToken) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// at reports whether the next tokens are as requested.
|
||||
func (p *Parser) at(next ...lex.ScanToken) bool {
|
||||
if len(p.input)-p.inputPos < len(next) {
|
||||
return false
|
||||
}
|
||||
for i, r := range next {
|
||||
if p.input[p.inputPos+i].ScanToken != r {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user