]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.cc] cm/asm: fix up arm after cross-check with 5a
authorRob Pike <r@golang.org>
Sat, 21 Feb 2015 00:02:11 +0000 (16:02 -0800)
committerRob Pike <r@golang.org>
Sat, 21 Feb 2015 01:53:30 +0000 (01:53 +0000)
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>
src/cmd/asm/internal/arch/arm.go
src/cmd/asm/internal/asm/asm.go
src/cmd/asm/internal/asm/operand_test.go
src/cmd/asm/internal/asm/parse.go

index 75bb0be1688f0c32d4afb6236940449e5a02df7a..fab896a79fef70ece69f806099cc4d65ec84060b 100644 (file)
@@ -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:]
        }
index 31e643ffb9455c16c3f31ec3c1395df985f895a8..5d0d0801902cba1fa0a9427aea972ac723416be2 100644 (file)
@@ -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
index 0e3d844954208d6d060f6331b5a05bc21721820e..4437b7d5a6050ef0ee7dd6ddf551e9c2d787feeb 100644 (file)
@@ -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"},
index 05db95b420890911b604c04514b13a4aeeefab50..14539dc9118a3cdb155a9b55bf9f57fa9082ee78 100644 (file)
@@ -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
+}