diff options
Diffstat (limited to 'lib/Target/ARM/Disassembler')
-rw-r--r-- | lib/Target/ARM/Disassembler/ARMDisassembler.cpp | 42 | ||||
-rw-r--r-- | lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp | 157 | ||||
-rw-r--r-- | lib/Target/ARM/Disassembler/CMakeLists.txt | 4 | ||||
-rw-r--r-- | lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h | 223 |
4 files changed, 171 insertions, 255 deletions
diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index abdcf81..78d73d3 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -253,9 +253,6 @@ static unsigned T2Morph2LoadLiteral(unsigned Opcode) { default: return Opcode; // Return unmorphed opcode. - case ARM::t2LDRDi8: - return ARM::t2LDRDpci; - case ARM::t2LDR_POST: case ARM::t2LDR_PRE: case ARM::t2LDRi12: case ARM::t2LDRi8: case ARM::t2LDRs: case ARM::t2LDRT: @@ -350,36 +347,6 @@ static unsigned decodeThumbSideEffect(bool IsThumb2, unsigned &insn) { return decodeThumbInstruction(insn); } -static inline bool Thumb2PreloadOpcodeNoPCI(unsigned Opcode) { - switch (Opcode) { - default: - return false; - case ARM::t2PLDi12: case ARM::t2PLDi8: - case ARM::t2PLDs: - case ARM::t2PLDWi12: case ARM::t2PLDWi8: - case ARM::t2PLDWs: - case ARM::t2PLIi12: case ARM::t2PLIi8: - case ARM::t2PLIs: - return true; - } -} - -static inline unsigned T2Morph2Preload2PCI(unsigned Opcode) { - switch (Opcode) { - default: - return 0; - case ARM::t2PLDi12: case ARM::t2PLDi8: - case ARM::t2PLDs: - return ARM::t2PLDpci; - case ARM::t2PLDWi12: case ARM::t2PLDWi8: - case ARM::t2PLDWs: - return ARM::t2PLDWpci; - case ARM::t2PLIi12: case ARM::t2PLIi8: - case ARM::t2PLIs: - return ARM::t2PLIpci; - } -} - // // Public interface for the disassembler // @@ -486,11 +453,6 @@ bool ThumbDisassembler::getInstruction(MCInst &MI, // instructions as well. unsigned Opcode = decodeThumbSideEffect(IsThumb2, insn); - // A8.6.117/119/120/121. - // PLD/PLDW/PLI instructions with Rn==15 is transformed to the pci variant. - if (Thumb2PreloadOpcodeNoPCI(Opcode) && slice(insn, 19, 16) == 15) - Opcode = T2Morph2Preload2PCI(Opcode); - ARMFormat Format = ARMFormats[Opcode]; Size = IsThumb2 ? 4 : 2; @@ -569,9 +531,9 @@ static MCDisassembler *createThumbDisassembler(const Target &T) { return new ThumbDisassembler; } -extern "C" void LLVMInitializeARMDisassembler() { +extern "C" void LLVMInitializeARMDisassembler() { // Register the disassembler. - TargetRegistry::RegisterMCDisassembler(TheARMTarget, + TargetRegistry::RegisterMCDisassembler(TheARMTarget, createARMDisassembler); TargetRegistry::RegisterMCDisassembler(TheThumbTarget, createThumbDisassembler); diff --git a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp index aeeb8cd..32c41fc 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassemblerCore.cpp @@ -720,25 +720,29 @@ static bool DisassembleBrFrm(MCInst &MI, unsigned Opcode, uint32_t insn, NumOpsAdded = 1; return true; } - // MSR and MSRsys take one GPR reg Rm, followed by the mask. - if (Opcode == ARM::MSR || Opcode == ARM::MSRsys) { - assert(NumOps >= 1 && OpInfo[0].RegClass == ARM::GPRRegClassID && + // MSR take a mask, followed by one GPR reg Rm. The mask contains the R Bit in + // bit 4, and the special register fields in bits 3-0. + if (Opcode == ARM::MSR) { + assert(NumOps >= 1 && OpInfo[1].RegClass == ARM::GPRRegClassID && "Reg operand expected"); + MI.addOperand(MCOperand::CreateImm(slice(insn, 22, 22) << 4 /* R Bit */ | + slice(insn, 19, 16) /* Special Reg */ )); MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, decodeRm(insn)))); - MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16))); NumOpsAdded = 2; return true; } - // MSRi and MSRsysi take one so_imm operand, followed by the mask. - if (Opcode == ARM::MSRi || Opcode == ARM::MSRsysi) { + // MSRi take a mask, followed by one so_imm operand. The mask contains the + // R Bit in bit 4, and the special register fields in bits 3-0. + if (Opcode == ARM::MSRi) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 22, 22) << 4 /* R Bit */ | + slice(insn, 19, 16) /* Special Reg */ )); // SOImm is 4-bit rotate amount in bits 11-8 with 8-bit imm in bits 7-0. // A5.2.4 Rotate amount is twice the numeric value of Inst{11-8}. // See also ARMAddressingModes.h: getSOImmValImm() and getSOImmValRot(). unsigned Rot = (insn >> ARMII::SoRotImmShift) & 0xF; unsigned Imm = insn & 0xFF; MI.addOperand(MCOperand::CreateImm(ARM_AM::rotr32(Imm, 2*Rot))); - MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 16))); NumOpsAdded = 2; return true; } @@ -789,9 +793,8 @@ static bool DisassembleBrFrm(MCInst &MI, unsigned Opcode, uint32_t insn, } // Misc. Branch Instructions. -// BR_JTadd, BR_JTr, BR_JTm // BLXr9, BXr9 -// BRIND, BX_RET +// BX, BX_RET static bool DisassembleBrMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) { @@ -802,12 +805,14 @@ static bool DisassembleBrMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, OpIdx = 0; - // BX_RET has only two predicate operands, do an early return. - if (Opcode == ARM::BX_RET) + // BX_RET and MOVPCLR have only two predicate operands; do an early return. + if (Opcode == ARM::BX_RET || Opcode == ARM::MOVPCLR) return true; - // BLXr9 and BRIND take one GPR reg. - if (Opcode == ARM::BLXr9 || Opcode == ARM::BRIND) { + // BLX and BX take one GPR reg. + if (Opcode == ARM::BLXr9 || Opcode == ARM::BLXr9_pred || + Opcode == ARM::BLX || Opcode == ARM::BLX_pred || + Opcode == ARM::BX) { assert(NumOps >= 1 && OpInfo[OpIdx].RegClass == ARM::GPRRegClassID && "Reg operand expected"); MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, @@ -816,72 +821,6 @@ static bool DisassembleBrMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, return true; } - // BR_JTadd is an ADD with Rd = PC, (Rn, Rm) as the target and index regs. - if (Opcode == ARM::BR_JTadd) { - // InOperandList with GPR:$target and GPR:$idx regs. - - assert(NumOps == 4 && "Expect 4 operands"); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, - decodeRn(insn)))); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, - decodeRm(insn)))); - - // Fill in the two remaining imm operands to signify build completion. - MI.addOperand(MCOperand::CreateImm(0)); - MI.addOperand(MCOperand::CreateImm(0)); - - OpIdx = 4; - return true; - } - - // BR_JTr is a MOV with Rd = PC, and Rm as the source register. - if (Opcode == ARM::BR_JTr) { - // InOperandList with GPR::$target reg. - - assert(NumOps == 3 && "Expect 3 operands"); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, - decodeRm(insn)))); - - // Fill in the two remaining imm operands to signify build completion. - MI.addOperand(MCOperand::CreateImm(0)); - MI.addOperand(MCOperand::CreateImm(0)); - - OpIdx = 3; - return true; - } - - // BR_JTm is an LDR with Rt = PC. - if (Opcode == ARM::BR_JTm) { - // This is the reg/reg form, with base reg followed by +/- reg shop imm. - // See also ARMAddressingModes.h (Addressing Mode #2). - - assert(NumOps == 5 && getIBit(insn) == 1 && "Expect 5 operands && I-bit=1"); - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, - decodeRn(insn)))); - - ARM_AM::AddrOpc AddrOpcode = getUBit(insn) ? ARM_AM::add : ARM_AM::sub; - - // Disassemble the offset reg (Rm), shift type, and immediate shift length. - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, - decodeRm(insn)))); - // Inst{6-5} encodes the shift opcode. - ARM_AM::ShiftOpc ShOp = getShiftOpcForBits(slice(insn, 6, 5)); - // Inst{11-7} encodes the imm5 shift amount. - unsigned ShImm = slice(insn, 11, 7); - - // A8.4.1. Possible rrx or shift amount of 32... - getImmShiftSE(ShOp, ShImm); - MI.addOperand(MCOperand::CreateImm( - ARM_AM::getAM2Opc(AddrOpcode, ShImm, ShOp))); - - // Fill in the two remaining imm operands to signify build completion. - MI.addOperand(MCOperand::CreateImm(0)); - MI.addOperand(MCOperand::CreateImm(0)); - - OpIdx = 5; - return true; - } - return false; } @@ -1306,30 +1245,28 @@ static bool DisassembleLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) { assert(NumOps >= 5 && "LdStMulFrm expects NumOps >= 5"); - - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; + NumOpsAdded = 0; unsigned Base = getRegisterEnum(B, ARM::GPRRegClassID, decodeRn(insn)); // Writeback to base, if necessary. - if (Opcode == ARM::LDM_UPD || Opcode == ARM::STM_UPD) { + if (Opcode == ARM::LDMIA_UPD || Opcode == ARM::STMIA_UPD || + Opcode == ARM::LDMDA_UPD || Opcode == ARM::STMDA_UPD || + Opcode == ARM::LDMDB_UPD || Opcode == ARM::STMDB_UPD || + Opcode == ARM::LDMIB_UPD || Opcode == ARM::STMIB_UPD) { MI.addOperand(MCOperand::CreateReg(Base)); - ++OpIdx; + ++NumOpsAdded; } + // Add the base register operand. MI.addOperand(MCOperand::CreateReg(Base)); - ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); - MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode))); - // Handling the two predicate operands before the reglist. int64_t CondVal = insn >> ARMII::CondShift; MI.addOperand(MCOperand::CreateImm(CondVal == 0xF ? 0xE : CondVal)); MI.addOperand(MCOperand::CreateReg(ARM::CPSR)); - OpIdx += 4; + NumOpsAdded += 3; // Fill the variadic part of reglist. unsigned RegListBits = insn & ((1 << 16) - 1); @@ -1337,7 +1274,7 @@ static bool DisassembleLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, if ((RegListBits >> i) & 1) { MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, i))); - ++OpIdx; + ++NumOpsAdded; } } @@ -1882,8 +1819,10 @@ static bool DisassembleVFPLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, unsigned Base = getRegisterEnum(B, ARM::GPRRegClassID, decodeRn(insn)); // Writeback to base, if necessary. - if (Opcode == ARM::VLDMD_UPD || Opcode == ARM::VLDMS_UPD || - Opcode == ARM::VSTMD_UPD || Opcode == ARM::VSTMS_UPD) { + if (Opcode == ARM::VLDMDIA_UPD || Opcode == ARM::VLDMSIA_UPD || + Opcode == ARM::VLDMDDB_UPD || Opcode == ARM::VLDMSDB_UPD || + Opcode == ARM::VSTMDIA_UPD || Opcode == ARM::VSTMSIA_UPD || + Opcode == ARM::VSTMDDB_UPD || Opcode == ARM::VSTMSDB_UPD) { MI.addOperand(MCOperand::CreateReg(Base)); ++OpIdx; } @@ -1906,8 +1845,10 @@ static bool DisassembleVFPLdStMulFrm(MCInst &MI, unsigned Opcode, uint32_t insn, OpIdx += 4; - bool isSPVFP = (Opcode == ARM::VLDMS || Opcode == ARM::VLDMS_UPD || - Opcode == ARM::VSTMS || Opcode == ARM::VSTMS_UPD); + bool isSPVFP = (Opcode == ARM::VLDMSIA || Opcode == ARM::VLDMSDB || + Opcode == ARM::VLDMSIA_UPD || Opcode == ARM::VLDMSDB_UPD || + Opcode == ARM::VSTMSIA || Opcode == ARM::VSTMSDB || + Opcode == ARM::VSTMSIA_UPD || Opcode == ARM::VSTMSDB_UPD); unsigned RegClassID = isSPVFP ? ARM::SPRRegClassID : ARM::DPRRegClassID; // Extract Dd/Sd. @@ -3007,15 +2948,25 @@ static bool DisassembleMiscFrm(MCInst &MI, unsigned Opcode, uint32_t insn, return true; } - // CPS has a singleton $opt operand that contains the following information: - // opt{4-0} = mode from Inst{4-0} - // opt{5} = changemode from Inst{17} - // opt{8-6} = AIF from Inst{8-6} - // opt{10-9} = imod from Inst{19-18} with 0b10 as enable and 0b11 as disable - if (Opcode == ARM::CPS) { - unsigned Option = slice(insn, 4, 0) | slice(insn, 17, 17) << 5 | - slice(insn, 8, 6) << 6 | slice(insn, 19, 18) << 9; - MI.addOperand(MCOperand::CreateImm(Option)); + // FIXME: To enable correct asm parsing and disasm of CPS we need 3 different + // opcodes which match the same real instruction. This is needed since there's + // no current handling of optional arguments. Fix here when a better handling + // of optional arguments is implemented. + if (Opcode == ARM::CPS3p) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 18))); // imod + MI.addOperand(MCOperand::CreateImm(slice(insn, 8, 6))); // iflags + MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); // mode + NumOpsAdded = 3; + return true; + } + if (Opcode == ARM::CPS2p) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 19, 18))); // imod + MI.addOperand(MCOperand::CreateImm(slice(insn, 8, 6))); // iflags + NumOpsAdded = 2; + return true; + } + if (Opcode == ARM::CPS1p) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); // mode NumOpsAdded = 1; return true; } diff --git a/lib/Target/ARM/Disassembler/CMakeLists.txt b/lib/Target/ARM/Disassembler/CMakeLists.txt index 5f43989..b23dd6b 100644 --- a/lib/Target/ARM/Disassembler/CMakeLists.txt +++ b/lib/Target/ARM/Disassembler/CMakeLists.txt @@ -4,8 +4,8 @@ add_llvm_library(LLVMARMDisassembler ARMDisassembler.cpp ARMDisassemblerCore.cpp ) -# workaround for hanging compilation on MSVC9 and 10 -if( MSVC_VERSION EQUAL 1500 OR MSVC_VERSION EQUAL 1600 ) +# workaround for hanging compilation on MSVC8, 9 and 10 +if( MSVC_VERSION EQUAL 1400 OR MSVC_VERSION EQUAL 1500 OR MSVC_VERSION EQUAL 1600 ) set_property( SOURCE ARMDisassembler.cpp PROPERTY COMPILE_FLAGS "/Od" diff --git a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h b/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h index 6ed2949..33889da 100644 --- a/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h +++ b/lib/Target/ARM/Disassembler/ThumbDisassemblerCore.h @@ -564,6 +564,38 @@ static bool DisassembleThumb1LdPC(MCInst &MI, unsigned Opcode, uint32_t insn, // t_addrmode_sp := sp + imm8 * 4 // +// A8.6.63 LDRB (literal) +// A8.6.79 LDRSB (literal) +// A8.6.75 LDRH (literal) +// A8.6.83 LDRSH (literal) +// A8.6.59 LDR (literal) +// +// These instrs calculate an address from the PC value and an immediate offset. +// Rd Rn=PC (+/-)imm12 (+ if Inst{23} == 0b1) +static bool DisassembleThumb2Ldpci(MCInst &MI, unsigned Opcode, + uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) { + + const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; + if (!OpInfo) return false; + + assert(NumOps >= 2 && + OpInfo[0].RegClass == ARM::GPRRegClassID && + OpInfo[1].RegClass < 0 && + "Expect >= 2 operands, first as reg, and second as imm operand"); + + // Build the register operand, followed by the (+/-)imm12 immediate. + + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, + decodeRd(insn)))); + + MI.addOperand(MCOperand::CreateImm(decodeImm12(insn))); + + NumOpsAdded = 2; + + return true; +} + + // A6.2.4 Load/store single data item // // Load/Store Register (reg|imm): tRd tRn imm5 tRm @@ -796,14 +828,13 @@ static bool DisassembleThumb1Misc(MCInst &MI, unsigned Opcode, uint32_t insn, } // CPS has a singleton $opt operand that contains the following information: - // opt{4-0} = don't care - // opt{5} = 0 (false) - // opt{8-6} = AIF from Inst{2-0} - // opt{10-9} = 1:imod from Inst{4} with 0b10 as enable and 0b11 as disable + // The first op would be 0b10 as enable and 0b11 as disable in regular ARM, + // but in Thumb it's is 0 as enable and 1 as disable. So map it to ARM's + // default one. The second get the AIF flags from Inst{2-0}. if (Opcode == ARM::tCPS) { - unsigned Option = slice(insn, 2, 0) << 6 | slice(insn, 4, 4) << 9 | 1 << 10; - MI.addOperand(MCOperand::CreateImm(Option)); - NumOpsAdded = 1; + MI.addOperand(MCOperand::CreateImm(2 + slice(insn, 4, 4))); + MI.addOperand(MCOperand::CreateImm(slice(insn, 2, 0))); + NumOpsAdded = 2; return true; } @@ -833,40 +864,32 @@ static bool DisassembleThumb1Misc(MCInst &MI, unsigned Opcode, uint32_t insn, // A8.6.53 LDM / LDMIA // A8.6.189 STM / STMIA // -// tLDM_UPD/tSTM_UPD: tRt tRt AM4ModeImm Pred-Imm Pred-CCR register_list -// tLDM: tRt AM4ModeImm Pred-Imm Pred-CCR register_list +// tLDMIA_UPD/tSTMIA_UPD: tRt tRt AM4ModeImm Pred-Imm Pred-CCR register_list +// tLDMIA: tRt AM4ModeImm Pred-Imm Pred-CCR register_list static bool DisassembleThumb1LdStMul(bool Ld, MCInst &MI, unsigned Opcode, - uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) { - - assert((Opcode == ARM::tLDM || Opcode == ARM::tLDM_UPD || - Opcode == ARM::tSTM_UPD) && "Unexpected opcode"); - - unsigned &OpIdx = NumOpsAdded; + uint32_t insn, unsigned short NumOps, + unsigned &NumOpsAdded, BO B) { + assert((Opcode == ARM::tLDMIA || Opcode == ARM::tLDMIA_UPD || + Opcode == ARM::tSTMIA_UPD) && "Unexpected opcode"); unsigned tRt = getT1tRt(insn); - - OpIdx = 0; + NumOpsAdded = 0; // WB register, if necessary. - if (Opcode == ARM::tLDM_UPD || Opcode == ARM::tSTM_UPD) { + if (Opcode == ARM::tLDMIA_UPD || Opcode == ARM::tSTMIA_UPD) { MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, tRt))); - ++OpIdx; + ++NumOpsAdded; } MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, tRt))); - ++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; + ++NumOpsAdded; // Handling the two predicate operands before the reglist. - if (B->DoPredicateOperands(MI, Opcode, insn, NumOps)) - OpIdx += 2; - else { + if (B->DoPredicateOperands(MI, Opcode, insn, NumOps)) { + NumOpsAdded += 2; + } else { DEBUG(errs() << "Expected predicate operands not found.\n"); return false; } @@ -874,13 +897,12 @@ static bool DisassembleThumb1LdStMul(bool Ld, MCInst &MI, unsigned Opcode, unsigned RegListBits = slice(insn, 7, 0); // Fill the variadic part of reglist. - for (unsigned i = 0; i < 8; ++i) { + for (unsigned i = 0; i < 8; ++i) if ((RegListBits >> i) & 1) { MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::tGPRRegClassID, i))); - ++OpIdx; + ++NumOpsAdded; } - } return true; } @@ -1122,34 +1144,31 @@ static bool DisassembleThumb2LdStMul(MCInst &MI, unsigned Opcode, uint32_t insn, if (Thumb2RFEOpcode(Opcode)) return DisassembleThumb2RFE(MI, Opcode, insn, NumOps, NumOpsAdded, B); - assert((Opcode == ARM::t2LDM || Opcode == ARM::t2LDM_UPD || - Opcode == ARM::t2STM || Opcode == ARM::t2STM_UPD) + assert((Opcode == ARM::t2LDMIA || Opcode == ARM::t2LDMIA_UPD || + Opcode == ARM::t2LDMDB || Opcode == ARM::t2LDMDB_UPD || + Opcode == ARM::t2STMIA || Opcode == ARM::t2STMIA_UPD || + Opcode == ARM::t2STMDB || Opcode == ARM::t2STMDB_UPD) && "Unexpected opcode"); assert(NumOps >= 5 && "Thumb2 LdStMul expects NumOps >= 5"); - unsigned &OpIdx = NumOpsAdded; - - OpIdx = 0; + NumOpsAdded = 0; unsigned Base = getRegisterEnum(B, ARM::GPRRegClassID, decodeRn(insn)); // Writeback to base. - if (Opcode == ARM::t2LDM_UPD || Opcode == ARM::t2STM_UPD) { + if (Opcode == ARM::t2LDMIA_UPD || Opcode == ARM::t2LDMDB_UPD || + Opcode == ARM::t2STMIA_UPD || Opcode == ARM::t2STMDB_UPD) { MI.addOperand(MCOperand::CreateReg(Base)); - ++OpIdx; + ++NumOpsAdded; } MI.addOperand(MCOperand::CreateReg(Base)); - ++OpIdx; - - ARM_AM::AMSubMode SubMode = getAMSubModeForBits(getPUBits(insn)); - MI.addOperand(MCOperand::CreateImm(ARM_AM::getAM4ModeImm(SubMode))); - ++OpIdx; + ++NumOpsAdded; // Handling the two predicate operands before the reglist. - if (B->DoPredicateOperands(MI, Opcode, insn, NumOps)) - OpIdx += 2; - else { + if (B->DoPredicateOperands(MI, Opcode, insn, NumOps)) { + NumOpsAdded += 2; + } else { DEBUG(errs() << "Expected predicate operands not found.\n"); return false; } @@ -1157,13 +1176,12 @@ static bool DisassembleThumb2LdStMul(MCInst &MI, unsigned Opcode, uint32_t insn, unsigned RegListBits = insn & ((1 << 16) - 1); // Fill the variadic part of reglist. - for (unsigned i = 0; i < 16; ++i) { + for (unsigned i = 0; i < 16; ++i) if ((RegListBits >> i) & 1) { MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, i))); - ++OpIdx; + ++NumOpsAdded; } - } return true; } @@ -1261,13 +1279,7 @@ static bool DisassembleThumb2LdStDual(MCInst &MI, unsigned Opcode, return true; } -// PC-based defined for Codegen, which do not get decoded by design: -// -// t2TBB, t2TBH: Rm immDontCare immDontCare -// -// Generic version defined for disassembly: -// -// t2TBBgen, t2TBHgen: Rn Rm Pred-Imm Pred-CCR +// t2TBB, t2TBH: Rn Rm Pred-Imm Pred-CCR static bool DisassembleThumb2TB(MCInst &MI, unsigned Opcode, uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) { @@ -1646,15 +1658,25 @@ static bool DisassembleThumb2BrMiscCtrl(MCInst &MI, unsigned Opcode, break; } - // CPS has a singleton $opt operand that contains the following information: - // opt{4-0} = mode from Inst{4-0} - // opt{5} = changemode from Inst{8} - // opt{8-6} = AIF from Inst{7-5} - // opt{10-9} = imod from Inst{10-9} with 0b10 as enable and 0b11 as disable - if (Opcode == ARM::t2CPS) { - unsigned Option = slice(insn, 4, 0) | slice(insn, 8, 8) << 5 | - slice(insn, 7, 5) << 6 | slice(insn, 10, 9) << 9; - MI.addOperand(MCOperand::CreateImm(Option)); + // FIXME: To enable correct asm parsing and disasm of CPS we need 3 different + // opcodes which match the same real instruction. This is needed since there's + // no current handling of optional arguments. Fix here when a better handling + // of optional arguments is implemented. + if (Opcode == ARM::t2CPS3p) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 10, 9))); // imod + MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 5))); // iflags + MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); // mode + NumOpsAdded = 3; + return true; + } + if (Opcode == ARM::t2CPS2p) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 10, 9))); // imod + MI.addOperand(MCOperand::CreateImm(slice(insn, 7, 5))); // iflags + NumOpsAdded = 2; + return true; + } + if (Opcode == ARM::t2CPS1p) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 4, 0))); // mode NumOpsAdded = 1; return true; } @@ -1680,11 +1702,13 @@ static bool DisassembleThumb2BrMiscCtrl(MCInst &MI, unsigned Opcode, NumOpsAdded = 1; return true; } - // MSR and MSRsys take one GPR reg Rn, followed by the mask. - if (Opcode == ARM::t2MSR || Opcode == ARM::t2MSRsys || Opcode == ARM::t2BXJ) { + // MSR take a mask, followed by one GPR reg Rn. The mask contains the R Bit in + // bit 4, and the special register fields in bits 3-0. + if (Opcode == ARM::t2MSR) { + MI.addOperand(MCOperand::CreateImm(slice(insn, 20, 20) << 4 /* R Bit */ | + slice(insn, 11, 8) /* Special Reg */)); MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, decodeRn(insn)))); - MI.addOperand(MCOperand::CreateImm(slice(insn, 11, 8))); NumOpsAdded = 2; return true; } @@ -1695,6 +1719,17 @@ static bool DisassembleThumb2BrMiscCtrl(MCInst &MI, unsigned Opcode, return true; } + // Some instructions have predicate operands first before the immediate. + if (Opcode == ARM::tBLXi_r9 || Opcode == ARM::tBLr9) { + // Handling the two predicate operands before the imm operand. + if (B->DoPredicateOperands(MI, Opcode, insn, NumOps)) + NumOpsAdded += 2; + else { + DEBUG(errs() << "Expected predicate operands not found.\n"); + return false; + } + } + // Add the imm operand. int Offset = 0; @@ -1721,7 +1756,8 @@ static bool DisassembleThumb2BrMiscCtrl(MCInst &MI, unsigned Opcode, // to compensate. MI.addOperand(MCOperand::CreateImm(Offset + 4)); - NumOpsAdded = 1; + // This is an increment as some predicate operands may have been added first. + NumOpsAdded += 1; return true; } @@ -1730,11 +1766,11 @@ static inline bool Thumb2PreloadOpcode(unsigned Opcode) { switch (Opcode) { default: return false; - case ARM::t2PLDi12: case ARM::t2PLDi8: case ARM::t2PLDpci: + case ARM::t2PLDi12: case ARM::t2PLDi8: case ARM::t2PLDs: - case ARM::t2PLDWi12: case ARM::t2PLDWi8: case ARM::t2PLDWpci: + case ARM::t2PLDWi12: case ARM::t2PLDWi8: case ARM::t2PLDWs: - case ARM::t2PLIi12: case ARM::t2PLIi8: case ARM::t2PLIpci: + case ARM::t2PLIi12: case ARM::t2PLIi8: case ARM::t2PLIs: return true; } @@ -1771,11 +1807,10 @@ static bool DisassembleThumb2PreLoad(MCInst &MI, unsigned Opcode, uint32_t insn, && !OpInfo[OpIdx].isOptionalDef() && "Pure imm operand expected"); int Offset = 0; - if (Opcode == ARM::t2PLDpci || Opcode == ARM::t2PLDWpci || - Opcode == ARM::t2PLIpci) { + if (slice(insn, 19, 16) == 0xFF) { bool Negative = slice(insn, 23, 23) == 0; unsigned Imm12 = getImm12(insn); - Offset = Negative ? -1 - Imm12 : 1 * Imm12; + Offset = Negative ? -1 - Imm12 : 1 * Imm12; } else if (Opcode == ARM::t2PLDi8 || Opcode == ARM::t2PLDWi8 || Opcode == ARM::t2PLIi8) { // A8.6.117 Encoding T2: add = FALSE @@ -1797,37 +1832,6 @@ static bool DisassembleThumb2PreLoad(MCInst &MI, unsigned Opcode, uint32_t insn, return true; } -// A8.6.63 LDRB (literal) -// A8.6.79 LDRSB (literal) -// A8.6.75 LDRH (literal) -// A8.6.83 LDRSH (literal) -// A8.6.59 LDR (literal) -// -// These instrs calculate an address from the PC value and an immediate offset. -// Rd Rn=PC (+/-)imm12 (+ if Inst{23} == 0b1) -static bool DisassembleThumb2Ldpci(MCInst &MI, unsigned Opcode, - uint32_t insn, unsigned short NumOps, unsigned &NumOpsAdded, BO B) { - - const TargetOperandInfo *OpInfo = ARMInsts[Opcode].OpInfo; - if (!OpInfo) return false; - - assert(NumOps >= 2 && - OpInfo[0].RegClass == ARM::GPRRegClassID && - OpInfo[1].RegClass < 0 && - "Expect >= 2 operands, first as reg, and second as imm operand"); - - // Build the register operand, followed by the (+/-)imm12 immediate. - - MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, - decodeRd(insn)))); - - MI.addOperand(MCOperand::CreateImm(decodeImm12(insn))); - - NumOpsAdded = 2; - - return true; -} - // A6.3.10 Store single data item // A6.3.9 Load byte, memory hints // A6.3.8 Load halfword, memory hints @@ -1866,7 +1870,6 @@ static bool DisassembleThumb2LdSt(bool Load, MCInst &MI, unsigned Opcode, // See, for example, A6.3.7 Load word: Table A6-18 Load word. if (Load && Rn == 15) return DisassembleThumb2Ldpci(MI, Opcode, insn, NumOps, NumOpsAdded, B); - const TargetInstrDesc &TID = ARMInsts[Opcode]; const TargetOperandInfo *OpInfo = TID.OpInfo; unsigned &OpIdx = NumOpsAdded; @@ -1913,7 +1916,7 @@ static bool DisassembleThumb2LdSt(bool Load, MCInst &MI, unsigned Opcode, else Imm = decodeImm8(insn); } - + MI.addOperand(MCOperand::CreateReg(getRegisterEnum(B, ARM::GPRRegClassID, R0))); ++OpIdx; @@ -2138,7 +2141,7 @@ static bool DisassembleThumb2(uint16_t op1, uint16_t op2, uint16_t op, return DisassembleThumb2LdStDual(MI, Opcode, insn, NumOps, NumOpsAdded, B); } - if (Opcode == ARM::t2TBBgen || Opcode == ARM::t2TBHgen) { + if (Opcode == ARM::t2TBB || Opcode == ARM::t2TBH) { // Table branch. return DisassembleThumb2TB(MI, Opcode, insn, NumOps, NumOpsAdded, B); } @@ -2238,7 +2241,7 @@ static bool DisassembleThumbFrm(MCInst &MI, unsigned Opcode, uint32_t insn, } // A6.3 32-bit Thumb instruction encoding - + uint16_t op1 = slice(HalfWord, 12, 11); uint16_t op2 = slice(HalfWord, 10, 4); uint16_t op = slice(insn, 15, 15); |