From 76ecc3d35b4d16afb016bb14e29e12802b968716 Mon Sep 17 00:00:00 2001 From: Jim Grosbach Date: Wed, 7 Sep 2011 18:05:34 +0000 Subject: [PATCH] Thumb2 parsing and encoding for LDMIA. Choose 32-bit vs. 16-bit encoding when there's no .w suffix in post-processing as match classes are insufficient to handle the context-sensitiveness of the writeback operand's legality for the 16-bit encodings. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@139242 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 54 +++++++++++++++++++++-- test/MC/ARM/basic-thumb2-instructions.s | 38 ++++++++++++++++ 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 1aa5563e5c7..b00bb0cdae5 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -3339,6 +3339,17 @@ static bool checkLowRegisterList(MCInst Inst, unsigned OpNo, unsigned Reg, return false; } +// Check if the specified regisgter is in the register list of the inst, +// starting at the indicated operand number. +static bool listContainsReg(MCInst &Inst, unsigned OpNo, unsigned Reg) { + for (unsigned i = OpNo; i < Inst.getNumOperands(); ++i) { + unsigned OpReg = Inst.getOperand(i).getReg(); + if (OpReg == Reg) + return true; + } + return false; +} + // FIXME: We would really prefer to have MCInstrInfo (the wrapper around // the ARMInsts array) instead. Getting that here requires awkward // API changes, though. Better way? @@ -3430,6 +3441,11 @@ validateInstruction(MCInst &Inst, return false; } case ARM::tLDMIA: { + // If we're parsing Thumb2, the .w variant is available and handles + // most cases that are normally illegal for a Thumb1 LDM + // instruction. We'll make the transformation in processInstruction() + // if necessary. + // // Thumb LDM instructions are writeback iff the base register is not // in the register list. unsigned Rn = Inst.getOperand(0).getReg(); @@ -3437,14 +3453,15 @@ validateInstruction(MCInst &Inst, (static_cast(Operands[3])->isToken() && static_cast(Operands[3])->getToken() == "!"); bool listContainsBase; - if (checkLowRegisterList(Inst, 3, Rn, 0, listContainsBase)) + if (checkLowRegisterList(Inst, 3, Rn, 0, listContainsBase) && !isThumbTwo()) return Error(Operands[3 + hasWritebackToken]->getStartLoc(), "registers must be in range r0-r7"); // If we should have writeback, then there should be a '!' token. - if (!listContainsBase && !hasWritebackToken) + if (!listContainsBase && !hasWritebackToken && !isThumbTwo()) return Error(Operands[2]->getStartLoc(), "writeback operator '!' expected"); - // Likewise, if we should not have writeback, there must not be a '!' + // If we should not have writeback, there must not be a '!'. This is + // true even for the 32-bit wide encodings. if (listContainsBase && hasWritebackToken) return Error(Operands[3]->getStartLoc(), "writeback operator '!' not allowed when base register " @@ -3452,6 +3469,13 @@ validateInstruction(MCInst &Inst, break; } + case ARM::t2LDMIA_UPD: { + if (listContainsReg(Inst, 3, Inst.getOperand(0).getReg())) + return Error(Operands[4]->getStartLoc(), + "writeback operator '!' not allowed when base register " + "in register list"); + break; + } case ARM::tPOP: { bool listContainsBase; if (checkLowRegisterList(Inst, 3, 0, ARM::PC, listContainsBase)) @@ -3533,6 +3557,30 @@ processInstruction(MCInst &Inst, if (Inst.getOperand(1).getImm() == ARMCC::AL) Inst.setOpcode(ARM::tB); break; + case ARM::tLDMIA: { + // If the register list contains any high registers, or if the writeback + // doesn't match what tLDMIA can do, we need to use the 32-bit encoding + // instead if we're in Thumb2. Otherwise, this should have generated + // an error in validateInstruction(). + unsigned Rn = Inst.getOperand(0).getReg(); + bool hasWritebackToken = + (static_cast(Operands[3])->isToken() && + static_cast(Operands[3])->getToken() == "!"); + bool listContainsBase; + if (checkLowRegisterList(Inst, 3, Rn, 0, listContainsBase) || + (!listContainsBase && !hasWritebackToken) || + (listContainsBase && hasWritebackToken)) { + // 16-bit encoding isn't sufficient. Switch to the 32-bit version. + assert (isThumbTwo()); + Inst.setOpcode(hasWritebackToken ? ARM::t2LDMIA_UPD : ARM::t2LDMIA); + // If we're switching to the updating version, we need to insert + // the writeback tied operand. + if (hasWritebackToken) + Inst.insert(Inst.begin(), + MCOperand::CreateReg(Inst.getOperand(0).getReg())); + } + break; + } case ARM::t2IT: { // The mask bits for all but the first condition are represented as // the low bit of the condition code value implies 't'. We currently diff --git a/test/MC/ARM/basic-thumb2-instructions.s b/test/MC/ARM/basic-thumb2-instructions.s index 55ec15093bc..5a475b934f7 100644 --- a/test/MC/ARM/basic-thumb2-instructions.s +++ b/test/MC/ARM/basic-thumb2-instructions.s @@ -462,6 +462,44 @@ _func: @ CHECK: isb sy @ encoding: [0xbf,0xf3,0x6f,0x8f] +@------------------------------------------------------------------------------ +@ LDMIA +@------------------------------------------------------------------------------ + ldmia.w r4, {r4, r5, r8, r9} + ldmia.w r4, {r5, r6} + ldmia.w r5!, {r3, r8} + ldm.w r4, {r4, r5, r8, r9} + ldm.w r4, {r5, r6} + ldm.w r5!, {r3, r8} + ldm.w r5!, {r1, r2} + ldm.w r2, {r1, r2} + + ldmia r4, {r4, r5, r8, r9} + ldmia r4, {r5, r6} + ldmia r5!, {r3, r8} + ldm r4, {r4, r5, r8, r9} + ldm r4, {r5, r6} + ldm r5!, {r3, r8} + ldmfd r5!, {r3, r8} + +@ CHECK: ldm.w r4, {r4, r5, r8, r9} @ encoding: [0x94,0xe8,0x30,0x03] +@ CHECK: ldm.w r4, {r5, r6} @ encoding: [0x94,0xe8,0x60,0x00] +@ CHECK: ldm.w r5!, {r3, r8} @ encoding: [0xb5,0xe8,0x08,0x01] +@ CHECK: ldm.w r4, {r4, r5, r8, r9} @ encoding: [0x94,0xe8,0x30,0x03] +@ CHECK: ldm.w r4, {r5, r6} @ encoding: [0x94,0xe8,0x60,0x00] +@ CHECK: ldm.w r5!, {r3, r8} @ encoding: [0xb5,0xe8,0x08,0x01] +@ CHECK: ldm.w r5!, {r1, r2} @ encoding: [0xb5,0xe8,0x06,0x00] +@ CHECK: ldm.w r2, {r1, r2} @ encoding: [0x92,0xe8,0x06,0x00] + +@ CHECK: ldm.w r4, {r4, r5, r8, r9} @ encoding: [0x94,0xe8,0x30,0x03] +@ CHECK: ldm.w r4, {r5, r6} @ encoding: [0x94,0xe8,0x60,0x00] +@ CHECK: ldm.w r5!, {r3, r8} @ encoding: [0xb5,0xe8,0x08,0x01] +@ CHECK: ldm.w r4, {r4, r5, r8, r9} @ encoding: [0x94,0xe8,0x30,0x03] +@ CHECK: ldm.w r4, {r5, r6} @ encoding: [0x94,0xe8,0x60,0x00] +@ CHECK: ldm.w r5!, {r3, r8} @ encoding: [0xb5,0xe8,0x08,0x01] +@ CHECK: ldm.w r5!, {r3, r8} @ encoding: [0xb5,0xe8,0x08,0x01] + + @------------------------------------------------------------------------------ @ IT @------------------------------------------------------------------------------