#include "llvm/Analysis/LazyCallGraph.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#ifdef EXPENSIVE_CHECKS
#include "llvm/ADT/ScopeExit.h"
#endif
usingnamespacellvm;
#define DEBUG_TYPE …
void LazyCallGraph::EdgeSequence::insertEdgeInternal(Node &TargetN,
Edge::Kind EK) { … }
void LazyCallGraph::EdgeSequence::setEdgeKind(Node &TargetN, Edge::Kind EK) { … }
bool LazyCallGraph::EdgeSequence::removeEdgeInternal(Node &TargetN) { … }
static void addEdge(SmallVectorImpl<LazyCallGraph::Edge> &Edges,
DenseMap<LazyCallGraph::Node *, int> &EdgeIndexMap,
LazyCallGraph::Node &N, LazyCallGraph::Edge::Kind EK) { … }
LazyCallGraph::EdgeSequence &LazyCallGraph::Node::populateSlow() { … }
void LazyCallGraph::Node::replaceFunction(Function &NewF) { … }
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void LazyCallGraph::Node::dump() const {
dbgs() << *this << '\n';
}
#endif
static bool isKnownLibFunction(Function &F, TargetLibraryInfo &TLI) { … }
LazyCallGraph::LazyCallGraph(
Module &M, function_ref<TargetLibraryInfo &(Function &)> GetTLI) { … }
LazyCallGraph::LazyCallGraph(LazyCallGraph &&G)
: … { … }
#if !defined(NDEBUG) || defined(EXPENSIVE_CHECKS)
void LazyCallGraph::verify() {
for (RefSCC &RC : postorder_ref_sccs()) {
RC.verify();
}
}
#endif
bool LazyCallGraph::invalidate(Module &, const PreservedAnalyses &PA,
ModuleAnalysisManager::Invalidator &) { … }
LazyCallGraph &LazyCallGraph::operator=(LazyCallGraph &&G) { … }
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void LazyCallGraph::SCC::dump() const {
dbgs() << *this << '\n';
}
#endif
#if !defined(NDEBUG) || defined(EXPENSIVE_CHECKS)
void LazyCallGraph::SCC::verify() {
assert(OuterRefSCC && "Can't have a null RefSCC!");
assert(!Nodes.empty() && "Can't have an empty SCC!");
for (Node *N : Nodes) {
assert(N && "Can't have a null node!");
assert(OuterRefSCC->G->lookupSCC(*N) == this &&
"Node does not map to this SCC!");
assert(N->DFSNumber == -1 &&
"Must set DFS numbers to -1 when adding a node to an SCC!");
assert(N->LowLink == -1 &&
"Must set low link to -1 when adding a node to an SCC!");
for (Edge &E : **N)
assert(E.getNode().isPopulated() && "Can't have an unpopulated node!");
#ifdef EXPENSIVE_CHECKS
SmallVector<Node *, 4> Worklist;
SmallPtrSet<Node *, 4> Visited;
Worklist.push_back(N);
while (!Worklist.empty()) {
Node *VisitingNode = Worklist.pop_back_val();
if (!Visited.insert(VisitingNode).second)
continue;
for (Edge &E : (*VisitingNode)->calls())
Worklist.push_back(&E.getNode());
}
for (Node *NodeToVisit : Nodes) {
assert(Visited.contains(NodeToVisit) &&
"Cannot reach all nodes within SCC");
}
#endif
}
}
#endif
bool LazyCallGraph::SCC::isParentOf(const SCC &C) const { … }
bool LazyCallGraph::SCC::isAncestorOf(const SCC &TargetC) const { … }
LazyCallGraph::RefSCC::RefSCC(LazyCallGraph &G) : … { … }
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void LazyCallGraph::RefSCC::dump() const {
dbgs() << *this << '\n';
}
#endif
#if !defined(NDEBUG) || defined(EXPENSIVE_CHECKS)
void LazyCallGraph::RefSCC::verify() {
assert(G && "Can't have a null graph!");
assert(!SCCs.empty() && "Can't have an empty SCC!");
SmallPtrSet<SCC *, 4> SCCSet;
for (SCC *C : SCCs) {
assert(C && "Can't have a null SCC!");
C->verify();
assert(&C->getOuterRefSCC() == this &&
"SCC doesn't think it is inside this RefSCC!");
bool Inserted = SCCSet.insert(C).second;
assert(Inserted && "Found a duplicate SCC!");
auto IndexIt = SCCIndices.find(C);
assert(IndexIt != SCCIndices.end() &&
"Found an SCC that doesn't have an index!");
}
for (auto [C, I] : SCCIndices) {
assert(C && "Can't have a null SCC in the indices!");
assert(SCCSet.count(C) && "Found an index for an SCC not in the RefSCC!");
assert(SCCs[I] == C && "Index doesn't point to SCC!");
}
for (int I = 0, Size = SCCs.size(); I < Size; ++I) {
SCC &SourceSCC = *SCCs[I];
for (Node &N : SourceSCC)
for (Edge &E : *N) {
if (!E.isCall())
continue;
SCC &TargetSCC = *G->lookupSCC(E.getNode());
if (&TargetSCC.getOuterRefSCC() == this) {
assert(SCCIndices.find(&TargetSCC)->second <= I &&
"Edge between SCCs violates post-order relationship.");
continue;
}
}
}
#ifdef EXPENSIVE_CHECKS
SmallVector<Node *> Nodes;
for (SCC *C : SCCs) {
for (Node &N : *C)
Nodes.push_back(&N);
}
for (Node *N : Nodes) {
SmallVector<Node *, 4> Worklist;
SmallPtrSet<Node *, 4> Visited;
Worklist.push_back(N);
while (!Worklist.empty()) {
Node *VisitingNode = Worklist.pop_back_val();
if (!Visited.insert(VisitingNode).second)
continue;
for (Edge &E : **VisitingNode)
Worklist.push_back(&E.getNode());
}
for (Node *NodeToVisit : Nodes) {
assert(Visited.contains(NodeToVisit) &&
"Cannot reach all nodes within RefSCC");
}
}
#endif
}
#endif
bool LazyCallGraph::RefSCC::isParentOf(const RefSCC &RC) const { … }
bool LazyCallGraph::RefSCC::isAncestorOf(const RefSCC &RC) const { … }
template <typename SCCT, typename PostorderSequenceT, typename SCCIndexMapT,
typename ComputeSourceConnectedSetCallableT,
typename ComputeTargetConnectedSetCallableT>
static iterator_range<typename PostorderSequenceT::iterator>
updatePostorderSequenceForEdgeInsertion(
SCCT &SourceSCC, SCCT &TargetSCC, PostorderSequenceT &SCCs,
SCCIndexMapT &SCCIndices,
ComputeSourceConnectedSetCallableT ComputeSourceConnectedSet,
ComputeTargetConnectedSetCallableT ComputeTargetConnectedSet) { … }
bool LazyCallGraph::RefSCC::switchInternalEdgeToCall(
Node &SourceN, Node &TargetN,
function_ref<void(ArrayRef<SCC *> MergeSCCs)> MergeCB) { … }
void LazyCallGraph::RefSCC::switchTrivialInternalEdgeToRef(Node &SourceN,
Node &TargetN) { … }
iterator_range<LazyCallGraph::RefSCC::iterator>
LazyCallGraph::RefSCC::switchInternalEdgeToRef(Node &SourceN, Node &TargetN) { … }
void LazyCallGraph::RefSCC::switchOutgoingEdgeToCall(Node &SourceN,
Node &TargetN) { … }
void LazyCallGraph::RefSCC::switchOutgoingEdgeToRef(Node &SourceN,
Node &TargetN) { … }
void LazyCallGraph::RefSCC::insertInternalRefEdge(Node &SourceN,
Node &TargetN) { … }
void LazyCallGraph::RefSCC::insertOutgoingEdge(Node &SourceN, Node &TargetN,
Edge::Kind EK) { … }
SmallVector<LazyCallGraph::RefSCC *, 1>
LazyCallGraph::RefSCC::insertIncomingRefEdge(Node &SourceN, Node &TargetN) { … }
void LazyCallGraph::RefSCC::removeOutgoingEdge(Node &SourceN, Node &TargetN) { … }
SmallVector<LazyCallGraph::RefSCC *, 1>
LazyCallGraph::RefSCC::removeInternalRefEdges(
ArrayRef<std::pair<Node *, Node *>> Edges) { … }
void LazyCallGraph::RefSCC::insertTrivialCallEdge(Node &SourceN,
Node &TargetN) { … }
void LazyCallGraph::RefSCC::insertTrivialRefEdge(Node &SourceN, Node &TargetN) { … }
void LazyCallGraph::RefSCC::replaceNodeFunction(Node &N, Function &NewF) { … }
void LazyCallGraph::insertEdge(Node &SourceN, Node &TargetN, Edge::Kind EK) { … }
void LazyCallGraph::removeEdge(Node &SourceN, Node &TargetN) { … }
void LazyCallGraph::markDeadFunction(Function &F) { … }
void LazyCallGraph::removeDeadFunctions(ArrayRef<Function *> DeadFs) { … }
static LazyCallGraph::Edge::Kind getEdgeKind(Function &OriginalFunction,
Function &NewFunction) { … }
void LazyCallGraph::addSplitFunction(Function &OriginalFunction,
Function &NewFunction) { … }
void LazyCallGraph::addSplitRefRecursiveFunctions(
Function &OriginalFunction, ArrayRef<Function *> NewFunctions) { … }
LazyCallGraph::Node &LazyCallGraph::insertInto(Function &F, Node *&MappedN) { … }
void LazyCallGraph::updateGraphPtrs() { … }
LazyCallGraph::Node &LazyCallGraph::initNode(Function &F) { … }
template <typename RootsT, typename GetBeginT, typename GetEndT,
typename GetNodeT, typename FormSCCCallbackT>
void LazyCallGraph::buildGenericSCCs(RootsT &&Roots, GetBeginT &&GetBegin,
GetEndT &&GetEnd, GetNodeT &&GetNode,
FormSCCCallbackT &&FormSCC) { … }
void LazyCallGraph::buildSCCs(RefSCC &RC, node_stack_range Nodes) { … }
void LazyCallGraph::buildRefSCCs() { … }
void LazyCallGraph::visitReferences(SmallVectorImpl<Constant *> &Worklist,
SmallPtrSetImpl<Constant *> &Visited,
function_ref<void(Function &)> Callback) { … }
AnalysisKey LazyCallGraphAnalysis::Key;
LazyCallGraphPrinterPass::LazyCallGraphPrinterPass(raw_ostream &OS) : … { … }
static void printNode(raw_ostream &OS, LazyCallGraph::Node &N) { … }
static void printSCC(raw_ostream &OS, LazyCallGraph::SCC &C) { … }
static void printRefSCC(raw_ostream &OS, LazyCallGraph::RefSCC &C) { … }
PreservedAnalyses LazyCallGraphPrinterPass::run(Module &M,
ModuleAnalysisManager &AM) { … }
LazyCallGraphDOTPrinterPass::LazyCallGraphDOTPrinterPass(raw_ostream &OS)
: … { … }
static void printNodeDOT(raw_ostream &OS, LazyCallGraph::Node &N) { … }
PreservedAnalyses LazyCallGraphDOTPrinterPass::run(Module &M,
ModuleAnalysisManager &AM) { … }