mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-15 04:30:12 +00:00
de1c9bb450
introduce no-return or unreachable heuristics. The return heuristics from the Ball and Larus paper don't work well in practice as they pessimize early return paths. The only good hitrate return heuristics are those for: - NULL return - Constant return - negative integer return Only the last of these three can possibly require significant code for the returning block, and even the last is fairly rare and usually also a constant. As a consequence, even for the cold return paths, there is little code on that return path, and so little code density to be gained by sinking it. The places where sinking these blocks is valuable (inner loops) will already be weighted appropriately as the edge is a loop-exit branch. All of this aside, early returns are nearly as common as all three of these return categories, and should actually be predicted as taken! Rather than muddy the waters of the static predictions, just remain silent on returns and let the CFG itself dictate any layout or other issues. However, the return heuristic was flagging one very important case: unreachable. Unfortunately it still gave a 1/4 chance of the branch-to-unreachable occuring. It also didn't do a rigorous job of finding those blocks which post-dominate an unreachable block. This patch builds a more powerful analysis that should flag all branches to blocks known to then reach unreachable. It also has better worst-case runtime complexity by not looping through successors for each block. The previous code would perform an N^2 walk in the event of a single entry block branching to N successors with a switch where each successor falls through to the next and they finally fall through to a return. Test case added for noreturn heuristics. Also doxygen comments improved along the way. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@142793 91177308-0d34-0410-b5e6-96231b3b80d8
130 lines
5.2 KiB
C++
130 lines
5.2 KiB
C++
//===--- BranchProbabilityInfo.h - Branch Probability Analysis --*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This pass is used to evaluate branch probabilties.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_ANALYSIS_BRANCHPROBABILITYINFO_H
|
|
#define LLVM_ANALYSIS_BRANCHPROBABILITYINFO_H
|
|
|
|
#include "llvm/InitializePasses.h"
|
|
#include "llvm/Pass.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
#include "llvm/Support/BranchProbability.h"
|
|
|
|
namespace llvm {
|
|
class LoopInfo;
|
|
class raw_ostream;
|
|
|
|
/// \brief Analysis pass providing branch probability information.
|
|
///
|
|
/// This is a function analysis pass which provides information on the relative
|
|
/// probabilities of each "edge" in the function's CFG where such an edge is
|
|
/// defined by a pair of basic blocks. The probability for a given block and
|
|
/// a successor block are always relative to the probabilities of the other
|
|
/// successor blocks. Another way of looking at it is that the probabilities
|
|
/// for a given block B and each of its successors should sum to exactly
|
|
/// one (100%).
|
|
class BranchProbabilityInfo : public FunctionPass {
|
|
public:
|
|
static char ID;
|
|
|
|
BranchProbabilityInfo() : FunctionPass(ID) {
|
|
initializeBranchProbabilityInfoPass(*PassRegistry::getPassRegistry());
|
|
}
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const;
|
|
bool runOnFunction(Function &F);
|
|
void print(raw_ostream &OS, const Module *M = 0) const;
|
|
|
|
/// \brief Get an edge's probability, relative to other out-edges of the Src.
|
|
///
|
|
/// This routine provides access to the fractional probability between zero
|
|
/// (0%) and one (100%) of this edge executing, relative to other edges
|
|
/// leaving the 'Src' block. The returned probability is never zero, and can
|
|
/// only be one if the source block has only one successor.
|
|
BranchProbability getEdgeProbability(const BasicBlock *Src,
|
|
const BasicBlock *Dst) const;
|
|
|
|
/// \brief Test if an edge is hot relative to other out-edges of the Src.
|
|
///
|
|
/// Check whether this edge out of the source block is 'hot'. We define hot
|
|
/// as having a relative probability >= 80%.
|
|
bool isEdgeHot(const BasicBlock *Src, const BasicBlock *Dst) const;
|
|
|
|
/// \brief Retrieve the hot successor of a block if one exists.
|
|
///
|
|
/// Given a basic block, look through its successors and if one exists for
|
|
/// which \see isEdgeHot would return true, return that successor block.
|
|
BasicBlock *getHotSucc(BasicBlock *BB) const;
|
|
|
|
/// \brief Print an edge's probability.
|
|
///
|
|
/// Retrieves an edge's probability similarly to \see getEdgeProbability, but
|
|
/// then prints that probability to the provided stream. That stream is then
|
|
/// returned.
|
|
raw_ostream &printEdgeProbability(raw_ostream &OS, const BasicBlock *Src,
|
|
const BasicBlock *Dst) const;
|
|
|
|
/// \brief Get the raw edge weight calculated for the block pair.
|
|
///
|
|
/// This returns the raw edge weight. It is guaranteed to fall between 1 and
|
|
/// UINT32_MAX. Note that the raw edge weight is not meaningful in isolation.
|
|
/// This interface should be very carefully, and primarily by routines that
|
|
/// are updating the analysis by later calling setEdgeWeight.
|
|
uint32_t getEdgeWeight(const BasicBlock *Src, const BasicBlock *Dst) const;
|
|
|
|
/// \brief Set the raw edge weight for the block pair.
|
|
///
|
|
/// This allows a pass to explicitly set the edge weight for a block. It can
|
|
/// be used when updating the CFG to update and preserve the branch
|
|
/// probability information. Read the implementation of how these edge
|
|
/// weights are calculated carefully before using!
|
|
void setEdgeWeight(const BasicBlock *Src, const BasicBlock *Dst,
|
|
uint32_t Weight);
|
|
|
|
private:
|
|
typedef std::pair<const BasicBlock *, const BasicBlock *> Edge;
|
|
|
|
// Default weight value. Used when we don't have information about the edge.
|
|
// TODO: DEFAULT_WEIGHT makes sense during static predication, when none of
|
|
// the successors have a weight yet. But it doesn't make sense when providing
|
|
// weight to an edge that may have siblings with non-zero weights. This can
|
|
// be handled various ways, but it's probably fine for an edge with unknown
|
|
// weight to just "inherit" the non-zero weight of an adjacent successor.
|
|
static const uint32_t DEFAULT_WEIGHT = 16;
|
|
|
|
DenseMap<Edge, uint32_t> Weights;
|
|
|
|
/// \brief Handle to the LoopInfo analysis.
|
|
LoopInfo *LI;
|
|
|
|
/// \brief Track the last function we run over for printing.
|
|
Function *LastF;
|
|
|
|
/// \brief Track the set of blocks directly succeeded by a returning block.
|
|
SmallPtrSet<BasicBlock *, 16> PostDominatedByUnreachable;
|
|
|
|
/// \brief Get sum of the block successors' weights.
|
|
uint32_t getSumForBlock(const BasicBlock *BB) const;
|
|
|
|
bool calcUnreachableHeuristics(BasicBlock *BB);
|
|
bool calcMetadataWeights(BasicBlock *BB);
|
|
bool calcPointerHeuristics(BasicBlock *BB);
|
|
bool calcLoopBranchHeuristics(BasicBlock *BB);
|
|
bool calcZeroHeuristics(BasicBlock *BB);
|
|
bool calcFloatingPointHeuristics(BasicBlock *BB);
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|