]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - opencl/llvm.git/commitdiff
ARM: improve instruction validation for thumb mode
authorSaleem Abdulrasool <compnerd@compnerd.org>
Thu, 18 Dec 2014 05:24:38 +0000 (05:24 +0000)
committerSaleem Abdulrasool <compnerd@compnerd.org>
Thu, 18 Dec 2014 05:24:38 +0000 (05:24 +0000)
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

lib/Target/ARM/AsmParser/ARMAsmParser.cpp
test/MC/ARM/thumb-diagnostics.s
test/MC/ARM/thumb-load-store-multiple.s [new file with mode: 0644]
test/MC/ARM/v8_IT_manual.s

index e2f7dfb17f96116706642032c30afa315a22ab22..e9860764962b3ce9f31f0f3737e05b449d18f28f 100644 (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:
+    if (validatetLDMRegList(Inst, Operands, 3))
+      return true;
+    break;
   case ARM::t2STMIA:
-  case ARM::t2STMDB: {
-    if (listContainsReg(Inst, 3, ARM::SP))
-      return Error(Operands.back()->getStartLoc(),
-                   "SP not allowed in register list");
+  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: {
index a2e494f08500811e1a81b9bdad826c35211a1b62..bd26d06865ca12a4c4e486d2092d573cdd9317ed 100644 (file)
@@ -83,25 +83,25 @@ error: invalid operand for instruction
 @ CHECK-ERRORS-V8: error: writeback register not allowed in register list
 @ CHECK-ERRORS-V8:         ldmdb r2!, {r2, r3, r4}
 @ CHECK-ERRORS-V8:                 ^
-@ CHECK-ERRORS-V7M: error: SP not allowed in register list
+@ CHECK-ERRORS-V7M: error: SP may not be in the register list
 @ CHECK-ERRORS-V7M:         ldm r0, {r2, sp}
 @ CHECK-ERRORS-V7M:                 ^
-@ CHECK-ERRORS-V7M: error: SP not allowed in register list
+@ CHECK-ERRORS-V7M: error: SP may not be in the register list
 @ CHECK-ERRORS-V7M:         ldmia r0, {r2-r3, sp}
 @ CHECK-ERRORS-V7M:                   ^
-@ CHECK-ERRORS-V7M: error: SP not allowed in register list
+@ CHECK-ERRORS-V7M: error: SP may not be in the register list
 @ CHECK-ERRORS-V7M:         ldmia r0!, {r2-r3, sp}
 @ CHECK-ERRORS-V7M:                    ^
-@ CHECK-ERRORS-V7M: error: SP not allowed in register list
+@ CHECK-ERRORS-V7M: error: SP may not be in the register list
 @ CHECK-ERRORS-V7M:         ldmfd r2, {r1, r3-r6, sp}
 @ CHECK-ERRORS-V7M:                   ^
-@ CHECK-ERRORS-V7M: error: SP not allowed in register list
+@ CHECK-ERRORS-V7M: error: SP may not be in the register list
 @ CHECK-ERRORS-V7M:         ldmfd r2!, {r1, r3-r6, sp}
 @ CHECK-ERRORS-V7M:                    ^
-@ CHECK-ERRORS-V7M: error: SP not allowed in register list
+@ CHECK-ERRORS-V7M: error: SP may not be in the register list
 @ CHECK-ERRORS-V7M:         ldmdb r1, {r2, r3, sp}
 @ CHECK-ERRORS-V7M:                   ^
-@ CHECK-ERRORS-V7M: error: SP not allowed in register list
+@ CHECK-ERRORS-V7M: error: SP may not be in the register list
 @ CHECK-ERRORS-V7M:         ldmdb r1!, {r2, r3, sp}
 @ CHECK-ERRORS-V7M:                    ^
 
@@ -137,16 +137,16 @@ error: invalid operand for instruction
 @ 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 may not be in the 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 may not be in the 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 may not be in the 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 may not be in the register list
 @ CHECK-ERRORS-V7M:         stmdb r1!, {r2, r3, sp}
 @ CHECK-ERRORS-V7M:                    ^
 
diff --git a/test/MC/ARM/thumb-load-store-multiple.s b/test/MC/ARM/thumb-load-store-multiple.s
new file mode 100644 (file)
index 0000000..e00fc66
--- /dev/null
@@ -0,0 +1,86 @@
+@ RUN: not llvm-mc -triple thumbv7-eabi -filetype asm -o /dev/null %s 2>&1 \
+@ RUN:     | FileCheck %s
+
+       .syntax unified
+       .thumb
+
+       .global ldm
+       .type ldm,%function
+ldb:
+       ldm r0!, {r1, sp}
+@ CHECK: error: SP may not be in the register list
+@ CHECK: ldm r0!, {r1, sp}
+@ CHECK:          ^
+       ldm r0!, {lr, pc}
+@ CHECK: error: PC and LR may not be in the register list simultaneously
+@ CHECK: ldm r0!, {lr, pc}
+@ CHECK:          ^
+       itt eq
+       ldmeq r0!, {r1, pc}
+       ldmeq r0!, {r2, lr}
+@ CHECK: error: instruction must be outside of IT block or the last instruction in an IT block
+@ CHECK: ldmeq r0!, {r1, pc}
+@ CHECK:            ^
+
+       .global ldmdb
+       .type ldmdb,%function
+ldmdb:
+       ldmdb r0!, {r1, sp}
+@ CHECK: error: SP may not be in the register list
+       ldm r0!, {lr, pc}
+@ error: PC and LR may not be in the register list simultaneously
+       itt eq
+       ldmeq r0!, {r1, pc}
+       ldmeq r0!, {r2, lr}
+@ CHECK: error: instruction must be outside of IT block or the last instruction in an IT block
+@ CHECK: ldmeq r0!, {r1, pc}
+@ CHECK:            ^
+
+       .global stm
+       .type stm,%function
+stm:
+       stm r0!, {r1, sp}
+@ CHECK: error: SP may not be in the register list
+       stm r0!, {r2, pc}
+@ CHECK: error: PC may not be in the register list
+       stm r0!, {sp, pc}
+@ CHECK: error: SP and PC may not be in the register list
+
+       .global stmdb
+       .type stmdb,%function
+stmdb:
+       stmdb r0!, {r1, sp}
+@ CHECK: error: SP may not be in the register list
+       stmdb r0!, {r2, pc}
+@ CHECK: error: PC may not be in the register list
+       stmdb r0!, {sp, pc}
+@ CHECK: error: SP and PC may not be in the register list
+
+       .global push
+       .type push,%function
+push:
+       push {sp}
+@ CHECK: error: SP may not be in the register list
+       push {pc}
+@ CHECK: error: PC may not be in the register list
+       push {sp,pc}
+@ CHECK: error: SP and PC may not be in the register list
+
+       .global pop
+       .type pop,%function
+pop:
+       pop {sp}
+@ CHECK-NOT: error: SP may not be in the register list
+       pop {sp, pc}
+@ CHECK-NOT: error: SP may not be in the register list
+       pop {lr, pc}
+@ CHECK: error: PC and LR may not be in the register list simultaneously
+@ CHECK: pop {lr, pc}
+@ CHECK:     ^
+       itt eq
+       popeq {r1, pc}
+       popeq {r2, lr}
+@ CHECK: error: instruction must be outside of IT block or the last instruction in an IT block
+@ CHECK: popeq {r1, pc}
+@ CHECK:     ^
+
index 4b63aa82dd681f6463051a1cd4151043d2e55f43..160e98ce8b4f1083f6a28c3fc6608590e2d333e0 100644 (file)
@@ -554,11 +554,11 @@ pushge {r1, r3, r7}
 @ PUSH, encoding T2 (32-bit)
 @ CHECK: [[@LINE+2]]:1: warning: deprecated instruction in IT block
 it ge
-pushge {r1, r13, r7}
+pushge {r1, r3, r7}
 @ PUSH, encoding T3 (32-bit)
 @ CHECK: [[@LINE+2]]:1: warning: deprecated instruction in IT block
 it ge
-pushge {r13}
+pushge {r3}
 
 @ REV, encoding T1
 @ CHECK: [[@LINE+2]]:1: warning: deprecated instruction in IT block
@@ -614,9 +614,10 @@ stmge r1!, {r2, r3}
 @ CHECK: [[@LINE+2]]:1: warning: deprecated instruction in IT block
 it ge
 stmge r1, {r2, r3}
+@ STM, encoding T3 (32-bit)
 @ CHECK: [[@LINE+2]]:1: warning: deprecated instruction in IT block
 it ge
-stmge r1!, {r2, r13}
+stmge r1!, {r2, r3}
 
 @ LDM, encoding T1
 @ CHECK: [[@LINE+2]]:1: warning: deprecated instruction in IT block