Improve ARM assembly parsing diagnostics a bit.

Catch potential cascading errors on a malformed so_reg operand and bail after
the first error.

Add some tests for the diagnostics we do want.

llvm-svn: 135055
This commit is contained in:
Jim Grosbach 2011-07-13 18:49:30 +00:00
parent dffafded6c
commit bb24c595f7
2 changed files with 76 additions and 21 deletions

View File

@ -53,7 +53,7 @@ class ARMAsmParser : public TargetAsmParser {
int TryParseRegister(); int TryParseRegister();
virtual bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc); virtual bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc);
bool TryParseRegisterWithWriteBack(SmallVectorImpl<MCParsedAsmOperand*> &); bool TryParseRegisterWithWriteBack(SmallVectorImpl<MCParsedAsmOperand*> &);
bool TryParseShiftRegister(SmallVectorImpl<MCParsedAsmOperand*> &); int TryParseShiftRegister(SmallVectorImpl<MCParsedAsmOperand*> &);
bool ParseRegisterList(SmallVectorImpl<MCParsedAsmOperand*> &); bool ParseRegisterList(SmallVectorImpl<MCParsedAsmOperand*> &);
bool ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &, bool ParseMemory(SmallVectorImpl<MCParsedAsmOperand*> &,
ARMII::AddrMode AddrMode); ARMII::AddrMode AddrMode);
@ -1017,11 +1017,12 @@ int ARMAsmParser::TryParseRegister() {
return RegNum; return RegNum;
} }
/// Try to parse a register name. The token must be an Identifier when called, // Try to parse a shifter (e.g., "lsl <amt>"). On success, return 0.
/// and if it is a register name the token is eaten and the register number is // If a recoverable error occurs, return 1. If an irrecoverable error
/// returned. Otherwise return -1. // occurs, return -1. An irrecoverable error is one where tokens have been
/// // consumed in the process of trying to parse the shifter (i.e., when it is
bool ARMAsmParser::TryParseShiftRegister( // indeed a shifter operand, but malformed).
int ARMAsmParser::TryParseShiftRegister(
SmallVectorImpl<MCParsedAsmOperand*> &Operands) { SmallVectorImpl<MCParsedAsmOperand*> &Operands) {
SMLoc S = Parser.getTok().getLoc(); SMLoc S = Parser.getTok().getLoc();
const AsmToken &Tok = Parser.getTok(); const AsmToken &Tok = Parser.getTok();
@ -1038,7 +1039,7 @@ bool ARMAsmParser::TryParseShiftRegister(
.Default(ARM_AM::no_shift); .Default(ARM_AM::no_shift);
if (ShiftTy == ARM_AM::no_shift) if (ShiftTy == ARM_AM::no_shift)
return true; return 1;
Parser.Lex(); // Eat the operator. Parser.Lex(); // Eat the operator.
@ -1062,12 +1063,16 @@ bool ARMAsmParser::TryParseShiftRegister(
Parser.Lex(); // Eat hash. Parser.Lex(); // Eat hash.
SMLoc ImmLoc = Parser.getTok().getLoc(); SMLoc ImmLoc = Parser.getTok().getLoc();
const MCExpr *ShiftExpr = 0; const MCExpr *ShiftExpr = 0;
if (getParser().ParseExpression(ShiftExpr)) if (getParser().ParseExpression(ShiftExpr)) {
return Error(ImmLoc, "invalid immediate shift value"); Error(ImmLoc, "invalid immediate shift value");
return -1;
}
// The expression must be evaluatable as an immediate. // The expression must be evaluatable as an immediate.
const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ShiftExpr); const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ShiftExpr);
if (!CE) if (!CE) {
return Error(ImmLoc, "invalid immediate shift value"); Error(ImmLoc, "invalid immediate shift value");
return -1;
}
// Range check the immediate. // Range check the immediate.
// lsl, ror: 0 <= imm <= 31 // lsl, ror: 0 <= imm <= 31
// lsr, asr: 0 <= imm <= 32 // lsr, asr: 0 <= imm <= 32
@ -1075,24 +1080,28 @@ bool ARMAsmParser::TryParseShiftRegister(
if (Imm < 0 || if (Imm < 0 ||
((ShiftTy == ARM_AM::lsl || ShiftTy == ARM_AM::ror) && Imm > 31) || ((ShiftTy == ARM_AM::lsl || ShiftTy == ARM_AM::ror) && Imm > 31) ||
((ShiftTy == ARM_AM::lsr || ShiftTy == ARM_AM::asr) && Imm > 32)) { ((ShiftTy == ARM_AM::lsr || ShiftTy == ARM_AM::asr) && Imm > 32)) {
return Error(ImmLoc, "immediate shift value out of range"); Error(ImmLoc, "immediate shift value out of range");
return -1;
} }
} else if (Parser.getTok().is(AsmToken::Identifier)) { } else if (Parser.getTok().is(AsmToken::Identifier)) {
ShiftReg = TryParseRegister(); ShiftReg = TryParseRegister();
SMLoc L = Parser.getTok().getLoc(); SMLoc L = Parser.getTok().getLoc();
if (ShiftReg == -1) if (ShiftReg == -1) {
return Error (L, "expected immediate or register in shift operand"); Error (L, "expected immediate or register in shift operand");
} else return -1;
return Error (Parser.getTok().getLoc(), }
} else {
Error (Parser.getTok().getLoc(),
"expected immediate or register in shift operand"); "expected immediate or register in shift operand");
return -1;
}
} }
Operands.push_back(ARMOperand::CreateShiftedRegister(ShiftTy, SrcReg, Operands.push_back(ARMOperand::CreateShiftedRegister(ShiftTy, SrcReg,
ShiftReg, Imm, ShiftReg, Imm,
S, Parser.getTok().getLoc())); S, Parser.getTok().getLoc()));
return false; return 0;
} }
@ -1737,15 +1746,18 @@ bool ARMAsmParser::ParseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
default: default:
Error(Parser.getTok().getLoc(), "unexpected token in operand"); Error(Parser.getTok().getLoc(), "unexpected token in operand");
return true; return true;
case AsmToken::Identifier: case AsmToken::Identifier: {
if (!TryParseRegisterWithWriteBack(Operands)) if (!TryParseRegisterWithWriteBack(Operands))
return false; return false;
if (!TryParseShiftRegister(Operands)) int Res = TryParseShiftRegister(Operands);
if (Res == 0) // success
return false; return false;
else if (Res == -1) // irrecoverable error
return true;
// Fall though for the Identifier case that is not a register or a // Fall though for the Identifier case that is not a register or a
// special name. // special name.
}
case AsmToken::Integer: // things like 1f and 2b as a branch targets case AsmToken::Integer: // things like 1f and 2b as a branch targets
case AsmToken::Dot: { // . as a branch target case AsmToken::Dot: { // . as a branch target
// This was not a register so parse other operands that start with an // This was not a register so parse other operands that start with an

View File

@ -0,0 +1,43 @@
@ RUN: not llvm-mc -triple=armv7-apple-darwin < %s 2> %t
@ RUN: FileCheck --check-prefix=CHECK-ERRORS < %t %s
@ Check for various assembly diagnostic messages on invalid input.
@ Out of range shift immediate values.
adc r1, r2, r3, lsl #invalid
adc r4, r5, r6, lsl #-1
adc r4, r5, r6, lsl #32
adc r4, r5, r6, lsr #-1
adc r4, r5, r6, lsr #33
adc r4, r5, r6, asr #-1
adc r4, r5, r6, asr #33
adc r4, r5, r6, ror #-1
adc r4, r5, r6, ror #32
@ CHECK-ERRORS: error: invalid immediate shift value
@ CHECK-ERRORS: adc r1, r2, r3, lsl #invalid
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: immediate shift value out of range
@ CHECK-ERRORS: adc r4, r5, r6, lsl #-1
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: immediate shift value out of range
@ CHECK-ERRORS: adc r4, r5, r6, lsl #32
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: immediate shift value out of range
@ CHECK-ERRORS: adc r4, r5, r6, lsr #-1
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: immediate shift value out of range
@ CHECK-ERRORS: adc r4, r5, r6, lsr #33
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: immediate shift value out of range
@ CHECK-ERRORS: adc r4, r5, r6, asr #-1
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: immediate shift value out of range
@ CHECK-ERRORS: adc r4, r5, r6, asr #33
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: immediate shift value out of range
@ CHECK-ERRORS: adc r4, r5, r6, ror #-1
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: immediate shift value out of range
@ CHECK-ERRORS: adc r4, r5, r6, ror #32
@ CHECK-ERRORS: ^