Thumb assembly parsing and encoding for LDM instruction.
authorJim Grosbach <grosbach@apple.com>
Thu, 18 Aug 2011 21:50:53 +0000 (21:50 +0000)
committerJim Grosbach <grosbach@apple.com>
Thu, 18 Aug 2011 21:50:53 +0000 (21:50 +0000)
Fix base register type and canonicallize to the "ldm" spelling rather than
"ldmia." Add diagnostics for incorrect writeback token and out-of-range
registers.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@137986 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMInstrThumb.td
lib/Target/ARM/AsmParser/ARMAsmParser.cpp
lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
test/CodeGen/Thumb2/thumb2-ldm.ll
test/MC/ARM/basic-thumb-instructions.s
test/MC/ARM/thumb-diagnostics.s
test/MC/Disassembler/ARM/thumb-tests.txt

index 2b047279d21d9844445e2278ccb079e84322662e..199691f6c30555ddd509e3ebae681c208581adfb 100644 (file)
@@ -683,8 +683,8 @@ multiclass thumb_ldst_mult<string asm, InstrItinClass itin,
                            InstrItinClass itin_upd, bits<6> T1Enc,
                            bit L_bit, string baseOpc> {
   def IA :
-    T1I<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops),
-        itin, !strconcat(asm, "ia${p}\t$Rn, $regs"), []>,
+    T1I<(outs), (ins tGPR:$Rn, pred:$p, reglist:$regs, variable_ops),
+        itin, !strconcat(asm, "${p}\t$Rn, $regs"), []>,
        T1Encoding<T1Enc> {
     bits<3> Rn;
     bits<8> regs;
@@ -696,7 +696,7 @@ multiclass thumb_ldst_mult<string asm, InstrItinClass itin,
     InstTemplate<AddrModeNone, 0, IndexModeNone, Pseudo, GenericDomain, 
                  "$Rn = $wb", itin_upd>,
     PseudoInstExpansion<(!cast<Instruction>(!strconcat(baseOpc, "IA"))
-                       GPR:$Rn, pred:$p, reglist:$regs)> {
+                       tGPR:$Rn, pred:$p, reglist:$regs)> {
     let Size = 2;
     let OutOperandList = (outs GPR:$wb);
     let InOperandList = (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops);
@@ -720,6 +720,11 @@ defm tSTM : thumb_ldst_mult<"stm", IIC_iStore_m, IIC_iStore_mu,
 
 } // neverHasSideEffects
 
+def : InstAlias<"ldm${p} $Rn!, $regs",
+                (tLDMIA tGPR:$Rn, pred:$p, reglist:$regs)>,
+        Requires<[IsThumb, IsThumb1Only]>;
+
+
 let mayLoad = 1, Uses = [SP], Defs = [SP], hasExtraDefRegAllocReq = 1 in
 def tPOP : T1I<(outs), (ins pred:$p, reglist:$regs, variable_ops),
                IIC_iPop,
index 44c7a0a8d61cb7be4743a6dd2f033ff3bf48c4fe..697754551116e0ea3a41f65f1c409cef63583a2b 100644 (file)
@@ -2988,6 +2988,29 @@ validateInstruction(MCInst &Inst,
                    "bitfield width must be in range [1,32-lsb]");
     return false;
   }
+  case ARM::tLDMIA: {
+    // Thumb LDM instructions are writeback iff the base register is not
+    // in the register list.
+    unsigned Rn = Inst.getOperand(0).getReg();
+    bool doesWriteback = true;
+    for (unsigned i = 3; i < Inst.getNumOperands(); ++i) {
+      unsigned Reg = Inst.getOperand(i).getReg();
+      if (Reg == Rn)
+        doesWriteback = false;
+      // Anything other than a low register isn't legal here.
+      if (getARMRegisterNumbering(Reg) > 7)
+        return Error(Operands[4]->getStartLoc(),
+                     "registers must be in range r0-r7");
+    }
+    // If we should have writeback, then there should be a '!' token.
+    if (doesWriteback &&
+        (!static_cast<ARMOperand*>(Operands[3])->isToken() ||
+         static_cast<ARMOperand*>(Operands[3])->getToken() != "!"))
+      return Error(Operands[2]->getStartLoc(),
+                   "writeback operator '!' expected");
+
+    break;
+  }
   }
 
   return false;
