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