From 52d2b0ed00d71c8ba0ff1a0b35cad4ffebc81dd5 Mon Sep 17 00:00:00 2001 From: Johnny Chen Date: Wed, 21 Apr 2010 01:01:19 +0000 Subject: [PATCH] Thumb instructions which have reglist operands at the end and predicate operands before reglist were not properly handled with respect to IT Block. Fix that by creating a new method ARMBasicMCBuilder::DoPredicateOperands() used by those instructions for disassembly. Add a test case. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@101974 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../ARM/Disassembler/ARMDisassemblerCore.cpp | 39 ++++++++++++++++++- .../ARM/Disassembler/ARMDisassemblerCore.h | 6 +++ .../ARM/Disassembler/ThumbDisassemblerCore.h | 37 ++++++++++++------ test/MC/Disassembler/thumb-tests.txt | 7 +++- 4 files changed, 73 insertions(+), 16 deletions(-) diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp index 6e76200b35e..adb7795a746 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp @@ -3218,6 +3218,40 @@ static uint32_t CondCode(uint32_t CondField) { return CondField; } +/// DoPredicateOperands - DoPredicateOperands process the predicate operands +/// of some Thumb instructions which come before the reglist operands. It +/// returns true if the two predicate operands have been processed. +bool ARMBasicMCBuilder::DoPredicateOperands(MCInst& MI, unsigned Opcode, + uint32_t /* insn */, unsigned short NumOpsRemaining) { + + assert(NumOpsRemaining > 0 && "Invalid argument"); + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + unsigned Idx = MI.getNumOperands(); + + // First, we check whether this instr specifies the PredicateOperand through + // a pair of TargetOperandInfos with isPredicate() property. + if (NumOpsRemaining >= 2 && + OpInfo[Idx].isPredicate() && OpInfo[Idx+1].isPredicate() && + OpInfo[Idx].RegClass == 0 && OpInfo[Idx+1].RegClass == ARM::CCRRegClassID) + { + // If we are inside an IT block, get the IT condition bits maintained via + // ARMBasicMCBuilder::ITState[7:0], through ARMBasicMCBuilder::GetITCond(). + // See also A2.5.2. + if (InITBlock()) + MI.addOperand(MCOperand::CreateImm(GetITCond())); + else + MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); + MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); + return true; + } + + return false; +} + +/// TryPredicateAndSBitModifier - TryPredicateAndSBitModifier tries to process +/// the possible Predicate and SBitModifier, to build the remaining MCOperand +/// constituents. bool ARMBasicMCBuilder::TryPredicateAndSBitModifier(MCInst& MI, unsigned Opcode, uint32_t insn, unsigned short NumOpsRemaining) { @@ -3258,10 +3292,11 @@ bool ARMBasicMCBuilder::TryPredicateAndSBitModifier(MCInst& MI, unsigned Opcode, MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); Idx += 2; NumOpsRemaining -= 2; - if (NumOpsRemaining == 0) - return true; } + if (NumOpsRemaining == 0) + return true; + // Next, if OptionalDefOperand exists, we check whether the 'S' bit is set. if (OpInfo[Idx].isOptionalDef() && OpInfo[Idx].RegClass==ARM::CCRRegClassID) { MI.addOperand(MCOperand::CreateReg(getSBit(insn) == 1 ? ARM::CPSR : 0)); diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h index ca6a67c76b2..b1d90df3417 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h +++ b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.h @@ -210,6 +210,12 @@ public: Err = ErrCode; } + /// DoPredicateOperands - DoPredicateOperands process the predicate operands + /// of some Thumb instructions which come before the reglist operands. It + /// returns true if the two predicate operands have been processed. + bool DoPredicateOperands(MCInst& MI, unsigned Opcode, + uint32_t insn, unsigned short NumOpsRemaning); + /// TryPredicateAndSBitModifier - TryPredicateAndSBitModifier tries to process /// the possible Predicate and SBitModifier, to build the remaining MCOperand /// constituents. diff --git a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h b/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h index ebbbfabe34d..53efaa7d1f3 100644 --- a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h +++ b/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h @@ -713,13 +713,17 @@ static bool DisassembleThumb1PushPop(MCInst &MI, unsigned Opcode, uint32_t insn, unsigned &OpIdx = NumOpsAdded; // Handling the two predicate operands before the reglist. - MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); - MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); - OpIdx = 2; + if (B->DoPredicateOperands(MI, Opcode, insn, NumOps)) + OpIdx += 2; + else { + DEBUG(errs() << "Expected predicate operands not found.\n"); + return false; + } - // Fill the variadic part of reglist. unsigned RegListBits = slice(insn, 8, 8) << (Opcode == ARM::tPUSH ? 14 : 15) | slice(insn, 7, 0); + + // Fill the variadic part of reglist. for (unsigned i = 0; i < 16; ++i) { if ((RegListBits >> i) & 1) { MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, @@ -840,7 +844,6 @@ static bool DisassembleThumb1LdStMul(bool Ld, MCInst &MI, unsigned Opcode, unsigned &OpIdx = NumOpsAdded; unsigned tRt = getT1tRt(insn); - unsigned RegListBits = slice(insn, 7, 0); OpIdx = 0; @@ -856,13 +859,19 @@ static bool DisassembleThumb1LdStMul(bool Ld, MCInst &MI, unsigned Opcode, ++OpIdx; // A8.6.53 LDM / LDMIA / LDMFD - Encoding T1 + // A8.6.53 STM / STMIA / STMEA - Encoding T1 MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(ARM_AM::ia))); ++OpIdx; // Handling the two predicate operands before the reglist. - MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); - MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); - OpIdx += 2; + if (B->DoPredicateOperands(MI, Opcode, insn, NumOps)) + OpIdx += 2; + else { + DEBUG(errs() << "Expected predicate operands not found.\n"); + return false; + } + + unsigned RegListBits = slice(insn, 7, 0); // Fill the variadic part of reglist. for (unsigned i = 0; i < 8; ++i) { @@ -1137,12 +1146,16 @@ static bool DisassembleThumb2LdStMul(MCInst &MI, unsigned Opcode, uint32_t insn, ++OpIdx; // Handling the two predicate operands before the reglist. - MI.addOperand(MCOperand::CreateImm(ARMCC::AL)); - MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); - OpIdx += 2; + if (B->DoPredicateOperands(MI, Opcode, insn, NumOps)) + OpIdx += 2; + else { + DEBUG(errs() << "Expected predicate operands not found.\n"); + return false; + } - // Fill the variadic part of reglist. unsigned RegListBits = insn & ((1 << 16) - 1); + + // Fill the variadic part of reglist. for (unsigned i = 0; i < 16; ++i) { if ((RegListBits >> i) & 1) { MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, diff --git a/test/MC/Disassembler/thumb-tests.txt b/test/MC/Disassembler/thumb-tests.txt index bfce44e8b19..14e91295276 100644 --- a/test/MC/Disassembler/thumb-tests.txt +++ b/test/MC/Disassembler/thumb-tests.txt @@ -85,6 +85,9 @@ # CHECK: lsleq r1, r0, #28 0x01 0x07 -# CHECK: rsbne r1, r2, #0 -0x51 0x42 +# CHECK: stmiane r0!, {r1, r2, r3} +0x0e 0xc0 + # IT block end +# CHECK: rsbs r1, r2, #0 +0x51 0x42 -- 2.34.1