Index: llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -5772,7 +5772,7 @@ return false; } -// Check if the specified regisgter is in the register list of the inst, +// Check if the specified register is in the register list of the inst, // starting at the indicated operand number. static bool listContainsReg(MCInst &Inst, unsigned OpNo, unsigned Reg) { for (unsigned i = OpNo; i < Inst.getNumOperands(); ++i) { @@ -5783,6 +5783,26 @@ return false; } +// Check if there are any special registers in the register list of the inst, +// starting at the indicated operand number. +static bool listContainsSplReg(MCInst &Inst, unsigned OpNo, bool &SP, bool &PC, + bool &LR) { + SP = PC = LR = false; + for (unsigned i = OpNo; i < Inst.getNumOperands(); ++i) { + unsigned OpReg = Inst.getOperand(i).getReg(); + if (OpReg == ARM::SP) + SP = true; + else if (OpReg == ARM::PC) + PC = true; + else if (OpReg == ARM::LR) + LR = true; + } + if (SP || PC || LR) + return true; + + return false; +} + // Return true if instruction has the interesting property of being // allowed in IT blocks, but not being predicable. static bool instIsBreakpoint(const MCInst &Inst) { @@ -5976,9 +5996,15 @@ return Error(Operands[3]->getStartLoc(), "writeback operator '!' not allowed when base register " "in register list"); - if (listContainsReg(Inst, 3 + HasWritebackToken, ARM::SP)) + bool SP, PC, LR; + if (listContainsSplReg(Inst, 3 + HasWritebackToken, SP, PC, LR) && SP) return Error(Operands[3 + HasWritebackToken]->getStartLoc(), "SP not allowed in register list"); + if (PC && LR && !inITBlock()) + return Error( + Operands[3 + HasWritebackToken]->getStartLoc(), + "LR not allowed in the list, when PC is in the register list"); + break; } case ARM::LDMIA_UPD: @@ -5997,9 +6023,20 @@ 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"); + bool SP, PC, LR; + if (listContainsSplReg(Inst, 3, SP, PC, LR)) { + if (((Opcode == ARM::t2STMIA) || (Opcode == ARM::t2STMDB)) && (SP || PC)) + return Error(Operands.back()->getStartLoc(), + "SP, PC not allowed in register list"); + else if (SP) + return Error(Operands.back()->getStartLoc(), + "SP not allowed in register list"); + if (((Opcode == ARM::t2LDMIA) || (Opcode == ARM::t2LDMDB)) && + (PC && LR) && !inITBlock()) + return Error( + Operands.back()->getStartLoc(), + "LR not allowed in the list, when PC is in the register list"); + } break; } case ARM::t2LDMIA_UPD: @@ -6006,13 +6043,24 @@ case ARM::t2LDMDB_UPD: case ARM::t2STMIA_UPD: case ARM::t2STMDB_UPD: { + bool SP, PC, LR; if (listContainsReg(Inst, 3, Inst.getOperand(0).getReg())) 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 (listContainsSplReg(Inst, 3, SP, PC, LR)) { + if (((Opcode == ARM::t2STMIA_UPD) || (Opcode == ARM::t2STMDB_UPD)) && + (SP || PC)) + return Error(Operands.back()->getStartLoc(), + "SP, PC not allowed in register list"); + else if (SP) + return Error(Operands.back()->getStartLoc(), + "SP not allowed in register list"); + if (((Opcode == ARM::t2LDMIA_UPD) || (Opcode == ARM::t2LDMDB_UPD)) && + (PC && LR) && !inITBlock()) + return Error( + Operands.back()->getStartLoc(), + "LR not allowed in the list, when PC is in the register list"); + } break; } case ARM::sysLDMIA_UPD: @@ -6057,6 +6105,14 @@ !isThumbTwo()) return Error(Operands[2]->getStartLoc(), "registers must be in range r0-r7 or pc"); + bool SP, PC, LR; + if (listContainsSplReg(Inst, 2, SP, PC, LR) && (PC && LR)) + return Error( + Operands[2]->getStartLoc(), + "LR not allowed in the list, when PC is in the register list"); + if (SP) + return Error(Operands[2]->getStartLoc(), + "SP not allowed in register list"); break; } case ARM::tPUSH: { @@ -6065,6 +6121,10 @@ !isThumbTwo()) return Error(Operands[2]->getStartLoc(), "registers must be in range r0-r7 or lr"); + bool SP, PC, LR; + if (listContainsSplReg(Inst, 2, SP, PC, LR) && (SP || PC) && !inITBlock()) + return Error(Operands[2]->getStartLoc(), + "SP, PC not allowed in register list"); break; } case ARM::tSTMIA_UPD: { @@ -6081,9 +6141,12 @@ 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"); + bool SP, PC, LR; + if (listContainsSplReg(Inst, 4, SP, PC, LR) && !inITBlock()) { + if (SP || PC) + return Error(Operands.back()->getStartLoc(), + "SP, PC not allowed in register list"); + } break; } case ARM::tADDrSP: { Index: llvm/test/MC/ARM/thumb-diagnostics.s =================================================================== --- llvm/test/MC/ARM/thumb-diagnostics.s +++ llvm/test/MC/ARM/thumb-diagnostics.s @@ -68,6 +68,7 @@ ldmfd r2!, {r1, r3-r6, sp} ldmdb r1, {r2, r3, sp} ldmdb r1!, {r2, r3, sp} + ldm r2, {r5, lr, pc} @ CHECK-ERRORS: error: registers must be in range r0-r7 @ CHECK-ERRORS: ldm r2!, {r5, r8} @ CHECK-ERRORS: ^ @@ -104,16 +105,31 @@ @ CHECK-ERRORS-V7M: error: SP not allowed in register list @ CHECK-ERRORS-V7M: ldmdb r1!, {r2, r3, sp} @ CHECK-ERRORS-V7M: ^ +@ CHECK-ERRORS-V7M: error: LR not allowed in the list, when PC is in the register list +@ CHECK-ERRORS-V7M: ldm r2, {r5, lr, pc} +@ CHECK-ERRORS-V7M: ^ @ Invalid writeback and register lists for PUSH/POP pop {r1, r2, r10} + pop {r1, r2, lr, pc} push {r8, r9} + push {r8, r9, sp} + push {r8, r9, pc} @ CHECK-ERRORS: error: registers must be in range r0-r7 or pc @ CHECK-ERRORS: pop {r1, r2, r10} @ CHECK-ERRORS: ^ +@ CHECK-ERRORS-V7M: error: LR not allowed in the list, when PC is in the register list +@ CHECK-ERRORS-V7M: pop {r1, r2, lr, pc} +@ CHECK-ERRORS-V7M: ^ @ CHECK-ERRORS: error: registers must be in range r0-r7 or lr @ CHECK-ERRORS: push {r8, r9} @ CHECK-ERRORS: ^ +@ CHECK-ERRORS-V7M: error: SP, PC not allowed in register list +@ CHECK-ERRORS-V7M: push {r8, r9, sp} +@ CHECK-ERRORS-V7M: ^ +@ CHECK-ERRORS-V7M: error: SP, PC not allowed in register list +@ CHECK-ERRORS-V7M: push {r8, r9, pc} +@ CHECK-ERRORS-V7M: ^ @ Invalid writeback and register lists for STM @@ -125,6 +141,8 @@ stmia r4!, {r0-r3, sp} stmdb r1, {r2, r3, sp} stmdb r1!, {r2, r3, sp} + stmia r4, {r2, sp, pc} + stmdb r1!, {r2, r3, pc} @ CHECK-ERRORS: error: instruction requires: thumb2 @ CHECK-ERRORS: stm r1, {r2, r6} @ CHECK-ERRORS: ^ @@ -137,18 +155,24 @@ @ CHECK-ERRORS-V8: error: writeback register not allowed in register list @ CHECK-ERRORS-V8: stmdb r2!, {r0, r2} @ CHECK-ERRORS-V8: ^ -@ CHECK-ERRORS-V7M: error: SP not allowed in register list +@ CHECK-ERRORS-V7M: error: SP, PC not allowed in register list @ CHECK-ERRORS-V7M: stm r1!, {r2, sp} @ CHECK-ERRORS-V7M: ^ -@ CHECK-ERRORS-V7M: error: SP not allowed in register list +@ CHECK-ERRORS-V7M: error: SP, PC not allowed in register list @ CHECK-ERRORS-V7M: stmia r4!, {r0-r3, sp} @ CHECK-ERRORS-V7M: ^ -@ CHECK-ERRORS-V7M: error: SP not allowed in register list +@ CHECK-ERRORS-V7M: error: SP, PC not allowed in register list @ CHECK-ERRORS-V7M: stmdb r1, {r2, r3, sp} @ CHECK-ERRORS-V7M: ^ -@ CHECK-ERRORS-V7M: error: SP not allowed in register list +@ CHECK-ERRORS-V7M: error: SP, PC not allowed in register list @ CHECK-ERRORS-V7M: stmdb r1!, {r2, r3, sp} @ CHECK-ERRORS-V7M: ^ +@ CHECK-ERRORS-V7M: error: SP, PC not allowed in register list +@ CHECK-ERRORS-V7M: stmia r4, {r2, sp, pc} +@ CHECK-ERRORS-V7M: ^ +@ CHECK-ERRORS-V7M: error: SP, PC not allowed in register list +@ CHECK-ERRORS-V7M: stmdb r1!, {r2, r3, pc} +@ CHECK-ERRORS-V7M: ^ @ Out of range immediates for LSL instruction. lsls r4, r5, #-1