forked from OSchip/llvm-project
166 lines
5.7 KiB
C++
166 lines
5.7 KiB
C++
//===- CallGraphUpdater.cpp - A (lazy) call graph update helper -----------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
/// \file
|
|
///
|
|
/// This file provides interfaces used to manipulate a call graph, regardless
|
|
/// if it is a "old style" CallGraph or an "new style" LazyCallGraph.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Transforms/Utils/CallGraphUpdater.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
|
|
|
using namespace llvm;
|
|
|
|
bool CallGraphUpdater::finalize() {
|
|
if (!DeadFunctionsInComdats.empty()) {
|
|
filterDeadComdatFunctions(*DeadFunctionsInComdats.front()->getParent(),
|
|
DeadFunctionsInComdats);
|
|
DeadFunctions.append(DeadFunctionsInComdats.begin(),
|
|
DeadFunctionsInComdats.end());
|
|
}
|
|
|
|
if (CG) {
|
|
// First remove all references, e.g., outgoing via called functions. This is
|
|
// necessary as we can delete functions that have circular references.
|
|
for (Function *DeadFn : DeadFunctions) {
|
|
DeadFn->removeDeadConstantUsers();
|
|
CallGraphNode *DeadCGN = (*CG)[DeadFn];
|
|
DeadCGN->removeAllCalledFunctions();
|
|
CG->getExternalCallingNode()->removeAnyCallEdgeTo(DeadCGN);
|
|
DeadFn->replaceAllUsesWith(UndefValue::get(DeadFn->getType()));
|
|
}
|
|
|
|
// Then remove the node and function from the module.
|
|
for (Function *DeadFn : DeadFunctions) {
|
|
CallGraphNode *DeadCGN = CG->getOrInsertFunction(DeadFn);
|
|
assert(DeadCGN->getNumReferences() == 0 &&
|
|
"References should have been handled by now");
|
|
delete CG->removeFunctionFromModule(DeadCGN);
|
|
}
|
|
} else {
|
|
// This is the code path for the new lazy call graph and for the case were
|
|
// no call graph was provided.
|
|
for (Function *DeadFn : DeadFunctions) {
|
|
DeadFn->removeDeadConstantUsers();
|
|
DeadFn->replaceAllUsesWith(UndefValue::get(DeadFn->getType()));
|
|
|
|
if (LCG && !ReplacedFunctions.count(DeadFn)) {
|
|
// Taken mostly from the inliner:
|
|
LazyCallGraph::Node &N = LCG->get(*DeadFn);
|
|
auto *DeadSCC = LCG->lookupSCC(N);
|
|
assert(DeadSCC && DeadSCC->size() == 1 &&
|
|
&DeadSCC->begin()->getFunction() == DeadFn);
|
|
auto &DeadRC = DeadSCC->getOuterRefSCC();
|
|
|
|
FunctionAnalysisManager &FAM =
|
|
AM->getResult<FunctionAnalysisManagerCGSCCProxy>(*DeadSCC, *LCG)
|
|
.getManager();
|
|
|
|
FAM.clear(*DeadFn, DeadFn->getName());
|
|
AM->clear(*DeadSCC, DeadSCC->getName());
|
|
LCG->removeDeadFunction(*DeadFn);
|
|
|
|
// Mark the relevant parts of the call graph as invalid so we don't
|
|
// visit them.
|
|
UR->InvalidatedSCCs.insert(DeadSCC);
|
|
UR->InvalidatedRefSCCs.insert(&DeadRC);
|
|
}
|
|
|
|
// The function is now really dead and de-attached from everything.
|
|
DeadFn->eraseFromParent();
|
|
}
|
|
}
|
|
|
|
bool Changed = !DeadFunctions.empty();
|
|
DeadFunctionsInComdats.clear();
|
|
DeadFunctions.clear();
|
|
return Changed;
|
|
}
|
|
|
|
void CallGraphUpdater::reanalyzeFunction(Function &Fn) {
|
|
if (CG) {
|
|
CallGraphNode *OldCGN = CG->getOrInsertFunction(&Fn);
|
|
OldCGN->removeAllCalledFunctions();
|
|
CG->populateCallGraphNode(OldCGN);
|
|
} else if (LCG) {
|
|
LazyCallGraph::Node &N = LCG->get(Fn);
|
|
LazyCallGraph::SCC *C = LCG->lookupSCC(N);
|
|
updateCGAndAnalysisManagerForCGSCCPass(*LCG, *C, N, *AM, *UR, *FAM);
|
|
}
|
|
}
|
|
|
|
void CallGraphUpdater::registerOutlinedFunction(Function &NewFn) {
|
|
if (CG)
|
|
CG->addToCallGraph(&NewFn);
|
|
}
|
|
|
|
void CallGraphUpdater::removeFunction(Function &DeadFn) {
|
|
DeadFn.deleteBody();
|
|
DeadFn.setLinkage(GlobalValue::ExternalLinkage);
|
|
if (DeadFn.hasComdat())
|
|
DeadFunctionsInComdats.push_back(&DeadFn);
|
|
else
|
|
DeadFunctions.push_back(&DeadFn);
|
|
|
|
// For the old call graph we remove the function from the SCC right away.
|
|
if (CG && !ReplacedFunctions.count(&DeadFn)) {
|
|
CallGraphNode *DeadCGN = (*CG)[&DeadFn];
|
|
DeadCGN->removeAllCalledFunctions();
|
|
CGSCC->DeleteNode(DeadCGN);
|
|
}
|
|
}
|
|
|
|
void CallGraphUpdater::replaceFunctionWith(Function &OldFn, Function &NewFn) {
|
|
OldFn.removeDeadConstantUsers();
|
|
ReplacedFunctions.insert(&OldFn);
|
|
if (CG) {
|
|
// Update the call graph for the newly promoted function.
|
|
CallGraphNode *OldCGN = (*CG)[&OldFn];
|
|
CallGraphNode *NewCGN = CG->getOrInsertFunction(&NewFn);
|
|
NewCGN->stealCalledFunctionsFrom(OldCGN);
|
|
CG->ReplaceExternalCallEdge(OldCGN, NewCGN);
|
|
|
|
// And update the SCC we're iterating as well.
|
|
CGSCC->ReplaceNode(OldCGN, NewCGN);
|
|
} else if (LCG) {
|
|
// Directly substitute the functions in the call graph.
|
|
LazyCallGraph::Node &OldLCGN = LCG->get(OldFn);
|
|
SCC->getOuterRefSCC().replaceNodeFunction(OldLCGN, NewFn);
|
|
}
|
|
removeFunction(OldFn);
|
|
}
|
|
|
|
bool CallGraphUpdater::replaceCallSite(CallBase &OldCS, CallBase &NewCS) {
|
|
// This is only necessary in the (old) CG.
|
|
if (!CG)
|
|
return true;
|
|
|
|
Function *Caller = OldCS.getCaller();
|
|
CallGraphNode *NewCalleeNode =
|
|
CG->getOrInsertFunction(NewCS.getCalledFunction());
|
|
CallGraphNode *CallerNode = (*CG)[Caller];
|
|
if (llvm::none_of(*CallerNode, [&OldCS](const CallGraphNode::CallRecord &CR) {
|
|
return CR.first && *CR.first == &OldCS;
|
|
}))
|
|
return false;
|
|
CallerNode->replaceCallEdge(OldCS, NewCS, NewCalleeNode);
|
|
return true;
|
|
}
|
|
|
|
void CallGraphUpdater::removeCallSite(CallBase &CS) {
|
|
// This is only necessary in the (old) CG.
|
|
if (!CG)
|
|
return;
|
|
|
|
Function *Caller = CS.getCaller();
|
|
CallGraphNode *CallerNode = (*CG)[Caller];
|
|
CallerNode->removeCallEdgeFor(CS);
|
|
}
|