mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
fffdcaf76a
These checks are not specific to the instruction based variant of isPotentiallyReachable(), they are equally valid for the basic block based variant. Move them there, to make sure that switching between the instruction and basic block variants cannot introduce regressions.
180 lines
7.8 KiB
C++
180 lines
7.8 KiB
C++
//===-- Analysis/CFG.h - BasicBlock Analyses --------------------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This family of functions performs analyses on basic blocks, and instructions
|
|
// contained within basic blocks.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_ANALYSIS_CFG_H
|
|
#define LLVM_ANALYSIS_CFG_H
|
|
|
|
#include "llvm/ADT/GraphTraits.h"
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
#include <utility>
|
|
|
|
namespace llvm {
|
|
|
|
class BasicBlock;
|
|
class DominatorTree;
|
|
class Function;
|
|
class Instruction;
|
|
class LoopInfo;
|
|
template <typename T> class SmallVectorImpl;
|
|
|
|
/// Analyze the specified function to find all of the loop backedges in the
|
|
/// function and return them. This is a relatively cheap (compared to
|
|
/// computing dominators and loop info) analysis.
|
|
///
|
|
/// The output is added to Result, as pairs of <from,to> edge info.
|
|
void FindFunctionBackedges(
|
|
const Function &F,
|
|
SmallVectorImpl<std::pair<const BasicBlock *, const BasicBlock *> > &
|
|
Result);
|
|
|
|
/// Search for the specified successor of basic block BB and return its position
|
|
/// in the terminator instruction's list of successors. It is an error to call
|
|
/// this with a block that is not a successor.
|
|
unsigned GetSuccessorNumber(const BasicBlock *BB, const BasicBlock *Succ);
|
|
|
|
/// Return true if the specified edge is a critical edge. Critical edges are
|
|
/// edges from a block with multiple successors to a block with multiple
|
|
/// predecessors.
|
|
///
|
|
bool isCriticalEdge(const Instruction *TI, unsigned SuccNum,
|
|
bool AllowIdenticalEdges = false);
|
|
bool isCriticalEdge(const Instruction *TI, const BasicBlock *Succ,
|
|
bool AllowIdenticalEdges = false);
|
|
|
|
/// Determine whether instruction 'To' is reachable from 'From', without passing
|
|
/// through any blocks in ExclusionSet, returning true if uncertain.
|
|
///
|
|
/// Determine whether there is a path from From to To within a single function.
|
|
/// Returns false only if we can prove that once 'From' has been executed then
|
|
/// 'To' can not be executed. Conservatively returns true.
|
|
///
|
|
/// This function is linear with respect to the number of blocks in the CFG,
|
|
/// walking down successors from From to reach To, with a fixed threshold.
|
|
/// Using DT or LI allows us to answer more quickly. LI reduces the cost of
|
|
/// an entire loop of any number of blocks to be the same as the cost of a
|
|
/// single block. DT reduces the cost by allowing the search to terminate when
|
|
/// we find a block that dominates the block containing 'To'. DT is most useful
|
|
/// on branchy code but not loops, and LI is most useful on code with loops but
|
|
/// does not help on branchy code outside loops.
|
|
bool isPotentiallyReachable(
|
|
const Instruction *From, const Instruction *To,
|
|
const SmallPtrSetImpl<BasicBlock *> *ExclusionSet = nullptr,
|
|
const DominatorTree *DT = nullptr, const LoopInfo *LI = nullptr);
|
|
|
|
/// Determine whether block 'To' is reachable from 'From', returning
|
|
/// true if uncertain.
|
|
///
|
|
/// Determine whether there is a path from From to To within a single function.
|
|
/// Returns false only if we can prove that once 'From' has been reached then
|
|
/// 'To' can not be executed. Conservatively returns true.
|
|
bool isPotentiallyReachable(
|
|
const BasicBlock *From, const BasicBlock *To,
|
|
const SmallPtrSetImpl<BasicBlock *> *ExclusionSet = nullptr,
|
|
const DominatorTree *DT = nullptr, const LoopInfo *LI = nullptr);
|
|
|
|
/// Determine whether there is at least one path from a block in
|
|
/// 'Worklist' to 'StopBB', returning true if uncertain.
|
|
///
|
|
/// Determine whether there is a path from at least one block in Worklist to
|
|
/// StopBB within a single function. Returns false only if we can prove that
|
|
/// once any block in 'Worklist' has been reached then 'StopBB' can not be
|
|
/// executed. Conservatively returns true.
|
|
bool isPotentiallyReachableFromMany(SmallVectorImpl<BasicBlock *> &Worklist,
|
|
BasicBlock *StopBB,
|
|
const DominatorTree *DT = nullptr,
|
|
const LoopInfo *LI = nullptr);
|
|
|
|
/// Determine whether there is at least one path from a block in
|
|
/// 'Worklist' to 'StopBB' without passing through any blocks in
|
|
/// 'ExclusionSet', returning true if uncertain.
|
|
///
|
|
/// Determine whether there is a path from at least one block in Worklist to
|
|
/// StopBB within a single function without passing through any of the blocks
|
|
/// in 'ExclusionSet'. Returns false only if we can prove that once any block
|
|
/// in 'Worklist' has been reached then 'StopBB' can not be executed.
|
|
/// Conservatively returns true.
|
|
bool isPotentiallyReachableFromMany(
|
|
SmallVectorImpl<BasicBlock *> &Worklist, BasicBlock *StopBB,
|
|
const SmallPtrSetImpl<BasicBlock *> *ExclusionSet,
|
|
const DominatorTree *DT = nullptr, const LoopInfo *LI = nullptr);
|
|
|
|
/// Return true if the control flow in \p RPOTraversal is irreducible.
|
|
///
|
|
/// This is a generic implementation to detect CFG irreducibility based on loop
|
|
/// info analysis. It can be used for any kind of CFG (Loop, MachineLoop,
|
|
/// Function, MachineFunction, etc.) by providing an RPO traversal (\p
|
|
/// RPOTraversal) and the loop info analysis (\p LI) of the CFG. This utility
|
|
/// function is only recommended when loop info analysis is available. If loop
|
|
/// info analysis isn't available, please, don't compute it explicitly for this
|
|
/// purpose. There are more efficient ways to detect CFG irreducibility that
|
|
/// don't require recomputing loop info analysis (e.g., T1/T2 or Tarjan's
|
|
/// algorithm).
|
|
///
|
|
/// Requirements:
|
|
/// 1) GraphTraits must be implemented for NodeT type. It is used to access
|
|
/// NodeT successors.
|
|
// 2) \p RPOTraversal must be a valid reverse post-order traversal of the
|
|
/// target CFG with begin()/end() iterator interfaces.
|
|
/// 3) \p LI must be a valid LoopInfoBase that contains up-to-date loop
|
|
/// analysis information of the CFG.
|
|
///
|
|
/// This algorithm uses the information about reducible loop back-edges already
|
|
/// computed in \p LI. When a back-edge is found during the RPO traversal, the
|
|
/// algorithm checks whether the back-edge is one of the reducible back-edges in
|
|
/// loop info. If it isn't, the CFG is irreducible. For example, for the CFG
|
|
/// below (canonical irreducible graph) loop info won't contain any loop, so the
|
|
/// algorithm will return that the CFG is irreducible when checking the B <-
|
|
/// -> C back-edge.
|
|
///
|
|
/// (A->B, A->C, B->C, C->B, C->D)
|
|
/// A
|
|
/// / \
|
|
/// B<- ->C
|
|
/// |
|
|
/// D
|
|
///
|
|
template <class NodeT, class RPOTraversalT, class LoopInfoT,
|
|
class GT = GraphTraits<NodeT>>
|
|
bool containsIrreducibleCFG(RPOTraversalT &RPOTraversal, const LoopInfoT &LI) {
|
|
/// Check whether the edge (\p Src, \p Dst) is a reducible loop backedge
|
|
/// according to LI. I.e., check if there exists a loop that contains Src and
|
|
/// where Dst is the loop header.
|
|
auto isProperBackedge = [&](NodeT Src, NodeT Dst) {
|
|
for (const auto *Lp = LI.getLoopFor(Src); Lp; Lp = Lp->getParentLoop()) {
|
|
if (Lp->getHeader() == Dst)
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
SmallPtrSet<NodeT, 32> Visited;
|
|
for (NodeT Node : RPOTraversal) {
|
|
Visited.insert(Node);
|
|
for (NodeT Succ : make_range(GT::child_begin(Node), GT::child_end(Node))) {
|
|
// Succ hasn't been visited yet
|
|
if (!Visited.count(Succ))
|
|
continue;
|
|
// We already visited Succ, thus Node->Succ must be a backedge. Check that
|
|
// the head matches what we have in the loop information. Otherwise, we
|
|
// have an irreducible graph.
|
|
if (!isProperBackedge(Node, Succ))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
} // End llvm namespace
|
|
|
|
#endif
|