Skip to content

Commit

Permalink
Add MCInstrAnalysis class. This allows the targets to specify own ver…
Browse files Browse the repository at this point in the history
…sions of MCInstrDescs functions.

- Add overrides for ARM.
- Teach llvm-objdump to use this instead of plain MCInstrDesc.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@137059 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
d0k committed Aug 8, 2011
1 parent c13464f commit 41ab14b
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 31 deletions.
54 changes: 54 additions & 0 deletions include/llvm/MC/MCInstrAnalysis.h
Original file line number Diff line number Diff line change
@@ -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;
};

}
23 changes: 23 additions & 0 deletions include/llvm/Target/TargetRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <string>
#include <cassert>
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
///
Expand Down
20 changes: 20 additions & 0 deletions lib/MC/MCInstrAnalysis.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
53 changes: 53 additions & 0 deletions lib/Target/ARM/MCTargetDesc/ARMMCTargetDesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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() {
Expand All @@ -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);
Expand Down
47 changes: 20 additions & 27 deletions tools/llvm-objdump/MCFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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<uint64_t> Splits;
Splits.insert(Start);
Expand All @@ -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);
}

Expand Down Expand Up @@ -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);
}
}
Expand Down
4 changes: 2 additions & 2 deletions tools/llvm-objdump/MCFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
namespace llvm {

class MCDisassembler;
class MCInstrInfo;
class MCInstrAnalysis;
class MemoryObject;
class raw_ostream;

Expand Down Expand Up @@ -68,7 +68,7 @@ class MCFunction {
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(); }
Expand Down
6 changes: 4 additions & 2 deletions tools/llvm-objdump/llvm-objdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ static void DisassembleInput(const StringRef &Filename) {
return;
}
const MCInstrInfo *InstrInfo = TheTarget->createMCInstrInfo();
OwningPtr<MCInstrAnalysis>
InstrAnalysis(TheTarget->createMCInstrAnalysis(InstrInfo));

outs() << '\n';
outs() << Filename
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 41ab14b

Please sign in to comment.