From 255722beb8898239d6687c21fa263a9e926a3188 Mon Sep 17 00:00:00 2001 From: Tilmann Scheller Date: Mon, 30 Sep 2013 16:11:48 +0000 Subject: [PATCH] [ARM] Assembler: ARM LDRD with writeback requires the base register to be different from the destination registers. See ARM ARM A8.8.72. Violating this constraint results in unpredictable behavior. llvm-svn: 191678 --- .../lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 23 +++++++++++++++---- llvm/test/MC/ARM/arm-ldrd.s | 6 +++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 6d6255f2cc2c..d360a24114e5 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -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: diff --git a/llvm/test/MC/ARM/arm-ldrd.s b/llvm/test/MC/ARM/arm-ldrd.s index d62193aeba80..d4c608c760f1 100644 --- a/llvm/test/MC/ARM/arm-ldrd.s +++ b/llvm/test/MC/ARM/arm-ldrd.s @@ -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]!