[ARM] Assembler: ARM LDRD with writeback requires the base register to be different...
authorTilmann Scheller <tilmann.scheller@googlemail.com>
Mon, 30 Sep 2013 16:11:48 +0000 (16:11 +0000)
committerTilmann Scheller <tilmann.scheller@googlemail.com>
Mon, 30 Sep 2013 16:11:48 +0000 (16:11 +0000)
See ARM ARM A8.8.72.

Violating this constraint results in unpredictable behavior.

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

lib/Target/ARM/AsmParser/ARMAsmParser.cpp
test/MC/ARM/arm-ldrd.s

index 6d6255f2cc2c891cc361afaffc594aaf5d34ebdf..d360a24114e5a02bd5126675e7b367120bb31988 100644 (file)
@@ -5343,25 +5343,40 @@ validateInstruction(MCInst &Inst,
              Inst.getOpcode() != ARM::t2Bcc)
     return Error(Loc, "predicated instructions must be in IT block");
 
-  switch (Inst.getOpcode()) {
+  const unsigned Opcode = Inst.getOpcode();
+  switch (Opcode) {
   case ARM::LDRD:
   case ARM::LDRD_PRE:
   case ARM::LDRD_POST: {
-    unsigned RtReg = Inst.getOperand(0).getReg();
+    const unsigned RtReg = Inst.getOperand(0).getReg();
+
     // Rt can't be R14.
     if (RtReg == ARM::LR)
       return Error(Operands[3]->getStartLoc(),
                    "Rt can't be R14");
-    unsigned Rt = MRI->getEncodingValue(RtReg);
+
+    const unsigned Rt = MRI->getEncodingValue(RtReg);
     // Rt must be even-numbered.
     if ((Rt & 1) == 1)
       return Error(Operands[3]->getStartLoc(),
                    "Rt must be even-numbered");
+
     // Rt2 must be Rt + 1.
-    unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
+    const unsigned Rt2 = MRI->getEncodingValue(Inst.getOperand(1).getReg());
     if (Rt2 != Rt + 1)
       return Error(Operands[3]->getStartLoc(),
                    "destination operands must be sequential");
+
+    if (Opcode == ARM::LDRD_PRE || Opcode == ARM::LDRD_POST) {
+      const unsigned Rn = MRI->getEncodingValue(Inst.getOperand(3).getReg());
+      // For addressing modes with writeback, the base register needs to be
+      // different from the destination registers.
+      if (Rn == Rt || Rn == Rt2)
+        return Error(Operands[3]->getStartLoc(),
+                     "base register needs to be different from destination "
+                     "registers");
+    }
+
     return false;
   }
   case ARM::t2LDRDi8:
index d62193aeba8062938ac4e6ade553cfb4a175e012..d4c608c760f1ceee0349ef18fd144c788e67ed3e 100644 (file)
@@ -3,6 +3,7 @@
 // RUN: grep "error: Rt must be even-numbered" %t | count 7
 // RUN: grep "error: Rt can't be R14" %t | count 7
 // RUN: grep "error: destination operands must be sequential" %t | count 7
+// RUN: grep "error: base register needs to be different from destination registers" %t | count 4
 // rdar://14479793
 
 ldrd r1, r2, [pc, #0]
@@ -26,3 +27,8 @@ ldrd r0, r3, [r4, r5]
 ldrd r1, r2, [r3], r4
 ldrd lr, pc, [r3], r4
 ldrd r0, r3, [r4], r5
+
+ldrd r0, r1, [r0], #4
+ldrd r0, r1, [r1], #4
+ldrd r0, r1, [r0, #4]!
+ldrd r0, r1, [r1, #4]!