From 90103ccc0577bbf8991d7b4f4e4e7ea2b12141d7 Mon Sep 17 00:00:00 2001 From: Jim Grosbach Date: Thu, 18 Aug 2011 21:50:53 +0000 Subject: [PATCH] Thumb assembly parsing and encoding for LDM instruction. Fix base register type and canonicallize to the "ldm" spelling rather than "ldmia." Add diagnostics for incorrect writeback token and out-of-range registers. llvm-svn: 137986 --- llvm/lib/Target/ARM/ARMInstrThumb.td | 11 ++++++--- .../lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 23 +++++++++++++++++++ .../Target/ARM/InstPrinter/ARMInstPrinter.cpp | 4 ++-- llvm/test/CodeGen/Thumb2/thumb2-ldm.ll | 2 +- llvm/test/MC/ARM/basic-thumb-instructions.s | 12 ++++++++++ llvm/test/MC/ARM/thumb-diagnostics.s | 10 ++++++++ llvm/test/MC/Disassembler/ARM/thumb-tests.txt | 10 ++++---- 7 files changed, 61 insertions(+), 11 deletions(-) diff --git a/llvm/lib/Target/ARM/ARMInstrThumb.td b/llvm/lib/Target/ARM/ARMInstrThumb.td index 2b047279d21d..199691f6c305 100644 --- a/llvm/lib/Target/ARM/ARMInstrThumb.td +++ b/llvm/lib/Target/ARM/ARMInstrThumb.td @@ -683,8 +683,8 @@ multiclass thumb_ldst_mult 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 { bits<3> Rn; bits<8> regs; @@ -696,7 +696,7 @@ multiclass thumb_ldst_mult, PseudoInstExpansion<(!cast(!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, diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 44c7a0a8d61c..697754551116 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -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(Operands[3])->isToken() || + static_cast(Operands[3])->getToken() != "!")) + return Error(Operands[2]->getStartLoc(), + "writeback operator '!' expected"); + + break; + } } return false; diff --git a/llvm/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp b/llvm/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp index 961b0576b09a..1999ee7a6f55 100644 --- a/llvm/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp +++ b/llvm/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp @@ -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!"); diff --git a/llvm/test/CodeGen/Thumb2/thumb2-ldm.ll b/llvm/test/CodeGen/Thumb2/thumb2-ldm.ll index c5f7e84c89d4..4f2b7c18f9ce 100644 --- a/llvm/test/CodeGen/Thumb2/thumb2-ldm.ll +++ b/llvm/test/CodeGen/Thumb2/thumb2-ldm.ll @@ -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) ; [#uses=1] %tmp3 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 3) ; [#uses=1] diff --git a/llvm/test/MC/ARM/basic-thumb-instructions.s b/llvm/test/MC/ARM/basic-thumb-instructions.s index e315a9fe5085..fd0b620a66ad 100644 --- a/llvm/test/MC/ARM/basic-thumb-instructions.s +++ b/llvm/test/MC/ARM/basic-thumb-instructions.s @@ -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] diff --git a/llvm/test/MC/ARM/thumb-diagnostics.s b/llvm/test/MC/ARM/thumb-diagnostics.s index 99d85fedfafe..d067b2be6c62 100644 --- a/llvm/test/MC/ARM/thumb-diagnostics.s +++ b/llvm/test/MC/ARM/thumb-diagnostics.s @@ -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: ^ diff --git a/llvm/test/MC/Disassembler/ARM/thumb-tests.txt b/llvm/test/MC/Disassembler/ARM/thumb-tests.txt index 3b578eca07a6..b9490c760f04 100644 --- a/llvm/test/MC/Disassembler/ARM/thumb-tests.txt +++ b/llvm/test/MC/Disassembler/ARM/thumb-tests.txt @@ -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 @@ -112,7 +112,7 @@ # CHECK: lsleq r1, r0, #28 0x01 0x07 -# CHECK: stmiane r0!, {r1, r2, r3} +# CHECK: stmne r0!, {r1, r2, r3} 0x0e 0xc0 # IT block end @@ -146,13 +146,13 @@ # 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