diff --git a/include/llvm/MC/MCInstrAnalysis.h b/include/llvm/MC/MCInstrAnalysis.h new file mode 100644 index 00000000000..adca7b124d7 --- /dev/null +++ b/include/llvm/MC/MCInstrAnalysis.h @@ -0,0 +1,54 @@ +//===-- llvm/MC/MCInstrAnalysis.h - InstrDesc target hooks ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MCInstrAnalysis class which the MCTargetDescs can +// derive from to give additional information to MC. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/MC/MCInstrInfo.h" + +namespace llvm { + +class MCInstrAnalysis { +protected: + friend class Target; + const MCInstrInfo *Info; + + MCInstrAnalysis(const MCInstrInfo *Info) : Info(Info) {} +public: + virtual bool isBranch(const MCInst &Inst) const { + return Info->get(Inst.getOpcode()).isBranch(); + } + + virtual bool isConditionalBranch(const MCInst &Inst) const { + return Info->get(Inst.getOpcode()).isBranch(); + } + + virtual bool isUnconditionalBranch(const MCInst &Inst) const { + return Info->get(Inst.getOpcode()).isUnconditionalBranch(); + } + + virtual bool isIndirectBranch(const MCInst &Inst) const { + return Info->get(Inst.getOpcode()).isIndirectBranch(); + } + + virtual bool isReturn(const MCInst &Inst) const { + return Info->get(Inst.getOpcode()).isReturn(); + } + + /// evaluateBranch - Given a branch instruction try to get the address the + /// branch targets. Otherwise return -1. + virtual uint64_t + evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size) const; +}; + +} diff --git a/include/llvm/Target/TargetRegistry.h b/include/llvm/Target/TargetRegistry.h index aa9e3a9889a..6e55c1fbf61 100644 --- a/include/llvm/Target/TargetRegistry.h +++ b/include/llvm/Target/TargetRegistry.h @@ -20,6 +20,7 @@ #define LLVM_TARGET_TARGETREGISTRY_H #include "llvm/MC/MCCodeGenInfo.h" +#include "llvm/MC/MCInstrAnalysis.h" #include "llvm/ADT/Triple.h" #include #include @@ -74,6 +75,7 @@ namespace llvm { Reloc::Model RM, CodeModel::Model CM); typedef MCInstrInfo *(*MCInstrInfoCtorFnTy)(void); + typedef MCInstrAnalysis *(*MCInstrAnalysisCtorFnTy)(const MCInstrInfo*Info); typedef MCRegisterInfo *(*MCRegInfoCtorFnTy)(StringRef TT); typedef MCSubtargetInfo *(*MCSubtargetInfoCtorFnTy)(StringRef TT, StringRef CPU, @@ -147,6 +149,10 @@ namespace llvm { /// if registered. MCInstrInfoCtorFnTy MCInstrInfoCtorFn; + /// MCInstrAnalysisCtorFn - Constructor function for this target's + /// MCInstrAnalysis, if registered. + MCInstrAnalysisCtorFnTy MCInstrAnalysisCtorFn; + /// MCRegInfoCtorFn - Constructor function for this target's MCRegisterInfo, /// if registered. MCRegInfoCtorFnTy MCRegInfoCtorFn; @@ -281,6 +287,14 @@ namespace llvm { return MCInstrInfoCtorFn(); } + /// createMCInstrAnalysis - Create a MCInstrAnalysis implementation. + /// + MCInstrAnalysis *createMCInstrAnalysis(const MCInstrInfo *Info) const { + if (!MCInstrAnalysisCtorFn) + return new MCInstrAnalysis(Info); + return MCInstrAnalysisCtorFn(Info); + } + /// createMCRegInfo - Create a MCRegisterInfo implementation. /// MCRegisterInfo *createMCRegInfo(StringRef Triple) const { @@ -557,6 +571,15 @@ namespace llvm { T.MCInstrInfoCtorFn = Fn; } + /// RegisterMCInstrAnalysis - Register a MCInstrAnalysis implementation for + /// the given target. + static void RegisterMCInstrAnalysis(Target &T, + Target::MCInstrAnalysisCtorFnTy Fn) { + // Ignore duplicate registration. + if (!T.MCInstrAnalysisCtorFn) + T.MCInstrAnalysisCtorFn = Fn; + } + /// RegisterMCRegInfo - Register a MCRegisterInfo implementation for the /// given target. /// diff --git a/lib/MC/MCInstrAnalysis.cpp b/lib/MC/MCInstrAnalysis.cpp new file mode 100644 index 00000000000..03a35c597be --- /dev/null +++ b/lib/MC/MCInstrAnalysis.cpp @@ -0,0 +1,20 @@ +//===-- MCInstrAnalysis.cpp - InstrDesc target hooks ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCInstrAnalysis.h" +using namespace llvm; + +uint64_t MCInstrAnalysis::evaluateBranch(const MCInst &Inst, uint64_t Addr, + uint64_t Size) const { + if (Info->get(Inst.getOpcode()).OpInfo[0].OperandType != MCOI::OPERAND_PCREL) + return -1ULL; + + int64_t Imm = Inst.getOperand(0).getImm(); + return Addr+Size+Imm; +} diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp b/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp index ffdf658728c..0a4d671a4e3 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp @@ -13,6 +13,7 @@ #include "ARMMCTargetDesc.h" #include "ARMMCAsmInfo.h" +#include "ARMBaseInfo.h" #include "InstPrinter/ARMInstPrinter.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" @@ -159,6 +160,53 @@ static MCInstPrinter *createARMMCInstPrinter(const Target &T, return 0; } +namespace { + +class ARMMCInstrAnalysis : public MCInstrAnalysis { +public: + ARMMCInstrAnalysis(const MCInstrInfo *Info) : MCInstrAnalysis(Info) {} + virtual bool isBranch(const MCInst &Inst) const { + // Don't flag "bx lr" as a branch. + return MCInstrAnalysis::isBranch(Inst) && (Inst.getOpcode() != ARM::BX || + Inst.getOperand(0).getReg() != ARM::LR); + } + + virtual bool isUnconditionalBranch(const MCInst &Inst) const { + // BCCs with the "always" predicate are unconditional branches. + if (Inst.getOpcode() == ARM::Bcc && Inst.getOperand(1).getImm()==ARMCC::AL) + return true; + return MCInstrAnalysis::isUnconditionalBranch(Inst); + } + + virtual bool isConditionalBranch(const MCInst &Inst) const { + // BCCs with the "always" predicate are unconditional branches. + if (Inst.getOpcode() == ARM::Bcc && Inst.getOperand(1).getImm()==ARMCC::AL) + return false; + return MCInstrAnalysis::isConditionalBranch(Inst); + } + + virtual bool isReturn(const MCInst &Inst) const { + // Recognize "bx lr" as return. + return Inst.getOpcode() == ARM::BX && Inst.getOperand(0).getReg()==ARM::LR; + } + + uint64_t evaluateBranch(const MCInst &Inst, uint64_t Addr, + uint64_t Size) const { + // We only handle PCRel branches for now. + if (Info->get(Inst.getOpcode()).OpInfo[0].OperandType!=MCOI::OPERAND_PCREL) + return -1ULL; + + int64_t Imm = Inst.getOperand(0).getImm(); + // FIXME: This is not right for thumb. + return Addr+Imm+8; // In ARM mode the PC is always off by 8 bytes. + } +}; + +} + +static MCInstrAnalysis *createARMMCInstrAnalysis(const MCInstrInfo *Info) { + return new ARMMCInstrAnalysis(Info); +} // Force static initialization. extern "C" void LLVMInitializeARMTargetMC() { @@ -178,6 +226,11 @@ extern "C" void LLVMInitializeARMTargetMC() { TargetRegistry::RegisterMCRegInfo(TheARMTarget, createARMMCRegisterInfo); TargetRegistry::RegisterMCRegInfo(TheThumbTarget, createARMMCRegisterInfo); + TargetRegistry::RegisterMCInstrAnalysis(TheARMTarget, + createARMMCInstrAnalysis); + TargetRegistry::RegisterMCInstrAnalysis(TheThumbTarget, + createARMMCInstrAnalysis); + // Register the MC subtarget info. TargetRegistry::RegisterMCSubtargetInfo(TheARMTarget, ARM_MC::createARMMCSubtargetInfo); diff --git a/tools/llvm-objdump/MCFunction.cpp b/tools/llvm-objdump/MCFunction.cpp index 66c6c4cba49..418e9d050c1 100644 --- a/tools/llvm-objdump/MCFunction.cpp +++ b/tools/llvm-objdump/MCFunction.cpp @@ -17,6 +17,7 @@ #include "llvm/MC/MCDisassembler.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/Support/MemoryObject.h" @@ -28,7 +29,7 @@ using namespace llvm; MCFunction MCFunction::createFunctionFromMC(StringRef Name, const MCDisassembler *DisAsm, const MemoryObject &Region, uint64_t Start, - uint64_t End, const MCInstrInfo *InstrInfo, + uint64_t End, const MCInstrAnalysis *Ana, raw_ostream &DebugOut) { std::set Splits; Splits.insert(Start); @@ -40,21 +41,17 @@ MCFunction::createFunctionFromMC(StringRef Name, const MCDisassembler *DisAsm, MCInst Inst; if (DisAsm->getInstruction(Inst, Size, Region, Index, DebugOut)) { - const MCInstrDesc &Desc = InstrInfo->get(Inst.getOpcode()); - if (Desc.isBranch()) { - if (Desc.OpInfo[0].OperandType == MCOI::OPERAND_PCREL) { - int64_t Imm = Inst.getOperand(0).getImm(); - // FIXME: Distinguish relocations from nop jumps. - if (Imm != 0) { - if (Index+Imm+Size >= End) { - Instructions.push_back(MCDecodedInst(Index, Size, Inst)); - continue; // Skip branches that leave the function. - } - Splits.insert(Index+Imm+Size); - } + if (Ana->isBranch(Inst)) { + uint64_t targ = Ana->evaluateBranch(Inst, Index, Size); + // FIXME: Distinguish relocations from nop jumps. + if (targ != -1ULL && (targ == Index+Size || targ >= End)) { + Instructions.push_back(MCDecodedInst(Index, Size, Inst)); + continue; // Skip branches that leave the function. } + if (targ != -1ULL) + Splits.insert(targ); Splits.insert(Index+Size); - } else if (Desc.isReturn()) { + } else if (Ana->isReturn(Inst)) { Splits.insert(Index+Size); } @@ -90,26 +87,22 @@ MCFunction::createFunctionFromMC(StringRef Name, const MCDisassembler *DisAsm, MCBasicBlock &BB = i->second; if (BB.getInsts().empty()) continue; const MCDecodedInst &Inst = BB.getInsts().back(); - const MCInstrDesc &Desc = InstrInfo->get(Inst.Inst.getOpcode()); - if (Desc.isBranch()) { - // PCRel branch, we know the destination. - if (Desc.OpInfo[0].OperandType == MCOI::OPERAND_PCREL) { - int64_t Imm = Inst.Inst.getOperand(0).getImm(); - if (Imm != 0) - BB.addSucc(&f.getBlockAtAddress(Inst.Address+Inst.Size+Imm)); - // Conditional branches can also fall through to the next block. - if (Desc.isConditionalBranch() && llvm::next(i) != e) - BB.addSucc(&llvm::next(i)->second); - } else { + if (Ana->isBranch(Inst.Inst)) { + uint64_t targ = Ana->evaluateBranch(Inst.Inst, Inst.Address, Inst.Size); + if (targ == -1ULL) { // Indirect branch. Bail and add all blocks of the function as a // successor. for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i) BB.addSucc(&i->second); - } + } else if (targ != Inst.Address+Inst.Size) + BB.addSucc(&f.getBlockAtAddress(targ)); + // Conditional branches can also fall through to the next block. + if (Ana->isConditionalBranch(Inst.Inst) && llvm::next(i) != e) + BB.addSucc(&llvm::next(i)->second); } else { // No branch. Fall through to the next block. - if (!Desc.isReturn() && llvm::next(i) != e) + if (!Ana->isReturn(Inst.Inst) && llvm::next(i) != e) BB.addSucc(&llvm::next(i)->second); } } diff --git a/tools/llvm-objdump/MCFunction.h b/tools/llvm-objdump/MCFunction.h index f156e940118..023ca391830 100644 --- a/tools/llvm-objdump/MCFunction.h +++ b/tools/llvm-objdump/MCFunction.h @@ -20,7 +20,7 @@ namespace llvm { class MCDisassembler; -class MCInstrInfo; +class MCInstrAnalysis; class MemoryObject; class raw_ostream; @@ -68,7 +68,7 @@ public: static MCFunction createFunctionFromMC(StringRef Name, const MCDisassembler *DisAsm, const MemoryObject &Region, uint64_t Start, uint64_t End, - const MCInstrInfo *InstrInfo, raw_ostream &DebugOut); + const MCInstrAnalysis *Ana, raw_ostream &DebugOut); typedef MapTy::iterator iterator; iterator begin() { return Blocks.begin(); } diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 2458af478fd..4804f596b24 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -165,6 +165,8 @@ static void DisassembleInput(const StringRef &Filename) { return; } const MCInstrInfo *InstrInfo = TheTarget->createMCInstrInfo(); + OwningPtr + InstrAnalysis(TheTarget->createMCInstrAnalysis(InstrInfo)); outs() << '\n'; outs() << Filename @@ -270,8 +272,8 @@ static void DisassembleInput(const StringRef &Filename) { // Create CFG and use it for disassembly. MCFunction f = MCFunction::createFunctionFromMC(Symbols[si].second, DisAsm.get(), - memoryObject, Start, End, InstrInfo, - DebugOut); + memoryObject, Start, End, + InstrAnalysis.get(), DebugOut); for (MCFunction::iterator fi = f.begin(), fe = f.end(); fi != fe; ++fi){ bool hasPreds = false;