172277ecdSJohannes Doerfert //===- CallGraphUpdater.cpp - A (lazy) call graph update helper -----------===//
272277ecdSJohannes Doerfert //
372277ecdSJohannes Doerfert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
472277ecdSJohannes Doerfert // See https://llvm.org/LICENSE.txt for license information.
572277ecdSJohannes Doerfert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
672277ecdSJohannes Doerfert //
772277ecdSJohannes Doerfert //===----------------------------------------------------------------------===//
872277ecdSJohannes Doerfert /// \file
972277ecdSJohannes Doerfert ///
1072277ecdSJohannes Doerfert /// This file provides interfaces used to manipulate a call graph, regardless
1172277ecdSJohannes Doerfert /// if it is a "old style" CallGraph or an "new style" LazyCallGraph.
1272277ecdSJohannes Doerfert ///
1372277ecdSJohannes Doerfert //===----------------------------------------------------------------------===//
1472277ecdSJohannes Doerfert
1572277ecdSJohannes Doerfert #include "llvm/Transforms/Utils/CallGraphUpdater.h"
1672277ecdSJohannes Doerfert #include "llvm/ADT/STLExtras.h"
17*a494ae43Sserge-sans-paille #include "llvm/Analysis/CallGraph.h"
18*a494ae43Sserge-sans-paille #include "llvm/Analysis/CallGraphSCCPass.h"
19a5bbc6efSBill Wendling #include "llvm/IR/Constants.h"
2072277ecdSJohannes Doerfert #include "llvm/Transforms/Utils/ModuleUtils.h"
2172277ecdSJohannes Doerfert
2272277ecdSJohannes Doerfert using namespace llvm;
2372277ecdSJohannes Doerfert
finalize()2472277ecdSJohannes Doerfert bool CallGraphUpdater::finalize() {
2572277ecdSJohannes Doerfert if (!DeadFunctionsInComdats.empty()) {
26c8189da2SNikita Popov filterDeadComdatFunctions(DeadFunctionsInComdats);
2772277ecdSJohannes Doerfert DeadFunctions.append(DeadFunctionsInComdats.begin(),
2872277ecdSJohannes Doerfert DeadFunctionsInComdats.end());
2972277ecdSJohannes Doerfert }
3072277ecdSJohannes Doerfert
317ec8d793SJohannes Doerfert if (CG) {
327ec8d793SJohannes Doerfert // First remove all references, e.g., outgoing via called functions. This is
337ec8d793SJohannes Doerfert // necessary as we can delete functions that have circular references.
3472277ecdSJohannes Doerfert for (Function *DeadFn : DeadFunctions) {
3572277ecdSJohannes Doerfert DeadFn->removeDeadConstantUsers();
367ec8d793SJohannes Doerfert CallGraphNode *DeadCGN = (*CG)[DeadFn];
377ec8d793SJohannes Doerfert DeadCGN->removeAllCalledFunctions();
387ec8d793SJohannes Doerfert CG->getExternalCallingNode()->removeAnyCallEdgeTo(DeadCGN);
3972277ecdSJohannes Doerfert DeadFn->replaceAllUsesWith(UndefValue::get(DeadFn->getType()));
4072277ecdSJohannes Doerfert }
4172277ecdSJohannes Doerfert
427ec8d793SJohannes Doerfert // Then remove the node and function from the module.
437ec8d793SJohannes Doerfert for (Function *DeadFn : DeadFunctions) {
447ec8d793SJohannes Doerfert CallGraphNode *DeadCGN = CG->getOrInsertFunction(DeadFn);
457ec8d793SJohannes Doerfert assert(DeadCGN->getNumReferences() == 0 &&
467ec8d793SJohannes Doerfert "References should have been handled by now");
477ec8d793SJohannes Doerfert delete CG->removeFunctionFromModule(DeadCGN);
487ec8d793SJohannes Doerfert }
497ec8d793SJohannes Doerfert } else {
507ec8d793SJohannes Doerfert // This is the code path for the new lazy call graph and for the case were
517ec8d793SJohannes Doerfert // no call graph was provided.
527ec8d793SJohannes Doerfert for (Function *DeadFn : DeadFunctions) {
537ec8d793SJohannes Doerfert DeadFn->removeDeadConstantUsers();
5472277ecdSJohannes Doerfert DeadFn->replaceAllUsesWith(UndefValue::get(DeadFn->getType()));
5572277ecdSJohannes Doerfert
5672277ecdSJohannes Doerfert if (LCG && !ReplacedFunctions.count(DeadFn)) {
5772277ecdSJohannes Doerfert // Taken mostly from the inliner:
5872277ecdSJohannes Doerfert LazyCallGraph::Node &N = LCG->get(*DeadFn);
5972277ecdSJohannes Doerfert auto *DeadSCC = LCG->lookupSCC(N);
6072277ecdSJohannes Doerfert assert(DeadSCC && DeadSCC->size() == 1 &&
6172277ecdSJohannes Doerfert &DeadSCC->begin()->getFunction() == DeadFn);
6272277ecdSJohannes Doerfert auto &DeadRC = DeadSCC->getOuterRefSCC();
6372277ecdSJohannes Doerfert
64282f5d7aSJohannes Doerfert FunctionAnalysisManager &FAM =
65282f5d7aSJohannes Doerfert AM->getResult<FunctionAnalysisManagerCGSCCProxy>(*DeadSCC, *LCG)
66282f5d7aSJohannes Doerfert .getManager();
67282f5d7aSJohannes Doerfert
6872277ecdSJohannes Doerfert FAM.clear(*DeadFn, DeadFn->getName());
6972277ecdSJohannes Doerfert AM->clear(*DeadSCC, DeadSCC->getName());
7072277ecdSJohannes Doerfert LCG->removeDeadFunction(*DeadFn);
7172277ecdSJohannes Doerfert
727ec8d793SJohannes Doerfert // Mark the relevant parts of the call graph as invalid so we don't
737ec8d793SJohannes Doerfert // visit them.
7472277ecdSJohannes Doerfert UR->InvalidatedSCCs.insert(DeadSCC);
7572277ecdSJohannes Doerfert UR->InvalidatedRefSCCs.insert(&DeadRC);
7672277ecdSJohannes Doerfert }
7772277ecdSJohannes Doerfert
7872277ecdSJohannes Doerfert // The function is now really dead and de-attached from everything.
7972277ecdSJohannes Doerfert DeadFn->eraseFromParent();
8072277ecdSJohannes Doerfert }
817ec8d793SJohannes Doerfert }
8272277ecdSJohannes Doerfert
8372277ecdSJohannes Doerfert bool Changed = !DeadFunctions.empty();
8472277ecdSJohannes Doerfert DeadFunctionsInComdats.clear();
8572277ecdSJohannes Doerfert DeadFunctions.clear();
8672277ecdSJohannes Doerfert return Changed;
8772277ecdSJohannes Doerfert }
8872277ecdSJohannes Doerfert
reanalyzeFunction(Function & Fn)8972277ecdSJohannes Doerfert void CallGraphUpdater::reanalyzeFunction(Function &Fn) {
9072277ecdSJohannes Doerfert if (CG) {
9172277ecdSJohannes Doerfert CallGraphNode *OldCGN = CG->getOrInsertFunction(&Fn);
9272277ecdSJohannes Doerfert OldCGN->removeAllCalledFunctions();
9372277ecdSJohannes Doerfert CG->populateCallGraphNode(OldCGN);
9472277ecdSJohannes Doerfert } else if (LCG) {
9572277ecdSJohannes Doerfert LazyCallGraph::Node &N = LCG->get(Fn);
9672277ecdSJohannes Doerfert LazyCallGraph::SCC *C = LCG->lookupSCC(N);
97bd541b21SAlina Sbirlea updateCGAndAnalysisManagerForCGSCCPass(*LCG, *C, N, *AM, *UR, *FAM);
9872277ecdSJohannes Doerfert }
9972277ecdSJohannes Doerfert }
10072277ecdSJohannes Doerfert
registerOutlinedFunction(Function & OriginalFn,Function & NewFn)1017fea561eSArthur Eubanks void CallGraphUpdater::registerOutlinedFunction(Function &OriginalFn,
1027fea561eSArthur Eubanks Function &NewFn) {
10372277ecdSJohannes Doerfert if (CG)
10472277ecdSJohannes Doerfert CG->addToCallGraph(&NewFn);
1057fea561eSArthur Eubanks else if (LCG)
1067fea561eSArthur Eubanks LCG->addSplitFunction(OriginalFn, NewFn);
10772277ecdSJohannes Doerfert }
10872277ecdSJohannes Doerfert
removeFunction(Function & DeadFn)10972277ecdSJohannes Doerfert void CallGraphUpdater::removeFunction(Function &DeadFn) {
11072277ecdSJohannes Doerfert DeadFn.deleteBody();
11172277ecdSJohannes Doerfert DeadFn.setLinkage(GlobalValue::ExternalLinkage);
11272277ecdSJohannes Doerfert if (DeadFn.hasComdat())
11372277ecdSJohannes Doerfert DeadFunctionsInComdats.push_back(&DeadFn);
11472277ecdSJohannes Doerfert else
11572277ecdSJohannes Doerfert DeadFunctions.push_back(&DeadFn);
11693702575SJohannes Doerfert
11793702575SJohannes Doerfert // For the old call graph we remove the function from the SCC right away.
118f637334dSSergey Dmitriev if (CG && !ReplacedFunctions.count(&DeadFn)) {
119f637334dSSergey Dmitriev CallGraphNode *DeadCGN = (*CG)[&DeadFn];
120f637334dSSergey Dmitriev DeadCGN->removeAllCalledFunctions();
121f637334dSSergey Dmitriev CGSCC->DeleteNode(DeadCGN);
122f637334dSSergey Dmitriev }
12372277ecdSJohannes Doerfert }
12472277ecdSJohannes Doerfert
replaceFunctionWith(Function & OldFn,Function & NewFn)12572277ecdSJohannes Doerfert void CallGraphUpdater::replaceFunctionWith(Function &OldFn, Function &NewFn) {
126cb0ecc5cSJohannes Doerfert OldFn.removeDeadConstantUsers();
12772277ecdSJohannes Doerfert ReplacedFunctions.insert(&OldFn);
12872277ecdSJohannes Doerfert if (CG) {
12972277ecdSJohannes Doerfert // Update the call graph for the newly promoted function.
13072277ecdSJohannes Doerfert CallGraphNode *OldCGN = (*CG)[&OldFn];
13172277ecdSJohannes Doerfert CallGraphNode *NewCGN = CG->getOrInsertFunction(&NewFn);
13272277ecdSJohannes Doerfert NewCGN->stealCalledFunctionsFrom(OldCGN);
1331b34b84dSJohannes Doerfert CG->ReplaceExternalCallEdge(OldCGN, NewCGN);
13472277ecdSJohannes Doerfert
13572277ecdSJohannes Doerfert // And update the SCC we're iterating as well.
13672277ecdSJohannes Doerfert CGSCC->ReplaceNode(OldCGN, NewCGN);
13772277ecdSJohannes Doerfert } else if (LCG) {
13872277ecdSJohannes Doerfert // Directly substitute the functions in the call graph.
13972277ecdSJohannes Doerfert LazyCallGraph::Node &OldLCGN = LCG->get(OldFn);
14072277ecdSJohannes Doerfert SCC->getOuterRefSCC().replaceNodeFunction(OldLCGN, NewFn);
14172277ecdSJohannes Doerfert }
14272277ecdSJohannes Doerfert removeFunction(OldFn);
14372277ecdSJohannes Doerfert }
14472277ecdSJohannes Doerfert
replaceCallSite(CallBase & OldCS,CallBase & NewCS)14572277ecdSJohannes Doerfert bool CallGraphUpdater::replaceCallSite(CallBase &OldCS, CallBase &NewCS) {
14672277ecdSJohannes Doerfert // This is only necessary in the (old) CG.
14772277ecdSJohannes Doerfert if (!CG)
14872277ecdSJohannes Doerfert return true;
14972277ecdSJohannes Doerfert
15072277ecdSJohannes Doerfert Function *Caller = OldCS.getCaller();
15172277ecdSJohannes Doerfert CallGraphNode *NewCalleeNode =
15272277ecdSJohannes Doerfert CG->getOrInsertFunction(NewCS.getCalledFunction());
15372277ecdSJohannes Doerfert CallGraphNode *CallerNode = (*CG)[Caller];
15472277ecdSJohannes Doerfert if (llvm::none_of(*CallerNode, [&OldCS](const CallGraphNode::CallRecord &CR) {
155cb8faaacSSergey Dmitriev return CR.first && *CR.first == &OldCS;
15672277ecdSJohannes Doerfert }))
15772277ecdSJohannes Doerfert return false;
15872277ecdSJohannes Doerfert CallerNode->replaceCallEdge(OldCS, NewCS, NewCalleeNode);
15972277ecdSJohannes Doerfert return true;
16072277ecdSJohannes Doerfert }
16172277ecdSJohannes Doerfert
removeCallSite(CallBase & CS)16272277ecdSJohannes Doerfert void CallGraphUpdater::removeCallSite(CallBase &CS) {
16372277ecdSJohannes Doerfert // This is only necessary in the (old) CG.
16472277ecdSJohannes Doerfert if (!CG)
16572277ecdSJohannes Doerfert return;
16672277ecdSJohannes Doerfert
16772277ecdSJohannes Doerfert Function *Caller = CS.getCaller();
16872277ecdSJohannes Doerfert CallGraphNode *CallerNode = (*CG)[Caller];
16972277ecdSJohannes Doerfert CallerNode->removeCallEdgeFor(CS);
17072277ecdSJohannes Doerfert }
171