index 961b0576b09a89143645a6105dfc8dad42c86cf2..1999ee7a6f55994baeddc151b4df3c59c72beb69 100644 (file)
@@ -155,9 +155,9 @@ void ARMInstPrinter::printInst(const MCInst *MI, raw_ostream &O) {
     }
 
     if (Opcode == ARM::tLDMIA)
-      O << "\tldmia";
+      O << "\tldm";
     else if (Opcode == ARM::tSTMIA)
-      O << "\tstmia";
+      O << "\tstm";
     else
       llvm_unreachable("Unknown opcode!");
 
index c5f7e84c89d47ece8e1b259eff2c809b67669ec8..4f2b7c18f9ce986aef2a162c536d519ba8f9f47a 100644 (file)
@@ -15,7 +15,7 @@ define i32 @t1() {
 define i32 @t2() {
 ; CHECK: t2:
 ; CHECK: push {r7, lr}
-; CHECK: ldmia
+; CHECK: ldm
 ; CHECK: pop {r7, pc}
         %tmp = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 2)            ; <i32> [#uses=1]
         %tmp3 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 3)           ; <i32> [#uses=1]
index e315a9fe50855e7440c80bc115d6d218a3d5d193..fd0b620a66ada136626183253c8c9361e66432f1 100644 (file)
@@ -162,3 +162,15 @@ _func:
         eors r4, r5
 
 @ CHECK: eors  r4, r5                  @ encoding: [0x6c,0x40]
+
+
+@------------------------------------------------------------------------------
+@ LDM
+@------------------------------------------------------------------------------
+        ldm r3, {r0, r1, r2, r3, r4, r5, r6, r7}
+        ldm r2!, {r1, r3, r4, r5, r7}
+        ldm r1, {r1}
+
+@ CHECK: ldm   r3, {r0, r1, r2, r3, r4, r5, r6, r7} @ encoding: [0xff,0xcb]
+@ CHECK: ldm   r2!, {r1, r3, r4, r5, r7} @ encoding: [0xba,0xca]
+@ CHECK: ldm   r1, {r1}                @ encoding: [0x02,0xc9]
index 99d85fedfafecebf7deb76694d83c65d6a364f1f..d067b2be6c627d87cad6cf926ccbe480d06667b6 100644 (file)
@@ -39,3 +39,13 @@ error: invalid operand for instruction
 error: invalid operand for instruction
         bkpt #-1
              ^
+
+@ Invalid writeback and register lists for LDM
+        ldm r2!, {r5, r8}
+        ldm r2, {r5, r7}
+@ CHECK-ERRORS: error: registers must be in range r0-r7
+@ CHECK-ERRORS:         ldm r2!, {r5, r8}
+@ CHECK-ERRORS:                  ^
+@ CHECK-ERRORS: error: writeback operator '!' expected
+@ CHECK-ERRORS:         ldm r2, {r5, r7}
+@ CHECK-ERRORS:             ^
index 3b578eca07a639ee95010be51d092b5f4f8794e7..b9490c760f0438ebd371f4ad23843073442f8656 100644 (file)
@@ -27,7 +27,7 @@
 # CHECK:       cmn.w   r0, #31
 0x10 0xf1 0x1f 0x0f
 
-# CHECK:       ldmia   r0!, {r1}
+# CHECK:       ldm     r0!, {r1}
 0x02 0xc8
 
 # CHECK:       ldr     r5, #432
 # CHECK:       lsleq   r1, r0, #28
 0x01 0x07
 
-# CHECK:       stmiane r0!, {r1, r2, r3}
+# CHECK:       stmne   r0!, {r1, r2, r3}
 0x0e 0xc0
 
 # IT block end
 # CHECK:       stmdb.w sp, {r0, r2, r3, r8, r11, lr}
 0x0d 0xe9 0x0d 0x49
 
-# CHECK:       stmia   r5!, {r0, r1, r2, r3, r4}
+# CHECK:       stm     r5!, {r0, r1, r2, r3, r4}
 0x1f 0xc5
 
-# CHECK:       ldmia   r5, {r0, r1, r2, r3, r4, r5}
+# CHECK:       ldm     r5, {r0, r1, r2, r3, r4, r5}
 0x3f 0xcd
 
-# CHECK:       ldmia   r5!, {r0, r1, r2, r3, r4}
+# CHECK:       ldm     r5!, {r0, r1, r2, r3, r4}
 0x1f 0xcd
 
 # CHECK:       addw    r0, pc, #1050