Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -380,6 +380,7 @@ unsigned ListNo); int tryParseRegister(); + int tryParseGPRegister(); bool tryParseRegisterWithWriteBack(OperandVector &); int tryParseShiftRegister(OperandVector &); bool parseRegisterList(OperandVector &); @@ -3296,6 +3297,19 @@ return RegNum; } +// Try to parse a register used as base or offset in a memory operand. We need +// to distinguish between not parsing a register at all and parsing a +// non-general purpose register. In the former case we may try other parsing +// alternatives. +int ARMAsmParser::tryParseGPRegister() { + auto Reg = tryParseRegister(); + if (Reg < 0) + return -1; + if (!ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg)) + return -Reg; + return Reg; +} + // Try to parse a shifter (e.g., "lsl "). On success, return 0. // If a recoverable error occurs, return 1. If an irrecoverable error // occurs, return -1. An irrecoverable error is one where tokens have been @@ -3328,9 +3342,9 @@ // register operand instead. std::unique_ptr PrevOp( (ARMOperand *)Operands.pop_back_val().release()); - if (!PrevOp->isReg()) - return Error(PrevOp->getStartLoc(), "shift must be of a register"); - int SrcReg = PrevOp->getReg(); + int SrcReg = PrevOp->isReg() ? PrevOp->getReg() : -1; + if (SrcReg < 0 || !ARMMCRegisterClasses[ARM::GPRRegClassID].contains(SrcReg)) + return Error(Parser.getTok().getLoc(), "shift must be of general-purpose register"); SMLoc EndLoc; int64_t Imm = 0; @@ -3374,14 +3388,14 @@ } else if (Parser.getTok().is(AsmToken::Identifier)) { SMLoc L = Parser.getTok().getLoc(); EndLoc = Parser.getTok().getEndLoc(); - ShiftReg = tryParseRegister(); - if (ShiftReg == -1) { - Error(L, "expected immediate or register in shift operand"); + ShiftReg = tryParseGPRegister(); + if (ShiftReg < 0) { + Error(L, "expected immediate or general-purpose register in shift operand"); return -1; } } else { Error(Parser.getTok().getLoc(), - "expected immediate or register in shift operand"); + "expected immediate or general-purpose register in shift operand"); return -1; } } @@ -4723,11 +4737,11 @@ } SMLoc E = Parser.getTok().getEndLoc(); - int Reg = tryParseRegister(); - if (Reg == -1) { - if (!haveEaten) + int Reg = tryParseGPRegister(); + if (Reg < 0) { + if (Reg == -1 && !haveEaten) return MatchOperand_NoMatch; - Error(Parser.getTok().getLoc(), "register expected"); + Error(Parser.getTok().getLoc(), "general-purpose register expected"); return MatchOperand_ParseFail; } @@ -4805,11 +4819,11 @@ } Tok = Parser.getTok(); - int Reg = tryParseRegister(); - if (Reg == -1) { - if (!haveEaten) + int Reg = tryParseGPRegister(); + if (Reg < 0) { + if (Reg == -1 && !haveEaten) return MatchOperand_NoMatch; - Error(Tok.getLoc(), "register expected"); + Error(Tok.getLoc(), "general-purpose register expected"); return MatchOperand_ParseFail; } @@ -4907,9 +4921,9 @@ Parser.Lex(); // Eat left bracket token. const AsmToken &BaseRegTok = Parser.getTok(); - int BaseRegNum = tryParseRegister(); - if (BaseRegNum == -1) - return Error(BaseRegTok.getLoc(), "register expected"); + int BaseRegNum = tryParseGPRegister(); + if (BaseRegNum < 0) + return Error(BaseRegTok.getLoc(), "general-purpose register expected"); // The next token must either be a comma, a colon or a closing bracket. const AsmToken &Tok = Parser.getTok(); @@ -5054,9 +5068,9 @@ } E = Parser.getTok().getLoc(); - int OffsetRegNum = tryParseRegister(); - if (OffsetRegNum == -1) - return Error(E, "register expected"); + int OffsetRegNum = tryParseGPRegister(); + if (OffsetRegNum < 0) + return Error(E, "general-purpose register expected"); // If there's a shift operator, handle it. ARM_AM::ShiftOpc ShiftType = ARM_AM::no_shift; Index: test/MC/ARM/arm-reg-addr-errors.s =================================================================== --- /dev/null +++ test/MC/ARM/arm-reg-addr-errors.s @@ -0,0 +1,70 @@ +@ RUN: not llvm-mc -triple=armv7a-eabi < %s 2>&1 | FileCheck %s + +ldr r4, [s1, #12] +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected + +ldr r4, [d2, #12] +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected + +ldr r4, [q3, #12] +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected + +ldr r4, [cpsr, #12] +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected + +ldr r4, [r1, s12] +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected + +ldr r4, [r1, d12] +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected + +ldr r4, [r1, q12] +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected + +ldr r4, [r1, cpsr] +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected + +ldr r4, [r3], s12 +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected + +ldr r4, [r3], d12 +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected + +ldr r4, [r3], q12 +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected + +ldr r4, [r3], cpsr +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected + +add r3, r0, s1, lsl #2 +@ CHECK: :[[@LINE-1]]:{{.*}} shift must be of general-purpose register + +add r3, r0, d1, lsl #2 +@ CHECK: :[[@LINE-1]]:{{.*}} shift must be of general-purpose register + +add r3, r0, q1, lsl #2 +@ CHECK: :[[@LINE-1]]:{{.*}} shift must be of general-purpose register + +add r3, r0, cpsr, lsl #2 +@ CHECK: :[[@LINE-1]]:{{.*}} shift must be of general-purpose register + +add r3, r0, r1, lsl s6 +@ CHECK: :[[@LINE-1]]:{{.*}} expected immediate or general-purpose register in shift operand + +add r3, r0, r1, lsl d6 +@ CHECK: :[[@LINE-1]]:{{.*}} expected immediate or general-purpose register in shift operand + +add r3, r0, r1, lsl q6 +@ CHECK: :[[@LINE-1]]:{{.*}} expected immediate or general-purpose register in shift operand + +add r3, r0, r1, lsl cpsr +@ CHECK: :[[@LINE-1]]:{{.*}} expected immediate or general-purpose register in shift operand + +ldrd r2, r3, [s4] +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected + +ldrd r2, r3, [r4, d5] +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected + +ldrd r2, r3, [r4], q5 +@ CHECK: :[[@LINE-1]]:{{.*}} general-purpose register expected