std::tie facilitates lexicographical comparisons through std::tuple's built-in operator<.
1021 lines
38 KiB
C++
1021 lines
38 KiB
C++
//===- bolt/Core/BinaryBasicBlock.h - Low-level basic block -----*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Sequence of MC/MCPlus instructions. Call/invoke does not terminate the block.
|
|
// CFI instructions are part of the instruction list with the initial CFI state
|
|
// defined at the beginning of the block.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef BOLT_CORE_BINARY_BASIC_BLOCK_H
|
|
#define BOLT_CORE_BINARY_BASIC_BLOCK_H
|
|
|
|
#include "bolt/Core/FunctionLayout.h"
|
|
#include "bolt/Core/MCPlus.h"
|
|
#include "llvm/ADT/GraphTraits.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
|
|
#include "llvm/MC/MCInst.h"
|
|
#include "llvm/MC/MCSymbol.h"
|
|
#include "llvm/Support/ErrorOr.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include <limits>
|
|
#include <utility>
|
|
|
|
namespace llvm {
|
|
class MCCodeEmitter;
|
|
|
|
namespace bolt {
|
|
|
|
class BinaryFunction;
|
|
class JumpTable;
|
|
|
|
class BinaryBasicBlock {
|
|
public:
|
|
/// Profile execution information for a given edge in CFG.
|
|
///
|
|
/// If MispredictedCount equals COUNT_INFERRED, then we have a profile
|
|
/// data for a fall-through edge with a Count representing an inferred
|
|
/// execution count, i.e. the count we calculated internally, not the one
|
|
/// coming from profile data.
|
|
///
|
|
/// For all other values of MispredictedCount, Count represents the number of
|
|
/// branch executions from a profile, and MispredictedCount is the number
|
|
/// of times the branch was mispredicted according to this profile.
|
|
struct BinaryBranchInfo {
|
|
uint64_t Count;
|
|
uint64_t MispredictedCount; /// number of branches mispredicted
|
|
|
|
bool operator<(const BinaryBranchInfo &Other) const {
|
|
return std::tie(Count, MispredictedCount) <
|
|
std::tie(Other.Count, Other.MispredictedCount);
|
|
}
|
|
};
|
|
|
|
static constexpr uint32_t INVALID_OFFSET =
|
|
std::numeric_limits<uint32_t>::max();
|
|
|
|
using BranchInfoType = SmallVector<BinaryBranchInfo, 0>;
|
|
|
|
private:
|
|
/// Vector of all instructions in the block.
|
|
InstructionListType Instructions;
|
|
|
|
/// CFG information.
|
|
using EdgeListType = SmallVector<BinaryBasicBlock *, 0>;
|
|
EdgeListType Predecessors;
|
|
EdgeListType Successors;
|
|
|
|
/// Each successor has a corresponding BranchInfo entry in the list.
|
|
BranchInfoType BranchInfo;
|
|
|
|
using ExceptionListType = SmallVector<BinaryBasicBlock *, 0>;
|
|
|
|
/// List of blocks that this landing pad is handling.
|
|
ExceptionListType Throwers;
|
|
|
|
/// List of blocks that can catch exceptions thrown by code in this block.
|
|
ExceptionListType LandingPads;
|
|
|
|
/// Function that owns this basic block.
|
|
BinaryFunction *Function;
|
|
|
|
/// Label associated with the block.
|
|
MCSymbol *Label{nullptr};
|
|
|
|
/// [Begin, End) address range for this block in the output binary.
|
|
std::pair<uint32_t, uint32_t> OutputAddressRange = {0, 0};
|
|
|
|
/// Original offset range of the basic block in the function.
|
|
std::pair<uint32_t, uint32_t> InputRange = {INVALID_OFFSET, INVALID_OFFSET};
|
|
|
|
/// Map input offset (from function start) of an instruction to an output
|
|
/// symbol. Enables writing BOLT address translation tables used for mapping
|
|
/// control transfer in the output binary back to the original binary.
|
|
using LocSymsTy = std::vector<std::pair<uint32_t, const MCSymbol *>>;
|
|
std::unique_ptr<LocSymsTy> LocSyms;
|
|
|
|
/// Alignment requirements for the block.
|
|
uint32_t Alignment{1};
|
|
|
|
/// Maximum number of bytes to use for alignment of the block.
|
|
uint32_t AlignmentMaxBytes{0};
|
|
|
|
/// Number of times this basic block was executed.
|
|
uint64_t ExecutionCount{COUNT_NO_PROFILE};
|
|
|
|
static constexpr unsigned InvalidIndex = ~0u;
|
|
|
|
/// Index to BasicBlocks vector in BinaryFunction.
|
|
unsigned Index{InvalidIndex};
|
|
|
|
/// Index in the current layout.
|
|
unsigned LayoutIndex{InvalidIndex};
|
|
|
|
/// Number of pseudo instructions in this block.
|
|
uint32_t NumPseudos{0};
|
|
|
|
/// CFI state at the entry to this basic block.
|
|
int32_t CFIState{-1};
|
|
|
|
/// In cases where the parent function has been split, FragmentNum > 0 means
|
|
/// this BB will be allocated in a fragment outside its parent function.
|
|
FragmentNum Fragment;
|
|
|
|
/// Indicates if the block could be outlined.
|
|
bool CanOutline{true};
|
|
|
|
/// Flag to indicate whether this block is valid or not. Invalid
|
|
/// blocks may contain out of date or incorrect information.
|
|
bool IsValid{true};
|
|
|
|
/// Last computed hash value.
|
|
mutable uint64_t Hash{0};
|
|
|
|
private:
|
|
BinaryBasicBlock() = delete;
|
|
BinaryBasicBlock(const BinaryBasicBlock &) = delete;
|
|
BinaryBasicBlock(const BinaryBasicBlock &&) = delete;
|
|
BinaryBasicBlock &operator=(const BinaryBasicBlock &) = delete;
|
|
BinaryBasicBlock &operator=(const BinaryBasicBlock &&) = delete;
|
|
|
|
explicit BinaryBasicBlock(BinaryFunction *Function, MCSymbol *Label)
|
|
: Function(Function), Label(Label) {
|
|
assert(Function && "Function must be non-null");
|
|
}
|
|
|
|
// Exclusively managed by BinaryFunction.
|
|
friend class BinaryFunction;
|
|
friend bool operator<(const BinaryBasicBlock &LHS,
|
|
const BinaryBasicBlock &RHS);
|
|
|
|
/// Assign new label to the basic block.
|
|
void setLabel(MCSymbol *Symbol) { Label = Symbol; }
|
|
|
|
public:
|
|
static constexpr uint64_t COUNT_INFERRED =
|
|
std::numeric_limits<uint64_t>::max();
|
|
static constexpr uint64_t COUNT_NO_PROFILE =
|
|
std::numeric_limits<uint64_t>::max();
|
|
|
|
// Instructions iterators.
|
|
using iterator = InstructionListType::iterator;
|
|
using const_iterator = InstructionListType::const_iterator;
|
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
|
|
|
bool empty() const { assert(hasInstructions());
|
|
return Instructions.empty(); }
|
|
size_t size() const { assert(hasInstructions());
|
|
return Instructions.size(); }
|
|
MCInst &front() { assert(hasInstructions());
|
|
return Instructions.front(); }
|
|
MCInst &back() { assert(hasInstructions());
|
|
return Instructions.back(); }
|
|
const MCInst &front() const { assert(hasInstructions());
|
|
return Instructions.front(); }
|
|
const MCInst &back() const { assert(hasInstructions());
|
|
return Instructions.back(); }
|
|
|
|
iterator begin() { assert(hasInstructions());
|
|
return Instructions.begin(); }
|
|
const_iterator begin() const { assert(hasInstructions());
|
|
return Instructions.begin(); }
|
|
iterator end () { assert(hasInstructions());
|
|
return Instructions.end(); }
|
|
const_iterator end () const { assert(hasInstructions());
|
|
return Instructions.end(); }
|
|
reverse_iterator rbegin() { assert(hasInstructions());
|
|
return Instructions.rbegin(); }
|
|
const_reverse_iterator rbegin() const { assert(hasInstructions());
|
|
return Instructions.rbegin(); }
|
|
reverse_iterator rend () { assert(hasInstructions());
|
|
return Instructions.rend(); }
|
|
const_reverse_iterator rend () const { assert(hasInstructions());
|
|
return Instructions.rend(); }
|
|
|
|
// CFG iterators.
|
|
using pred_iterator = EdgeListType::iterator;
|
|
using const_pred_iterator = EdgeListType::const_iterator;
|
|
using succ_iterator = EdgeListType::iterator;
|
|
using const_succ_iterator = EdgeListType::const_iterator;
|
|
using throw_iterator = decltype(Throwers)::iterator;
|
|
using const_throw_iterator = decltype(Throwers)::const_iterator;
|
|
using lp_iterator = decltype(LandingPads)::iterator;
|
|
using const_lp_iterator = decltype(LandingPads)::const_iterator;
|
|
|
|
using pred_reverse_iterator = std::reverse_iterator<pred_iterator>;
|
|
using const_pred_reverse_iterator =
|
|
std::reverse_iterator<const_pred_iterator>;
|
|
using succ_reverse_iterator = std::reverse_iterator<succ_iterator>;
|
|
using const_succ_reverse_iterator =
|
|
std::reverse_iterator<const_succ_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(); }
|
|
size_t pred_size() const {
|
|
return 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(); }
|
|
size_t succ_size() const {
|
|
return 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(); }
|
|
size_t throw_size() const {
|
|
return Throwers.size();
|
|
}
|
|
bool throw_empty() const { return Throwers.empty(); }
|
|
bool isLandingPad() 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(); }
|
|
size_t lp_size() const {
|
|
return LandingPads.size();
|
|
}
|
|
bool lp_empty() const { return LandingPads.empty(); }
|
|
|
|
inline iterator_range<iterator> instructions() {
|
|
assert(hasInstructions());
|
|
return iterator_range<iterator>(begin(), end());
|
|
}
|
|
inline iterator_range<const_iterator> instructions() const {
|
|
assert(hasInstructions());
|
|
return iterator_range<const_iterator>(begin(), end());
|
|
}
|
|
inline iterator_range<pred_iterator> predecessors() {
|
|
assert(hasCFG());
|
|
return iterator_range<pred_iterator>(pred_begin(), pred_end());
|
|
}
|
|
inline iterator_range<const_pred_iterator> predecessors() const {
|
|
assert(hasCFG());
|
|
return iterator_range<const_pred_iterator>(pred_begin(), pred_end());
|
|
}
|
|
inline iterator_range<succ_iterator> successors() {
|
|
assert(hasCFG());
|
|
return iterator_range<succ_iterator>(succ_begin(), succ_end());
|
|
}
|
|
inline iterator_range<const_succ_iterator> successors() const {
|
|
assert(hasCFG());
|
|
return iterator_range<const_succ_iterator>(succ_begin(), succ_end());
|
|
}
|
|
inline iterator_range<throw_iterator> throwers() {
|
|
assert(hasCFG());
|
|
return iterator_range<throw_iterator>(throw_begin(), throw_end());
|
|
}
|
|
inline iterator_range<const_throw_iterator> throwers() const {
|
|
assert(hasCFG());
|
|
return iterator_range<const_throw_iterator>(throw_begin(), throw_end());
|
|
}
|
|
inline iterator_range<lp_iterator> landing_pads() {
|
|
assert(hasCFG());
|
|
return iterator_range<lp_iterator>(lp_begin(), lp_end());
|
|
}
|
|
inline iterator_range<const_lp_iterator> landing_pads() const {
|
|
assert(hasCFG());
|
|
return iterator_range<const_lp_iterator>(lp_begin(), lp_end());
|
|
}
|
|
|
|
// BranchInfo iterators.
|
|
using branch_info_iterator = BranchInfoType::iterator;
|
|
using const_branch_info_iterator = BranchInfoType::const_iterator;
|
|
using branch_info_reverse_iterator =
|
|
std::reverse_iterator<branch_info_iterator>;
|
|
using const_branch_info_reverse_iterator =
|
|
std::reverse_iterator<const_branch_info_iterator>;
|
|
|
|
branch_info_iterator branch_info_begin() { return BranchInfo.begin(); }
|
|
branch_info_iterator branch_info_end() { return BranchInfo.end(); }
|
|
const_branch_info_iterator branch_info_begin() const {
|
|
return BranchInfo.begin();
|
|
}
|
|
const_branch_info_iterator branch_info_end() const {
|
|
return BranchInfo.end();
|
|
}
|
|
branch_info_reverse_iterator branch_info_rbegin() {
|
|
return BranchInfo.rbegin();
|
|
}
|
|
branch_info_reverse_iterator branch_info_rend() { return BranchInfo.rend(); }
|
|
const_branch_info_reverse_iterator branch_info_rbegin() const {
|
|
return BranchInfo.rbegin();
|
|
}
|
|
const_branch_info_reverse_iterator branch_info_rend() const {
|
|
return BranchInfo.rend();
|
|
}
|
|
|
|
size_t branch_info_size() const { return BranchInfo.size(); }
|
|
bool branch_info_empty() const { return BranchInfo.empty(); }
|
|
|
|
inline iterator_range<branch_info_iterator> branch_info() {
|
|
return iterator_range<branch_info_iterator>(BranchInfo.begin(),
|
|
BranchInfo.end());
|
|
}
|
|
inline iterator_range<const_branch_info_iterator> branch_info() const {
|
|
return iterator_range<const_branch_info_iterator>(BranchInfo.begin(),
|
|
BranchInfo.end());
|
|
}
|
|
|
|
/// Get instruction at given index.
|
|
MCInst &getInstructionAtIndex(unsigned Index) { return Instructions[Index]; }
|
|
|
|
const MCInst &getInstructionAtIndex(unsigned Index) const {
|
|
return Instructions[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 \p Label if \p Label != nullptr.
|
|
/// Returns nullptr if no such successor is found.
|
|
/// If the \p Label == nullptr and the block has only one successor then
|
|
/// return the successor.
|
|
BinaryBasicBlock *getSuccessor(const MCSymbol *Label = nullptr) const;
|
|
|
|
/// Return the related branch info as well as the successor.
|
|
BinaryBasicBlock *getSuccessor(const MCSymbol *Label,
|
|
BinaryBranchInfo &BI) const;
|
|
|
|
/// If the basic block ends with a conditional branch (possibly followed by
|
|
/// an unconditional branch) and thus has 2 successors, return a successor
|
|
/// corresponding to a jump condition which could be true or false.
|
|
/// Return nullptr if the basic block does not have a conditional jump.
|
|
BinaryBasicBlock *getConditionalSuccessor(bool Condition) {
|
|
if (succ_size() != 2)
|
|
return nullptr;
|
|
return Successors[Condition == true ? 0 : 1];
|
|
}
|
|
|
|
const BinaryBasicBlock *getConditionalSuccessor(bool Condition) const {
|
|
return const_cast<BinaryBasicBlock *>(this)->getConditionalSuccessor(
|
|
Condition);
|
|
}
|
|
|
|
/// Find the fallthrough successor for a block, or nullptr if there is
|
|
/// none.
|
|
BinaryBasicBlock *getFallthrough() {
|
|
if (succ_size() == 2)
|
|
return getConditionalSuccessor(false);
|
|
else
|
|
return getSuccessor();
|
|
}
|
|
|
|
const BinaryBasicBlock *getFallthrough() const {
|
|
return const_cast<BinaryBasicBlock *>(this)->getFallthrough();
|
|
}
|
|
|
|
/// Return branch info corresponding to a taken branch.
|
|
const BinaryBranchInfo &getTakenBranchInfo() const {
|
|
assert(BranchInfo.size() == 2 &&
|
|
"could only be called for blocks with 2 successors");
|
|
return BranchInfo[0];
|
|
};
|
|
|
|
/// Return branch info corresponding to a fall-through branch.
|
|
const BinaryBranchInfo &getFallthroughBranchInfo() const {
|
|
assert(BranchInfo.size() == 2 &&
|
|
"could only be called for blocks with 2 successors");
|
|
return BranchInfo[1];
|
|
};
|
|
|
|
/// Return branch info corresponding to an edge going to \p Succ basic block.
|
|
BinaryBranchInfo &getBranchInfo(const BinaryBasicBlock &Succ);
|
|
|
|
/// Return branch info corresponding to an edge going to \p Succ basic block.
|
|
const BinaryBranchInfo &getBranchInfo(const BinaryBasicBlock &Succ) const;
|
|
|
|
/// Set branch information for the outgoing edge to block \p Succ.
|
|
void setSuccessorBranchInfo(const BinaryBasicBlock &Succ, uint64_t Count,
|
|
uint64_t MispredictedCount) {
|
|
BinaryBranchInfo &BI = getBranchInfo(Succ);
|
|
BI.Count = Count;
|
|
BI.MispredictedCount = MispredictedCount;
|
|
}
|
|
|
|
/// Try to compute the taken and misprediction frequencies for the given
|
|
/// successor. The result is an error if no information can be found.
|
|
ErrorOr<std::pair<double, double>>
|
|
getBranchStats(const BinaryBasicBlock *Succ) const;
|
|
|
|
/// If the basic block ends with a conditional branch (possibly followed by
|
|
/// an unconditional branch) and thus has 2 successor, reverse the order of
|
|
/// its successors in CFG, update branch info, and return true. If the basic
|
|
/// block does not have 2 successors return false.
|
|
bool swapConditionalSuccessors();
|
|
|
|
/// Add an instruction with unconditional control transfer to \p Successor
|
|
/// basic block to the end of this basic block.
|
|
void addBranchInstruction(const BinaryBasicBlock *Successor);
|
|
|
|
/// Add an instruction with tail call control transfer to \p Target
|
|
/// to the end of this basic block.
|
|
void addTailCallInstruction(const MCSymbol *Target);
|
|
|
|
/// Return the number of call instructions in this basic block.
|
|
uint32_t getNumCalls() 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 iterator pointing to the inserted instruction.
|
|
iterator addInstruction(MCInst &&Inst) {
|
|
adjustNumPseudos(Inst, 1);
|
|
Instructions.emplace_back(Inst);
|
|
return std::prev(Instructions.end());
|
|
}
|
|
|
|
/// Add instruction at the end of this basic block.
|
|
/// Returns iterator pointing to the inserted instruction.
|
|
iterator addInstruction(const MCInst &Inst) {
|
|
adjustNumPseudos(Inst, 1);
|
|
Instructions.push_back(Inst);
|
|
return std::prev(Instructions.end());
|
|
}
|
|
|
|
/// 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 a range of instructions to the end of this basic block.
|
|
template <typename RangeTy> void addInstructions(RangeTy R) {
|
|
for (auto &I : R)
|
|
addInstruction(I);
|
|
}
|
|
|
|
/// Add instruction before Pos in this basic block.
|
|
template <typename Itr> Itr insertPseudoInstr(Itr Pos, MCInst &Instr) {
|
|
++NumPseudos;
|
|
return Instructions.insert(Pos, Instr);
|
|
}
|
|
|
|
/// Return the number of pseudo instructions in the basic block.
|
|
uint32_t getNumPseudos() const;
|
|
|
|
/// Return the number of emitted instructions for this basic block.
|
|
uint32_t getNumNonPseudos() const { return size() - getNumPseudos(); }
|
|
|
|
/// Return iterator to the first non-pseudo instruction or end()
|
|
/// if no such instruction was found.
|
|
iterator getFirstNonPseudo();
|
|
|
|
/// Return a pointer to the first non-pseudo instruction in this basic
|
|
/// block. Returns nullptr if none exists.
|
|
MCInst *getFirstNonPseudoInstr() {
|
|
auto II = getFirstNonPseudo();
|
|
return II == Instructions.end() ? nullptr : &*II;
|
|
}
|
|
|
|
/// Return reverse iterator to the last non-pseudo instruction or rend()
|
|
/// if no such instruction was found.
|
|
reverse_iterator getLastNonPseudo();
|
|
const_reverse_iterator getLastNonPseudo() const {
|
|
return const_cast<BinaryBasicBlock *>(this)->getLastNonPseudo();
|
|
}
|
|
|
|
/// Return a pointer to the last non-pseudo instruction in this basic
|
|
/// block. Returns nullptr if none exists.
|
|
MCInst *getLastNonPseudoInstr() {
|
|
auto RII = getLastNonPseudo();
|
|
return RII == Instructions.rend() ? nullptr : &*RII;
|
|
}
|
|
const MCInst *getLastNonPseudoInstr() const {
|
|
auto RII = getLastNonPseudo();
|
|
return RII == Instructions.rend() ? nullptr : &*RII;
|
|
}
|
|
|
|
/// Set CFI state at entry to this basic block.
|
|
void setCFIState(int32_t NewCFIState) {
|
|
assert((CFIState == -1 || NewCFIState == CFIState) &&
|
|
"unexpected change of CFI state for basic block");
|
|
CFIState = NewCFIState;
|
|
}
|
|
|
|
/// Return CFI state (expected) at entry of this basic block.
|
|
int32_t getCFIState() const {
|
|
assert(CFIState >= 0 && "unknown CFI state");
|
|
return CFIState;
|
|
}
|
|
|
|
/// Calculate and return CFI state right before instruction \p Instr in
|
|
/// this basic block. If \p Instr is nullptr then return the state at
|
|
/// the end of the basic block.
|
|
int32_t getCFIStateAtInstr(const MCInst *Instr) const;
|
|
|
|
/// Calculate and return CFI state after execution of this basic block.
|
|
/// The state depends on CFI state at entry and CFI instructions inside the
|
|
/// basic block.
|
|
int32_t getCFIStateAtExit() const { return getCFIStateAtInstr(nullptr); }
|
|
|
|
/// Set minimum alignment for the basic block.
|
|
void setAlignment(uint32_t Align) { Alignment = Align; }
|
|
|
|
/// Set alignment of the block based on the alignment of its offset.
|
|
void setDerivedAlignment() {
|
|
const uint64_t DerivedAlignment = getOffset() & (1 + ~getOffset());
|
|
Alignment = std::min(DerivedAlignment, uint64_t(32));
|
|
}
|
|
|
|
/// Return required alignment for the block.
|
|
Align getAlign() const { return Align(Alignment); }
|
|
uint32_t getAlignment() const { return Alignment; }
|
|
|
|
/// Set the maximum number of bytes to use for the block alignment.
|
|
void setAlignmentMaxBytes(uint32_t Value) { AlignmentMaxBytes = Value; }
|
|
|
|
/// Return the maximum number of bytes to use for the block alignment.
|
|
uint32_t getAlignmentMaxBytes() const { return AlignmentMaxBytes; }
|
|
|
|
/// 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);
|
|
|
|
void addSuccessor(BinaryBasicBlock *Succ, const BinaryBranchInfo &BI) {
|
|
addSuccessor(Succ, BI.Count, BI.MispredictedCount);
|
|
}
|
|
|
|
/// 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)
|
|
addSuccessor(*Begin++, *BrBegin++);
|
|
}
|
|
|
|
/// Replace Succ with NewSucc. This routine is helpful for preserving
|
|
/// the order of conditional successors when editing the CFG.
|
|
void replaceSuccessor(BinaryBasicBlock *Succ, BinaryBasicBlock *NewSucc,
|
|
uint64_t Count = 0, uint64_t MispredictedCount = 0);
|
|
|
|
/// Move all of this block's successors to a new block, and set the
|
|
/// execution count of this new block with our execution count. This is
|
|
/// useful when splitting a block in two.
|
|
void moveAllSuccessorsTo(BinaryBasicBlock *New) {
|
|
New->addSuccessors(successors().begin(), successors().end(),
|
|
branch_info_begin(), branch_info_end());
|
|
removeAllSuccessors();
|
|
|
|
// Update the execution count on the new block.
|
|
New->setExecutionCount(getExecutionCount());
|
|
}
|
|
|
|
/// 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 all successors of the basic block, and remove the block
|
|
/// from respective lists of predecessors.
|
|
void removeAllSuccessors();
|
|
|
|
/// Remove useless duplicate successors. When the conditional
|
|
/// successor is the same as the unconditional successor, we can
|
|
/// remove the conditional successor and branch instruction.
|
|
void removeDuplicateConditionalSuccessor(MCInst *CondBranch);
|
|
|
|
/// Update successors of the basic block based on the jump table instruction.
|
|
/// The block must end with a jump table instruction.
|
|
void updateJumpTableSuccessors();
|
|
|
|
/// Test if BB is a predecessor of this block.
|
|
bool isPredecessor(const BinaryBasicBlock *BB) const {
|
|
return llvm::is_contained(Predecessors, BB);
|
|
}
|
|
|
|
/// Test if BB is a successor of this block.
|
|
bool isSuccessor(const BinaryBasicBlock *BB) const {
|
|
return llvm::is_contained(Successors, BB);
|
|
}
|
|
|
|
/// Test if this BB has a valid execution count.
|
|
bool hasProfile() const { return ExecutionCount != COUNT_NO_PROFILE; }
|
|
|
|
/// 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; }
|
|
|
|
/// Return the execution count for blocks with known profile.
|
|
/// Return 0 if the block has no profile.
|
|
uint64_t getKnownExecutionCount() const {
|
|
return !hasProfile() ? 0 : ExecutionCount;
|
|
}
|
|
|
|
/// Set the execution count for this block.
|
|
void setExecutionCount(uint64_t Count) { ExecutionCount = Count; }
|
|
|
|
/// Apply a given \p Ratio to the profile information of this basic block.
|
|
void adjustExecutionCount(double Ratio);
|
|
|
|
/// Return true if the basic block is an entry point into the function
|
|
/// (either primary or secondary).
|
|
bool isEntryPoint() const;
|
|
|
|
bool isValid() const { return IsValid; }
|
|
|
|
void markValid(const bool Valid) { IsValid = Valid; }
|
|
|
|
FragmentNum getFragmentNum() const { return Fragment; }
|
|
|
|
void setFragmentNum(const FragmentNum Value) { Fragment = Value; }
|
|
|
|
bool isSplit() const { return Fragment != FragmentNum::main(); }
|
|
|
|
bool isCold() const {
|
|
assert(Fragment.get() < 2 &&
|
|
"Function is split into more than two (hot/cold)-fragments");
|
|
return isSplit();
|
|
}
|
|
|
|
void setIsCold(const bool Flag) {
|
|
Fragment = Flag ? FragmentNum::cold() : FragmentNum::main();
|
|
}
|
|
|
|
/// 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; }
|
|
|
|
void setCanOutline(const bool Flag) { CanOutline = Flag; }
|
|
|
|
/// Erase pseudo instruction at a given iterator.
|
|
/// Return iterator following the removed instruction.
|
|
iterator erasePseudoInstruction(iterator II) {
|
|
--NumPseudos;
|
|
return Instructions.erase(II);
|
|
}
|
|
|
|
/// Erase non-pseudo instruction at a given iterator \p II.
|
|
/// Return iterator following the removed instruction.
|
|
iterator eraseInstruction(iterator II) {
|
|
adjustNumPseudos(*II, -1);
|
|
return Instructions.erase(II);
|
|
}
|
|
|
|
/// Erase non-pseudo instruction at a given \p Index
|
|
void eraseInstructionAtIndex(unsigned Index) {
|
|
eraseInstruction(Instructions.begin() + Index);
|
|
}
|
|
|
|
/// Erase instructions in the specified range.
|
|
template <typename ItrType>
|
|
void eraseInstructions(ItrType Begin, ItrType End) {
|
|
while (End > Begin)
|
|
eraseInstruction(findInstruction(*--End));
|
|
}
|
|
|
|
/// Erase all instructions.
|
|
void clear() {
|
|
Instructions.clear();
|
|
NumPseudos = 0;
|
|
}
|
|
|
|
/// Retrieve iterator for \p Inst or return end iterator if instruction is not
|
|
/// from this basic block.
|
|
decltype(Instructions)::iterator findInstruction(const MCInst *Inst) {
|
|
if (Instructions.empty())
|
|
return Instructions.end();
|
|
size_t Index = Inst - &Instructions[0];
|
|
return Index >= Instructions.size() ? Instructions.end()
|
|
: Instructions.begin() + Index;
|
|
}
|
|
|
|
/// Replace instruction referenced by iterator \II with a sequence of
|
|
/// instructions defined by [\p Begin, \p End] range.
|
|
///
|
|
/// Return iterator pointing to the first inserted instruction.
|
|
template <typename Itr>
|
|
iterator replaceInstruction(iterator II, Itr Begin, Itr End) {
|
|
adjustNumPseudos(*II, -1);
|
|
adjustNumPseudos(Begin, End, 1);
|
|
|
|
auto I = II - Instructions.begin();
|
|
Instructions.insert(Instructions.erase(II), Begin, End);
|
|
return I + Instructions.begin();
|
|
}
|
|
|
|
iterator replaceInstruction(iterator II,
|
|
const InstructionListType &Replacement) {
|
|
return replaceInstruction(II, Replacement.begin(), Replacement.end());
|
|
}
|
|
|
|
/// Insert \p NewInst before \p At, which must be an existing instruction in
|
|
/// this BB. Return iterator pointing to the newly inserted instruction.
|
|
iterator insertInstruction(iterator At, MCInst &&NewInst) {
|
|
adjustNumPseudos(NewInst, 1);
|
|
return Instructions.emplace(At, std::move(NewInst));
|
|
}
|
|
|
|
iterator insertInstruction(iterator At, MCInst &NewInst) {
|
|
adjustNumPseudos(NewInst, 1);
|
|
return Instructions.insert(At, NewInst);
|
|
}
|
|
|
|
/// Helper to retrieve any terminators in \p BB before \p Pos. This is used
|
|
/// to skip CFI instructions and to retrieve the first terminator instruction
|
|
/// in basic blocks with two terminators (conditional jump and unconditional
|
|
/// jump).
|
|
MCInst *getTerminatorBefore(MCInst *Pos);
|
|
|
|
/// Used to identify whether an instruction is before a terminator and whether
|
|
/// moving it to the end of the BB would render it dead code.
|
|
bool hasTerminatorAfter(MCInst *Pos);
|
|
|
|
/// Split apart the instructions in this basic block starting at Inst.
|
|
/// The instructions following Inst are removed and returned in a vector.
|
|
InstructionListType splitInstructions(const MCInst *Inst) {
|
|
InstructionListType SplitInst;
|
|
|
|
assert(!Instructions.empty());
|
|
while (&Instructions.back() != Inst) {
|
|
SplitInst.push_back(Instructions.back());
|
|
Instructions.pop_back();
|
|
}
|
|
std::reverse(SplitInst.begin(), SplitInst.end());
|
|
NumPseudos = 0;
|
|
adjustNumPseudos(Instructions.begin(), Instructions.end(), 1);
|
|
return SplitInst;
|
|
}
|
|
|
|
/// Split basic block at the instruction pointed to by II.
|
|
/// All iterators pointing after II get invalidated.
|
|
///
|
|
/// Return the new basic block that starts with the instruction
|
|
/// at the split point.
|
|
BinaryBasicBlock *splitAt(iterator II);
|
|
|
|
/// Set start offset of this basic block in the input binary.
|
|
void setOffset(uint32_t Offset) { InputRange.first = Offset; };
|
|
|
|
/// Sets address of the basic block in the output.
|
|
void setOutputStartAddress(uint64_t Address) {
|
|
OutputAddressRange.first = Address;
|
|
}
|
|
|
|
/// Sets address past the end of the basic block in the output.
|
|
void setOutputEndAddress(uint64_t Address) {
|
|
OutputAddressRange.second = Address;
|
|
}
|
|
|
|
/// Gets the memory address range of this BB in the input binary.
|
|
std::pair<uint64_t, uint64_t> getInputAddressRange() const {
|
|
return InputRange;
|
|
}
|
|
|
|
/// Gets the memory address range of this BB in the output binary.
|
|
std::pair<uint64_t, uint64_t> getOutputAddressRange() const {
|
|
return OutputAddressRange;
|
|
}
|
|
|
|
uint64_t getOutputStartAddress() const { return OutputAddressRange.first; }
|
|
uint64_t getOutputEndAddress() const { return OutputAddressRange.second; }
|
|
|
|
bool hasLocSyms() const { return LocSyms != nullptr; }
|
|
|
|
/// Return mapping of input offsets to symbols in the output.
|
|
LocSymsTy &getLocSyms() {
|
|
return LocSyms ? *LocSyms : *(LocSyms = std::make_unique<LocSymsTy>());
|
|
}
|
|
|
|
/// Return mapping of input offsets to symbols in the output.
|
|
const LocSymsTy &getLocSyms() const {
|
|
return const_cast<BinaryBasicBlock *>(this)->getLocSyms();
|
|
}
|
|
|
|
/// Return size of the basic block in the output binary.
|
|
uint64_t getOutputSize() const {
|
|
return OutputAddressRange.second - OutputAddressRange.first;
|
|
}
|
|
|
|
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 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() const;
|
|
|
|
/// Validate successor invariants for this BB.
|
|
bool validateSuccessorInvariants();
|
|
|
|
/// Return offset of the basic block from the function start on input.
|
|
uint32_t getInputOffset() const { return InputRange.first; }
|
|
|
|
/// Return offset from the function start to location immediately past
|
|
/// the end of the basic block.
|
|
uint32_t getEndOffset() const { return InputRange.second; }
|
|
|
|
/// Return size of the basic block on input.
|
|
uint32_t getOriginalSize() const {
|
|
return InputRange.second - InputRange.first;
|
|
}
|
|
|
|
/// Returns an estimate of size of basic block during run time optionally
|
|
/// using a user-supplied emitter for lock-free multi-thread work.
|
|
/// MCCodeEmitter is not thread safe and each thread should operate with its
|
|
/// own copy of it.
|
|
uint64_t estimateSize(const MCCodeEmitter *Emitter = nullptr) const;
|
|
|
|
/// Return index in the current layout. The user is responsible for
|
|
/// making sure the indices are up to date,
|
|
/// e.g. by calling BinaryFunction::updateLayoutIndices();
|
|
unsigned getLayoutIndex() const {
|
|
assert(isValid());
|
|
return LayoutIndex;
|
|
}
|
|
|
|
/// Set layout index. To be used by BinaryFunction.
|
|
void setLayoutIndex(unsigned Index) { LayoutIndex = Index; }
|
|
|
|
/// Needed by graph traits.
|
|
BinaryFunction *getParent() const { return getFunction(); }
|
|
|
|
/// Return true if the containing function is in CFG state.
|
|
bool hasCFG() const;
|
|
|
|
/// Return true if the containing function is in a state with instructions.
|
|
bool hasInstructions() const;
|
|
|
|
/// Return offset of the basic block from the function start.
|
|
uint32_t getOffset() const { return InputRange.first; }
|
|
|
|
/// Get the index of this basic block.
|
|
unsigned getIndex() const {
|
|
assert(isValid());
|
|
return Index;
|
|
}
|
|
|
|
/// Return jump table if the block contains a jump table instruction or
|
|
/// nullptr otherwise.
|
|
const JumpTable *getJumpTable() const;
|
|
|
|
/// Check if the block has a jump table instruction.
|
|
bool hasJumpTable() const { return getJumpTable() != nullptr; }
|
|
|
|
/// Returns the last computed hash value of the block.
|
|
uint64_t getHash() const { return Hash; }
|
|
|
|
private:
|
|
void adjustNumPseudos(const MCInst &Inst, int Sign);
|
|
|
|
template <typename Itr> void adjustNumPseudos(Itr Begin, Itr End, int Sign) {
|
|
while (Begin != End)
|
|
adjustNumPseudos(*Begin++, Sign);
|
|
}
|
|
|
|
/// 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() function.
|
|
/// If \p Multiple is set to true, it will remove all predecessors that
|
|
/// are equal to \p Pred. Otherwise, the first instance of \p Pred found
|
|
/// will be removed. This only matters in awkward, redundant CFGs.
|
|
void removePredecessor(BinaryBasicBlock *Pred, bool Multiple = true);
|
|
|
|
/// Set end offset of this basic block.
|
|
void setEndOffset(uint32_t Offset) { InputRange.second = Offset; }
|
|
|
|
/// Set the index of this basic block.
|
|
void setIndex(unsigned I) { Index = I; }
|
|
|
|
/// Sets the hash value of the basic block.
|
|
void setHash(uint64_t Value) const { Hash = Value; }
|
|
|
|
template <typename T> void clearList(T &List) {
|
|
T TempList;
|
|
TempList.swap(List);
|
|
}
|
|
|
|
/// Release memory taken by CFG edges and instructions.
|
|
void releaseCFG() {
|
|
clearList(Predecessors);
|
|
clearList(Successors);
|
|
clearList(Throwers);
|
|
clearList(LandingPads);
|
|
clearList(BranchInfo);
|
|
clearList(Instructions);
|
|
}
|
|
};
|
|
|
|
#if defined(LLVM_ON_UNIX)
|
|
/// Keep the size of the BinaryBasicBlock within a reasonable size class
|
|
/// (jemalloc bucket) on Linux
|
|
static_assert(sizeof(BinaryBasicBlock) <= 256);
|
|
#endif
|
|
|
|
bool operator<(const BinaryBasicBlock &LHS, const BinaryBasicBlock &RHS);
|
|
|
|
} // namespace bolt
|
|
|
|
// GraphTraits specializations for basic block graphs (CFGs)
|
|
template <> struct GraphTraits<bolt::BinaryBasicBlock *> {
|
|
using NodeRef = bolt::BinaryBasicBlock *;
|
|
using ChildIteratorType = bolt::BinaryBasicBlock::succ_iterator;
|
|
|
|
static NodeRef getEntryNode(bolt::BinaryBasicBlock *BB) { return BB; }
|
|
static inline ChildIteratorType child_begin(NodeRef N) {
|
|
return N->succ_begin();
|
|
}
|
|
static inline ChildIteratorType child_end(NodeRef N) { return N->succ_end(); }
|
|
};
|
|
|
|
template <> struct GraphTraits<const bolt::BinaryBasicBlock *> {
|
|
using NodeRef = const bolt::BinaryBasicBlock *;
|
|
using ChildIteratorType = bolt::BinaryBasicBlock::const_succ_iterator;
|
|
|
|
static NodeRef getEntryNode(const bolt::BinaryBasicBlock *BB) { return BB; }
|
|
static inline ChildIteratorType child_begin(NodeRef N) {
|
|
return N->succ_begin();
|
|
}
|
|
static inline ChildIteratorType child_end(NodeRef N) { return N->succ_end(); }
|
|
};
|
|
|
|
template <> struct GraphTraits<Inverse<bolt::BinaryBasicBlock *>> {
|
|
using NodeRef = bolt::BinaryBasicBlock *;
|
|
using ChildIteratorType = bolt::BinaryBasicBlock::pred_iterator;
|
|
static NodeRef getEntryNode(Inverse<bolt::BinaryBasicBlock *> G) {
|
|
return G.Graph;
|
|
}
|
|
static inline ChildIteratorType child_begin(NodeRef N) {
|
|
return N->pred_begin();
|
|
}
|
|
static inline ChildIteratorType child_end(NodeRef N) { return N->pred_end(); }
|
|
};
|
|
|
|
template <> struct GraphTraits<Inverse<const bolt::BinaryBasicBlock *>> {
|
|
using NodeRef = const bolt::BinaryBasicBlock *;
|
|
using ChildIteratorType = bolt::BinaryBasicBlock::const_pred_iterator;
|
|
static NodeRef getEntryNode(Inverse<const bolt::BinaryBasicBlock *> G) {
|
|
return G.Graph;
|
|
}
|
|
static inline ChildIteratorType child_begin(NodeRef N) {
|
|
return N->pred_begin();
|
|
}
|
|
static inline ChildIteratorType child_end(NodeRef N) { return N->pred_end(); }
|
|
};
|
|
|
|
} // namespace llvm
|
|
|
|
#endif
|