ARM: improve instruction validation for thumb mode

The ARM Architecture Reference Manual states the following:
  LDM{,IA,DB}:
    The SP cannot be in the list.
    The PC can be in the list.
    If the PC is in the list:
      • the LR must not be in the list
      • the instruction must be either outside any IT block, or the last
        instruction in an IT block.
  POP:
    The PC can be in the list.
    If the PC is in the list:
      • the LR must not be in the list
      • the instruction must be either outside any IT block, or the last
        instruction in an IT block.
  PUSH:
    The SP and PC can be in the list in ARM instructions, but not in Thumb
    instructions.
  STM:{,IA,DB}:
    The SP and PC can be in the list in ARM instructions, but not in Thumb
    instructions.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@224502 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Saleem Abdulrasool
2014-12-18 05:24:38 +00:00
parent 4d3a8d8a3a
commit 9c1911b105
4 changed files with 178 additions and 30 deletions

View File

@@ -164,7 +164,10 @@ class ARMAsmParser : public MCTargetAsmParser {
// according to count of instructions in block.
// ~0U if no active IT block.
} ITState;
bool inITBlock() { return ITState.CurPosition != ~0U;}
bool inITBlock() { return ITState.CurPosition != ~0U; }
bool lastInITBlock() {
return ITState.CurPosition == 4 - countTrailingZeros(ITState.Mask);
}
void forwardITPosition() {
if (!inITBlock()) return;
// Move to the next instruction in the IT block, if there is one. If not,
@@ -186,6 +189,11 @@ class ARMAsmParser : public MCTargetAsmParser {
return getParser().Error(L, Msg, Ranges);
}
bool validatetLDMRegList(MCInst Inst, const OperandVector &Operands,
unsigned ListNo, bool IsPop = false);
bool validatetSTMRegList(MCInst Inst, const OperandVector &Operands,
unsigned ListNo);
int tryParseRegister();
bool tryParseRegisterWithWriteBack(OperandVector &);
int tryParseShiftRegister(OperandVector &);
@@ -6011,6 +6019,50 @@ static bool instIsBreakpoint(const MCInst &Inst) {
}
bool ARMAsmParser::validatetLDMRegList(MCInst Inst,
const OperandVector &Operands,
unsigned ListNo, bool IsPop) {
const ARMOperand &Op = static_cast<const ARMOperand &>(*Operands[ListNo]);
bool HasWritebackToken = Op.isToken() && Op.getToken() == "!";
bool ListContainsSP = listContainsReg(Inst, ListNo, ARM::SP);
bool ListContainsLR = listContainsReg(Inst, ListNo, ARM::LR);
bool ListContainsPC = listContainsReg(Inst, ListNo, ARM::PC);
if (!IsPop && ListContainsSP)
return Error(Operands[ListNo + HasWritebackToken]->getStartLoc(),
"SP may not be in the register list");
else if (ListContainsPC && ListContainsLR)
return Error(Operands[ListNo + HasWritebackToken]->getStartLoc(),
"PC and LR may not be in the register list simultaneously");
else if (inITBlock() && !lastInITBlock() && ListContainsPC)
return Error(Operands[ListNo + HasWritebackToken]->getStartLoc(),
"instruction must be outside of IT block or the last "
"instruction in an IT block");
return false;
}
bool ARMAsmParser::validatetSTMRegList(MCInst Inst,
const OperandVector &Operands,
unsigned ListNo) {
const ARMOperand &Op = static_cast<const ARMOperand &>(*Operands[ListNo]);
bool HasWritebackToken = Op.isToken() && Op.getToken() == "!";
bool ListContainsSP = listContainsReg(Inst, ListNo, ARM::SP);
bool ListContainsPC = listContainsReg(Inst, ListNo, ARM::PC);
if (ListContainsSP && ListContainsPC)
return Error(Operands[ListNo + HasWritebackToken]->getStartLoc(),
"SP and PC may not be in the register list");
else if (ListContainsSP)
return Error(Operands[ListNo + HasWritebackToken]->getStartLoc(),
"SP may not be in the register list");
else if (ListContainsPC)
return Error(Operands[ListNo + HasWritebackToken]->getStartLoc(),
"PC may not be in the register list");
return false;
}
// FIXME: We would really like to be able to tablegen'erate this.
bool ARMAsmParser::validateInstruction(MCInst &Inst,
const OperandVector &Operands) {
@@ -6194,9 +6246,9 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
return Error(Operands[3]->getStartLoc(),
"writeback operator '!' not allowed when base register "
"in register list");
if (listContainsReg(Inst, 3 + HasWritebackToken, ARM::SP))
return Error(Operands[3 + HasWritebackToken]->getStartLoc(),
"SP not allowed in register list");
if (validatetLDMRegList(Inst, Operands, 3))
return true;
break;
}
case ARM::LDMIA_UPD:
@@ -6213,13 +6265,14 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
break;
case ARM::t2LDMIA:
case ARM::t2LDMDB:
case ARM::t2STMIA:
case ARM::t2STMDB: {
if (listContainsReg(Inst, 3, ARM::SP))
return Error(Operands.back()->getStartLoc(),
"SP not allowed in register list");
if (validatetLDMRegList(Inst, Operands, 3))
return true;
break;
case ARM::t2STMIA:
case ARM::t2STMDB:
if (validatetSTMRegList(Inst, Operands, 3))
return true;
break;
}
case ARM::t2LDMIA_UPD:
case ARM::t2LDMDB_UPD:
case ARM::t2STMIA_UPD:
@@ -6228,9 +6281,13 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
return Error(Operands.back()->getStartLoc(),
"writeback register not allowed in register list");
if (listContainsReg(Inst, 4, ARM::SP))
return Error(Operands.back()->getStartLoc(),
"SP not allowed in register list");
if (Opcode == ARM::t2LDMIA_UPD || Opcode == ARM::t2LDMDB_UPD) {
if (validatetLDMRegList(Inst, Operands, 4))
return true;
} else {
if (validatetSTMRegList(Inst, Operands, 4))
return true;
}
break;
}
case ARM::sysLDMIA_UPD:
@@ -6275,6 +6332,8 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
!isThumbTwo())
return Error(Operands[2]->getStartLoc(),
"registers must be in range r0-r7 or pc");
if (validatetLDMRegList(Inst, Operands, 2, /*IsPop=*/true))
return true;
break;
}
case ARM::tPUSH: {
@@ -6283,6 +6342,8 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
!isThumbTwo())
return Error(Operands[2]->getStartLoc(),
"registers must be in range r0-r7 or lr");
if (validatetSTMRegList(Inst, Operands, 2))
return true;
break;
}
case ARM::tSTMIA_UPD: {
@@ -6299,9 +6360,9 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst,
return Error(Operands[4]->getStartLoc(),
"writeback operator '!' not allowed when base register "
"in register list");
if (listContainsReg(Inst, 4, ARM::SP) && !inITBlock())
return Error(Operands.back()->getStartLoc(),
"SP not allowed in register list");
if (validatetSTMRegList(Inst, Operands, 4))
return true;
break;
}
case ARM::tADDrSP: {