mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 19:08:21 +08:00
Summary: Eliminated BinaryFunction::getName(). The function was confusing since the name is ambigous. Instead we have BinaryFunction::getPrintName() used for printing and whenever unique string identifier is needed one can use getSymbol()->getName(). In the next diff I'll have a map from MCSymbol to BinaryFunction in BinaryContext to facilitate function lookup from instruction operand expressions. There's one bug fixed where the function was called only under assert() in ICF::foldFunction(). For output we update all symbols associated with the function. At the moment it has no effect on the generated binary but in the future we would like to have all symbols in the symbol table updated. (cherry picked from FBD3704790)
579 lines
21 KiB
C++
579 lines
21 KiB
C++
//===--- BinaryBasicBlock.h - Interface for assembly-level basic block ----===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// TODO: memory management for instructions.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_TOOLS_LLVM_BOLT_BINARY_BASIC_BLOCK_H
|
|
#define LLVM_TOOLS_LLVM_BOLT_BINARY_BASIC_BLOCK_H
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/GraphTraits.h"
|
|
#include "llvm/MC/MCInst.h"
|
|
#include "llvm/MC/MCSymbol.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <limits>
|
|
#include <utility>
|
|
#include <set>
|
|
|
|
namespace llvm {
|
|
class MCInstrAnalysis;
|
|
namespace bolt {
|
|
|
|
class BinaryFunction;
|
|
class BinaryContext;
|
|
|
|
/// The intention is to keep the structure similar to MachineBasicBlock as
|
|
/// we might switch to it at some point.
|
|
class BinaryBasicBlock {
|
|
public:
|
|
struct BinaryBranchInfo {
|
|
uint64_t Count;
|
|
uint64_t MispredictedCount; /// number of branches mispredicted
|
|
};
|
|
|
|
private:
|
|
/// Label associated with the block.
|
|
MCSymbol *Label{nullptr};
|
|
|
|
/// Function that owns this basic block.
|
|
BinaryFunction *Function;
|
|
|
|
/// Label associated with the end of the block in the output binary.
|
|
const MCSymbol *EndLabel{nullptr};
|
|
|
|
/// [Begin, End) address range for this block in the output binary.
|
|
std::pair<uint64_t, uint64_t> OutputAddressRange{0, 0};
|
|
|
|
/// Original offset in the function.
|
|
uint64_t Offset{std::numeric_limits<uint64_t>::max()};
|
|
|
|
/// Alignment requirements for the block.
|
|
uint64_t Alignment{1};
|
|
|
|
/// Index to BasicBlocks vector in BinaryFunction.
|
|
unsigned Index{~0u};
|
|
|
|
/// Number of pseudo instructions in this block.
|
|
uint32_t NumPseudos{0};
|
|
|
|
/// Number of times this basic block was executed.
|
|
uint64_t ExecutionCount{COUNT_NO_PROFILE};
|
|
|
|
/// In cases where the parent function has been split, IsCold == true means
|
|
/// this BB will be allocated outside its parent function.
|
|
bool IsCold{false};
|
|
|
|
/// Indicates if the block could be outlined.
|
|
bool CanOutline{true};
|
|
|
|
/// Vector of all instructions in the block.
|
|
std::vector<MCInst> Instructions;
|
|
|
|
/// CFG information.
|
|
std::vector<BinaryBasicBlock *> Predecessors;
|
|
std::vector<BinaryBasicBlock *> Successors;
|
|
std::set<BinaryBasicBlock *> Throwers;
|
|
std::set<BinaryBasicBlock *> LandingPads;
|
|
|
|
/// Each successor has a corresponding BranchInfo entry in the list.
|
|
std::vector<BinaryBranchInfo> BranchInfo;
|
|
|
|
BinaryBasicBlock() {}
|
|
|
|
explicit BinaryBasicBlock(
|
|
MCSymbol *Label,
|
|
BinaryFunction *Function,
|
|
uint64_t Offset = std::numeric_limits<uint64_t>::max())
|
|
: Label(Label), Function(Function), Offset(Offset) {}
|
|
|
|
explicit BinaryBasicBlock(uint64_t Offset)
|
|
: Offset(Offset) {}
|
|
|
|
// Exclusively managed by BinaryFunction.
|
|
friend class BinaryFunction;
|
|
friend bool operator<(const BinaryBasicBlock &LHS,
|
|
const BinaryBasicBlock &RHS);
|
|
|
|
public:
|
|
static constexpr uint64_t COUNT_FALLTHROUGH_EDGE =
|
|
std::numeric_limits<uint64_t>::max();
|
|
static constexpr uint64_t COUNT_NO_PROFILE =
|
|
std::numeric_limits<uint64_t>::max();
|
|
|
|
// Instructions iterators.
|
|
typedef std::vector<MCInst>::iterator iterator;
|
|
typedef std::vector<MCInst>::const_iterator const_iterator;
|
|
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
|
|
typedef std::reverse_iterator<iterator> reverse_iterator;
|
|
|
|
bool empty() const { return Instructions.empty(); }
|
|
unsigned size() const { return (unsigned)Instructions.size(); }
|
|
MCInst &front() { return Instructions.front(); }
|
|
MCInst &back() { return Instructions.back(); }
|
|
const MCInst &front() const { return Instructions.front(); }
|
|
const MCInst &back() const { return Instructions.back(); }
|
|
|
|
iterator begin() { return Instructions.begin(); }
|
|
const_iterator begin() const { return Instructions.begin(); }
|
|
iterator end () { return Instructions.end(); }
|
|
const_iterator end () const { return Instructions.end(); }
|
|
reverse_iterator rbegin() { return Instructions.rbegin(); }
|
|
const_reverse_iterator rbegin() const { return Instructions.rbegin(); }
|
|
reverse_iterator rend () { return Instructions.rend(); }
|
|
const_reverse_iterator rend () const { return Instructions.rend(); }
|
|
|
|
// CFG iterators.
|
|
typedef std::vector<BinaryBasicBlock *>::iterator pred_iterator;
|
|
typedef std::vector<BinaryBasicBlock *>::const_iterator const_pred_iterator;
|
|
typedef std::vector<BinaryBasicBlock *>::iterator succ_iterator;
|
|
typedef std::vector<BinaryBasicBlock *>::const_iterator const_succ_iterator;
|
|
typedef std::set<BinaryBasicBlock *>::iterator throw_iterator;
|
|
typedef std::set<BinaryBasicBlock *>::const_iterator const_throw_iterator;
|
|
typedef std::set<BinaryBasicBlock *>::iterator lp_iterator;
|
|
typedef std::set<BinaryBasicBlock *>::const_iterator const_lp_iterator;
|
|
typedef std::vector<BinaryBasicBlock *>::reverse_iterator
|
|
pred_reverse_iterator;
|
|
typedef std::vector<BinaryBasicBlock *>::const_reverse_iterator
|
|
const_pred_reverse_iterator;
|
|
typedef std::vector<BinaryBasicBlock *>::reverse_iterator
|
|
succ_reverse_iterator;
|
|
typedef std::vector<BinaryBasicBlock *>::const_reverse_iterator
|
|
const_succ_reverse_iterator;
|
|
typedef std::set<BinaryBasicBlock *>::reverse_iterator
|
|
throw_reverse_iterator;
|
|
typedef std::set<BinaryBasicBlock *>::const_reverse_iterator
|
|
const_throw_reverse_iterator;
|
|
typedef std::set<BinaryBasicBlock *>::reverse_iterator
|
|
lp_reverse_iterator;
|
|
typedef std::set<BinaryBasicBlock *>::const_reverse_iterator
|
|
const_lp_reverse_iterator;
|
|
|
|
pred_iterator pred_begin() { return Predecessors.begin(); }
|
|
const_pred_iterator pred_begin() const { return Predecessors.begin(); }
|
|
pred_iterator pred_end() { return Predecessors.end(); }
|
|
const_pred_iterator pred_end() const { return Predecessors.end(); }
|
|
pred_reverse_iterator pred_rbegin()
|
|
{ return Predecessors.rbegin();}
|
|
const_pred_reverse_iterator pred_rbegin() const
|
|
{ return Predecessors.rbegin();}
|
|
pred_reverse_iterator pred_rend()
|
|
{ return Predecessors.rend(); }
|
|
const_pred_reverse_iterator pred_rend() const
|
|
{ return Predecessors.rend(); }
|
|
unsigned pred_size() const {
|
|
return (unsigned)Predecessors.size();
|
|
}
|
|
bool pred_empty() const { return Predecessors.empty(); }
|
|
|
|
succ_iterator succ_begin() { return Successors.begin(); }
|
|
const_succ_iterator succ_begin() const { return Successors.begin(); }
|
|
succ_iterator succ_end() { return Successors.end(); }
|
|
const_succ_iterator succ_end() const { return Successors.end(); }
|
|
succ_reverse_iterator succ_rbegin()
|
|
{ return Successors.rbegin(); }
|
|
const_succ_reverse_iterator succ_rbegin() const
|
|
{ return Successors.rbegin(); }
|
|
succ_reverse_iterator succ_rend()
|
|
{ return Successors.rend(); }
|
|
const_succ_reverse_iterator succ_rend() const
|
|
{ return Successors.rend(); }
|
|
unsigned succ_size() const {
|
|
return (unsigned)Successors.size();
|
|
}
|
|
bool succ_empty() const { return Successors.empty(); }
|
|
|
|
throw_iterator throw_begin() { return Throwers.begin(); }
|
|
const_throw_iterator throw_begin() const { return Throwers.begin(); }
|
|
throw_iterator throw_end() { return Throwers.end(); }
|
|
const_throw_iterator throw_end() const { return Throwers.end(); }
|
|
throw_reverse_iterator throw_rbegin()
|
|
{ return Throwers.rbegin();}
|
|
const_throw_reverse_iterator throw_rbegin() const
|
|
{ return Throwers.rbegin();}
|
|
throw_reverse_iterator throw_rend()
|
|
{ return Throwers.rend(); }
|
|
const_throw_reverse_iterator throw_rend() const
|
|
{ return Throwers.rend(); }
|
|
unsigned throw_size() const {
|
|
return (unsigned)Throwers.size();
|
|
}
|
|
bool throw_empty() const { return Throwers.empty(); }
|
|
|
|
lp_iterator lp_begin() { return LandingPads.begin(); }
|
|
const_lp_iterator lp_begin() const { return LandingPads.begin(); }
|
|
lp_iterator lp_end() { return LandingPads.end(); }
|
|
const_lp_iterator lp_end() const { return LandingPads.end(); }
|
|
lp_reverse_iterator lp_rbegin()
|
|
{ return LandingPads.rbegin(); }
|
|
const_lp_reverse_iterator lp_rbegin() const
|
|
{ return LandingPads.rbegin(); }
|
|
lp_reverse_iterator lp_rend()
|
|
{ return LandingPads.rend(); }
|
|
const_lp_reverse_iterator lp_rend() const
|
|
{ return LandingPads.rend(); }
|
|
unsigned lp_size() const {
|
|
return (unsigned)LandingPads.size();
|
|
}
|
|
bool lp_empty() const { return LandingPads.empty(); }
|
|
|
|
inline iterator_range<pred_iterator> predecessors() {
|
|
return iterator_range<pred_iterator>(pred_begin(), pred_end());
|
|
}
|
|
inline iterator_range<const_pred_iterator> predecessors() const {
|
|
return iterator_range<const_pred_iterator>(pred_begin(), pred_end());
|
|
}
|
|
inline iterator_range<succ_iterator> successors() {
|
|
return iterator_range<succ_iterator>(succ_begin(), succ_end());
|
|
}
|
|
inline iterator_range<const_succ_iterator> successors() const {
|
|
return iterator_range<const_succ_iterator>(succ_begin(), succ_end());
|
|
}
|
|
inline iterator_range<throw_iterator> throwers() {
|
|
return iterator_range<throw_iterator>(throw_begin(), throw_end());
|
|
}
|
|
inline iterator_range<const_throw_iterator> throwers() const {
|
|
return iterator_range<const_throw_iterator>(throw_begin(), throw_end());
|
|
}
|
|
inline iterator_range<lp_iterator> landing_pads() {
|
|
return iterator_range<lp_iterator>(lp_begin(), lp_end());
|
|
}
|
|
inline iterator_range<const_lp_iterator> landing_pads() const {
|
|
return iterator_range<const_lp_iterator>(lp_begin(), lp_end());
|
|
}
|
|
|
|
// BranchInfo iterators.
|
|
typedef std::vector<BinaryBranchInfo>::const_iterator
|
|
const_branch_info_iterator;
|
|
|
|
const_branch_info_iterator branch_info_begin() const
|
|
{ return BranchInfo.begin(); }
|
|
const_branch_info_iterator branch_info_end() const
|
|
{ return BranchInfo.end(); }
|
|
unsigned branch_info_size() const {
|
|
return (unsigned)BranchInfo.size();
|
|
}
|
|
bool branch_info_empty() const
|
|
{ return BranchInfo.empty(); }
|
|
|
|
inline iterator_range<const_branch_info_iterator> branch_info() const {
|
|
return iterator_range<const_branch_info_iterator>(
|
|
branch_info_begin(), branch_info_end());
|
|
}
|
|
|
|
/// Get instruction at given index.
|
|
MCInst &getInstructionAtIndex(unsigned Index) {
|
|
return Instructions.at(Index);
|
|
}
|
|
|
|
const MCInst &getInstructionAtIndex(unsigned Index) const {
|
|
return Instructions.at(Index);
|
|
}
|
|
|
|
/// Return symbol marking the start of this basic block.
|
|
MCSymbol *getLabel() {
|
|
return Label;
|
|
}
|
|
|
|
/// Return symbol marking the start of this basic block (const version).
|
|
const MCSymbol *getLabel() const {
|
|
return Label;
|
|
}
|
|
|
|
/// Get successor with given label. Returns nullptr if no such
|
|
/// successor is found.
|
|
BinaryBasicBlock *getSuccessor(const MCSymbol *Label) const;
|
|
|
|
/// Get landing pad with given label. Returns nullptr if no such
|
|
/// landing pad is found.
|
|
BinaryBasicBlock *getLandingPad(const MCSymbol *Label) const;
|
|
|
|
/// Return local name for the block.
|
|
StringRef getName() const {
|
|
return Label->getName();
|
|
}
|
|
|
|
/// Add instruction at the end of this basic block.
|
|
/// Returns the index of the instruction in the Instructions vector of the BB.
|
|
uint32_t addInstruction(MCInst &&Inst) {
|
|
Instructions.emplace_back(Inst);
|
|
return Instructions.size() - 1;
|
|
}
|
|
|
|
/// Add instruction at the end of this basic block.
|
|
/// Returns the index of the instruction in the Instructions vector of the BB.
|
|
uint32_t addInstruction(const MCInst &Inst) {
|
|
Instructions.push_back(Inst);
|
|
return Instructions.size() - 1;
|
|
}
|
|
|
|
/// Add a range of instructions to the end of this basic block.
|
|
template <typename Itr>
|
|
void addInstructions(Itr Begin, Itr End) {
|
|
while (Begin != End) {
|
|
addInstruction(*Begin++);
|
|
}
|
|
}
|
|
|
|
/// Add instruction before Pos in this basic block.
|
|
const_iterator insertPseudoInstr(const_iterator Pos, MCInst &Instr) {
|
|
++NumPseudos;
|
|
return Instructions.emplace(Pos, Instr);
|
|
}
|
|
|
|
uint32_t getNumPseudos() const { return NumPseudos; }
|
|
|
|
/// Set minimum alignment for the basic block.
|
|
void setAlignment(uint64_t Align) {
|
|
Alignment = Align;
|
|
}
|
|
|
|
/// Return required alignment for the block.
|
|
uint64_t getAlignment() const {
|
|
return Alignment;
|
|
}
|
|
|
|
/// Return offset of the basic block from the function start.
|
|
uint64_t getOffset() const {
|
|
return Offset;
|
|
}
|
|
|
|
/// Adds block to successor list, and also updates predecessor list for
|
|
/// successor block.
|
|
/// Set branch info for this path.
|
|
void addSuccessor(BinaryBasicBlock *Succ,
|
|
uint64_t Count = 0,
|
|
uint64_t MispredictedCount = 0);
|
|
|
|
/// Add a range of successors.
|
|
template <typename Itr>
|
|
void addSuccessors(Itr Begin, Itr End) {
|
|
while (Begin != End) {
|
|
addSuccessor(*Begin++);
|
|
}
|
|
}
|
|
|
|
/// Add a range of successors with branch info.
|
|
template <typename Itr, typename BrItr>
|
|
void addSuccessors(Itr Begin, Itr End, BrItr BrBegin, BrItr BrEnd) {
|
|
assert(std::distance(Begin, End) == std::distance(BrBegin, BrEnd));
|
|
while (Begin != End) {
|
|
const auto BrInfo = *BrBegin++;
|
|
addSuccessor(*Begin++, BrInfo.Count, BrInfo.MispredictedCount);
|
|
}
|
|
}
|
|
|
|
/// Adds block to landing pad list.
|
|
void addLandingPad(BinaryBasicBlock *LPBlock);
|
|
|
|
/// Remove /p Succ basic block from the list of successors. Update the
|
|
/// list of predecessors of /p Succ and update branch info.
|
|
void removeSuccessor(BinaryBasicBlock *Succ);
|
|
|
|
/// Remove a range of successor blocks.
|
|
template <typename Itr>
|
|
void removeSuccessors(Itr Begin, Itr End) {
|
|
while (Begin != End) {
|
|
removeSuccessor(*Begin++);
|
|
}
|
|
}
|
|
|
|
/// Return the information about the number of times this basic block was
|
|
/// executed.
|
|
///
|
|
/// Return COUNT_NO_PROFILE if there's no profile info.
|
|
uint64_t getExecutionCount() const {
|
|
return ExecutionCount;
|
|
}
|
|
|
|
/// Set the execution count for this block.
|
|
void setExecutionCount(uint64_t Count) {
|
|
ExecutionCount = Count;
|
|
}
|
|
|
|
bool isCold() const {
|
|
return IsCold;
|
|
}
|
|
|
|
/// Return true if the block can be outlined. At the moment we disallow
|
|
/// outlining of blocks that can potentially throw exceptions or are
|
|
/// the beginning of a landing pad. The entry basic block also can
|
|
/// never be outlined.
|
|
bool canOutline() const {
|
|
return CanOutline;
|
|
}
|
|
|
|
bool eraseInstruction(MCInst *Inst) {
|
|
return replaceInstruction(Inst, std::vector<MCInst>());
|
|
}
|
|
|
|
/// Replace an instruction with a sequence of instructions. Returns true
|
|
/// if the instruction to be replaced was found and replaced.
|
|
template <typename Itr>
|
|
bool replaceInstruction(MCInst *Inst, Itr Begin, Itr End) {
|
|
auto I = Instructions.end();
|
|
auto B = Instructions.begin();
|
|
while (I > B) {
|
|
--I;
|
|
if (&*I == Inst) {
|
|
Instructions.insert(Instructions.erase(I), Begin, End);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool replaceInstruction(MCInst *Inst,
|
|
const std::vector<MCInst> &Replacement) {
|
|
return replaceInstruction(Inst, Replacement.begin(), Replacement.end());
|
|
}
|
|
|
|
/// Split apart the instructions in this basic block starting at Inst.
|
|
/// The instructions following Inst are removed and returned in a vector.
|
|
std::vector<MCInst> splitInstructions(const MCInst *Inst) {
|
|
std::vector<MCInst> SplitInst;
|
|
|
|
assert(!Instructions.empty());
|
|
while(&Instructions.back() != Inst) {
|
|
SplitInst.push_back(Instructions.back());
|
|
Instructions.pop_back();
|
|
}
|
|
std::reverse(SplitInst.begin(), SplitInst.end());
|
|
|
|
return SplitInst;
|
|
}
|
|
|
|
/// Sets the symbol pointing to the end of the BB in the output binary.
|
|
void setEndLabel(const MCSymbol *Symbol) {
|
|
EndLabel = Symbol;
|
|
}
|
|
|
|
/// Gets the symbol pointing to the end of the BB in the output binary.
|
|
const MCSymbol *getEndLabel() const {
|
|
return EndLabel;
|
|
}
|
|
|
|
/// Sets the memory address range of this BB in the output binary.
|
|
void setOutputAddressRange(std::pair<uint64_t, uint64_t> Range) {
|
|
OutputAddressRange = Range;
|
|
}
|
|
|
|
/// Gets the memory address range of this BB in the output binary.
|
|
std::pair<uint64_t, uint64_t> getOutputAddressRange() const {
|
|
return OutputAddressRange;
|
|
}
|
|
|
|
BinaryFunction *getFunction() const {
|
|
return Function;
|
|
}
|
|
|
|
/// Analyze and interpret the terminators of this basic block. TBB must be
|
|
/// initialized with the original fall-through for this BB.
|
|
bool analyzeBranch(const MCInstrAnalysis &MIA,
|
|
const MCSymbol *&TBB,
|
|
const MCSymbol *&FBB,
|
|
MCInst *&CondBranch,
|
|
MCInst *&UncondBranch);
|
|
|
|
/// Printer required for printing dominator trees.
|
|
void printAsOperand(raw_ostream &OS, bool PrintType = true) {
|
|
if (PrintType) {
|
|
OS << "basic block ";
|
|
}
|
|
OS << getName();
|
|
}
|
|
|
|
/// A simple dump function for debugging.
|
|
void dump(BinaryContext &BC) const;
|
|
|
|
private:
|
|
|
|
/// Adds predecessor to the BB. Most likely you don't need to call this.
|
|
void addPredecessor(BinaryBasicBlock *Pred);
|
|
|
|
/// Remove predecessor of the basic block. Don't use directly, instead
|
|
/// use removeSuccessor() funciton.
|
|
void removePredecessor(BinaryBasicBlock *Pred);
|
|
|
|
/// Set offset of the basic block from the function start.
|
|
void setOffset(uint64_t NewOffset) {
|
|
Offset = NewOffset;
|
|
}
|
|
};
|
|
|
|
bool operator<(const BinaryBasicBlock &LHS, const BinaryBasicBlock &RHS);
|
|
|
|
|
|
} // namespace bolt
|
|
|
|
|
|
// GraphTraits specializations for basic block graphs (CFGs)
|
|
template <> struct GraphTraits<bolt::BinaryBasicBlock *> {
|
|
typedef bolt::BinaryBasicBlock NodeType;
|
|
typedef bolt::BinaryBasicBlock::succ_iterator ChildIteratorType;
|
|
|
|
static NodeType *getEntryNode(bolt::BinaryBasicBlock *BB) { return BB; }
|
|
static inline ChildIteratorType child_begin(NodeType *N) {
|
|
return N->succ_begin();
|
|
}
|
|
static inline ChildIteratorType child_end(NodeType *N) {
|
|
return N->succ_end();
|
|
}
|
|
};
|
|
|
|
template <> struct GraphTraits<const bolt::BinaryBasicBlock *> {
|
|
typedef const bolt::BinaryBasicBlock NodeType;
|
|
typedef bolt::BinaryBasicBlock::const_succ_iterator ChildIteratorType;
|
|
|
|
static NodeType *getEntryNode(const bolt::BinaryBasicBlock *BB) {
|
|
return BB;
|
|
}
|
|
static inline ChildIteratorType child_begin(NodeType *N) {
|
|
return N->succ_begin();
|
|
}
|
|
static inline ChildIteratorType child_end(NodeType *N) {
|
|
return N->succ_end();
|
|
}
|
|
};
|
|
|
|
template <> struct GraphTraits<Inverse<bolt::BinaryBasicBlock *>> {
|
|
typedef bolt::BinaryBasicBlock NodeType;
|
|
typedef bolt::BinaryBasicBlock::pred_iterator ChildIteratorType;
|
|
static NodeType *getEntryNode(Inverse<bolt::BinaryBasicBlock *> G) {
|
|
return G.Graph;
|
|
}
|
|
static inline ChildIteratorType child_begin(NodeType *N) {
|
|
return N->pred_begin();
|
|
}
|
|
static inline ChildIteratorType child_end(NodeType *N) {
|
|
return N->pred_end();
|
|
}
|
|
};
|
|
|
|
template <> struct GraphTraits<Inverse<const bolt::BinaryBasicBlock *>> {
|
|
typedef const bolt::BinaryBasicBlock NodeType;
|
|
typedef bolt::BinaryBasicBlock::const_pred_iterator ChildIteratorType;
|
|
static NodeType *getEntryNode(Inverse<const bolt::BinaryBasicBlock *> G) {
|
|
return G.Graph;
|
|
}
|
|
static inline ChildIteratorType child_begin(NodeType *N) {
|
|
return N->pred_begin();
|
|
}
|
|
static inline ChildIteratorType child_end(NodeType *N) {
|
|
return N->pred_end();
|
|
}
|
|
};
|
|
|
|
|
|
} // namespace llvm
|
|
|
|
#endif
|