xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Utils/CallGraphUpdater.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
1*5ffd83dbSDimitry Andric //===- CallGraphUpdater.cpp - A (lazy) call graph update helper -----------===//
2*5ffd83dbSDimitry Andric //
3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5ffd83dbSDimitry Andric //
7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
8*5ffd83dbSDimitry Andric /// \file
9*5ffd83dbSDimitry Andric ///
10*5ffd83dbSDimitry Andric /// This file provides interfaces used to manipulate a call graph, regardless
11*5ffd83dbSDimitry Andric /// if it is a "old style" CallGraph or an "new style" LazyCallGraph.
12*5ffd83dbSDimitry Andric ///
13*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
14*5ffd83dbSDimitry Andric 
15*5ffd83dbSDimitry Andric #include "llvm/Transforms/Utils/CallGraphUpdater.h"
16*5ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h"
17*5ffd83dbSDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h"
18*5ffd83dbSDimitry Andric 
19*5ffd83dbSDimitry Andric using namespace llvm;
20*5ffd83dbSDimitry Andric 
21*5ffd83dbSDimitry Andric bool CallGraphUpdater::finalize() {
22*5ffd83dbSDimitry Andric   if (!DeadFunctionsInComdats.empty()) {
23*5ffd83dbSDimitry Andric     filterDeadComdatFunctions(*DeadFunctionsInComdats.front()->getParent(),
24*5ffd83dbSDimitry Andric                               DeadFunctionsInComdats);
25*5ffd83dbSDimitry Andric     DeadFunctions.append(DeadFunctionsInComdats.begin(),
26*5ffd83dbSDimitry Andric                          DeadFunctionsInComdats.end());
27*5ffd83dbSDimitry Andric   }
28*5ffd83dbSDimitry Andric 
29*5ffd83dbSDimitry Andric   if (CG) {
30*5ffd83dbSDimitry Andric     // First remove all references, e.g., outgoing via called functions. This is
31*5ffd83dbSDimitry Andric     // necessary as we can delete functions that have circular references.
32*5ffd83dbSDimitry Andric     for (Function *DeadFn : DeadFunctions) {
33*5ffd83dbSDimitry Andric       DeadFn->removeDeadConstantUsers();
34*5ffd83dbSDimitry Andric       CallGraphNode *DeadCGN = (*CG)[DeadFn];
35*5ffd83dbSDimitry Andric       DeadCGN->removeAllCalledFunctions();
36*5ffd83dbSDimitry Andric       CG->getExternalCallingNode()->removeAnyCallEdgeTo(DeadCGN);
37*5ffd83dbSDimitry Andric       DeadFn->replaceAllUsesWith(UndefValue::get(DeadFn->getType()));
38*5ffd83dbSDimitry Andric     }
39*5ffd83dbSDimitry Andric 
40*5ffd83dbSDimitry Andric     // Then remove the node and function from the module.
41*5ffd83dbSDimitry Andric     for (Function *DeadFn : DeadFunctions) {
42*5ffd83dbSDimitry Andric       CallGraphNode *DeadCGN = CG->getOrInsertFunction(DeadFn);
43*5ffd83dbSDimitry Andric       assert(DeadCGN->getNumReferences() == 0 &&
44*5ffd83dbSDimitry Andric              "References should have been handled by now");
45*5ffd83dbSDimitry Andric       delete CG->removeFunctionFromModule(DeadCGN);
46*5ffd83dbSDimitry Andric     }
47*5ffd83dbSDimitry Andric   } else {
48*5ffd83dbSDimitry Andric     // This is the code path for the new lazy call graph and for the case were
49*5ffd83dbSDimitry Andric     // no call graph was provided.
50*5ffd83dbSDimitry Andric     for (Function *DeadFn : DeadFunctions) {
51*5ffd83dbSDimitry Andric       DeadFn->removeDeadConstantUsers();
52*5ffd83dbSDimitry Andric       DeadFn->replaceAllUsesWith(UndefValue::get(DeadFn->getType()));
53*5ffd83dbSDimitry Andric 
54*5ffd83dbSDimitry Andric       if (LCG && !ReplacedFunctions.count(DeadFn)) {
55*5ffd83dbSDimitry Andric         // Taken mostly from the inliner:
56*5ffd83dbSDimitry Andric         LazyCallGraph::Node &N = LCG->get(*DeadFn);
57*5ffd83dbSDimitry Andric         auto *DeadSCC = LCG->lookupSCC(N);
58*5ffd83dbSDimitry Andric         assert(DeadSCC && DeadSCC->size() == 1 &&
59*5ffd83dbSDimitry Andric                &DeadSCC->begin()->getFunction() == DeadFn);
60*5ffd83dbSDimitry Andric         auto &DeadRC = DeadSCC->getOuterRefSCC();
61*5ffd83dbSDimitry Andric 
62*5ffd83dbSDimitry Andric         FunctionAnalysisManager &FAM =
63*5ffd83dbSDimitry Andric             AM->getResult<FunctionAnalysisManagerCGSCCProxy>(*DeadSCC, *LCG)
64*5ffd83dbSDimitry Andric                 .getManager();
65*5ffd83dbSDimitry Andric 
66*5ffd83dbSDimitry Andric         FAM.clear(*DeadFn, DeadFn->getName());
67*5ffd83dbSDimitry Andric         AM->clear(*DeadSCC, DeadSCC->getName());
68*5ffd83dbSDimitry Andric         LCG->removeDeadFunction(*DeadFn);
69*5ffd83dbSDimitry Andric 
70*5ffd83dbSDimitry Andric         // Mark the relevant parts of the call graph as invalid so we don't
71*5ffd83dbSDimitry Andric         // visit them.
72*5ffd83dbSDimitry Andric         UR->InvalidatedSCCs.insert(DeadSCC);
73*5ffd83dbSDimitry Andric         UR->InvalidatedRefSCCs.insert(&DeadRC);
74*5ffd83dbSDimitry Andric       }
75*5ffd83dbSDimitry Andric 
76*5ffd83dbSDimitry Andric       // The function is now really dead and de-attached from everything.
77*5ffd83dbSDimitry Andric       DeadFn->eraseFromParent();
78*5ffd83dbSDimitry Andric     }
79*5ffd83dbSDimitry Andric   }
80*5ffd83dbSDimitry Andric 
81*5ffd83dbSDimitry Andric   bool Changed = !DeadFunctions.empty();
82*5ffd83dbSDimitry Andric   DeadFunctionsInComdats.clear();
83*5ffd83dbSDimitry Andric   DeadFunctions.clear();
84*5ffd83dbSDimitry Andric   return Changed;
85*5ffd83dbSDimitry Andric }
86*5ffd83dbSDimitry Andric 
87*5ffd83dbSDimitry Andric void CallGraphUpdater::reanalyzeFunction(Function &Fn) {
88*5ffd83dbSDimitry Andric   if (CG) {
89*5ffd83dbSDimitry Andric     CallGraphNode *OldCGN = CG->getOrInsertFunction(&Fn);
90*5ffd83dbSDimitry Andric     OldCGN->removeAllCalledFunctions();
91*5ffd83dbSDimitry Andric     CG->populateCallGraphNode(OldCGN);
92*5ffd83dbSDimitry Andric   } else if (LCG) {
93*5ffd83dbSDimitry Andric     LazyCallGraph::Node &N = LCG->get(Fn);
94*5ffd83dbSDimitry Andric     LazyCallGraph::SCC *C = LCG->lookupSCC(N);
95*5ffd83dbSDimitry Andric     updateCGAndAnalysisManagerForCGSCCPass(*LCG, *C, N, *AM, *UR, *FAM);
96*5ffd83dbSDimitry Andric   }
97*5ffd83dbSDimitry Andric }
98*5ffd83dbSDimitry Andric 
99*5ffd83dbSDimitry Andric void CallGraphUpdater::registerOutlinedFunction(Function &NewFn) {
100*5ffd83dbSDimitry Andric   if (CG)
101*5ffd83dbSDimitry Andric     CG->addToCallGraph(&NewFn);
102*5ffd83dbSDimitry Andric   else if (LCG)
103*5ffd83dbSDimitry Andric     LCG->addNewFunctionIntoSCC(NewFn, *SCC);
104*5ffd83dbSDimitry Andric }
105*5ffd83dbSDimitry Andric 
106*5ffd83dbSDimitry Andric void CallGraphUpdater::removeFunction(Function &DeadFn) {
107*5ffd83dbSDimitry Andric   DeadFn.deleteBody();
108*5ffd83dbSDimitry Andric   DeadFn.setLinkage(GlobalValue::ExternalLinkage);
109*5ffd83dbSDimitry Andric   if (DeadFn.hasComdat())
110*5ffd83dbSDimitry Andric     DeadFunctionsInComdats.push_back(&DeadFn);
111*5ffd83dbSDimitry Andric   else
112*5ffd83dbSDimitry Andric     DeadFunctions.push_back(&DeadFn);
113*5ffd83dbSDimitry Andric 
114*5ffd83dbSDimitry Andric   // For the old call graph we remove the function from the SCC right away.
115*5ffd83dbSDimitry Andric   if (CG && !ReplacedFunctions.count(&DeadFn)) {
116*5ffd83dbSDimitry Andric     CallGraphNode *DeadCGN = (*CG)[&DeadFn];
117*5ffd83dbSDimitry Andric     DeadCGN->removeAllCalledFunctions();
118*5ffd83dbSDimitry Andric     CGSCC->DeleteNode(DeadCGN);
119*5ffd83dbSDimitry Andric   }
120*5ffd83dbSDimitry Andric }
121*5ffd83dbSDimitry Andric 
122*5ffd83dbSDimitry Andric void CallGraphUpdater::replaceFunctionWith(Function &OldFn, Function &NewFn) {
123*5ffd83dbSDimitry Andric   OldFn.removeDeadConstantUsers();
124*5ffd83dbSDimitry Andric   ReplacedFunctions.insert(&OldFn);
125*5ffd83dbSDimitry Andric   if (CG) {
126*5ffd83dbSDimitry Andric     // Update the call graph for the newly promoted function.
127*5ffd83dbSDimitry Andric     CallGraphNode *OldCGN = (*CG)[&OldFn];
128*5ffd83dbSDimitry Andric     CallGraphNode *NewCGN = CG->getOrInsertFunction(&NewFn);
129*5ffd83dbSDimitry Andric     NewCGN->stealCalledFunctionsFrom(OldCGN);
130*5ffd83dbSDimitry Andric     CG->ReplaceExternalCallEdge(OldCGN, NewCGN);
131*5ffd83dbSDimitry Andric 
132*5ffd83dbSDimitry Andric     // And update the SCC we're iterating as well.
133*5ffd83dbSDimitry Andric     CGSCC->ReplaceNode(OldCGN, NewCGN);
134*5ffd83dbSDimitry Andric   } else if (LCG) {
135*5ffd83dbSDimitry Andric     // Directly substitute the functions in the call graph.
136*5ffd83dbSDimitry Andric     LazyCallGraph::Node &OldLCGN = LCG->get(OldFn);
137*5ffd83dbSDimitry Andric     SCC->getOuterRefSCC().replaceNodeFunction(OldLCGN, NewFn);
138*5ffd83dbSDimitry Andric   }
139*5ffd83dbSDimitry Andric   removeFunction(OldFn);
140*5ffd83dbSDimitry Andric }
141*5ffd83dbSDimitry Andric 
142*5ffd83dbSDimitry Andric bool CallGraphUpdater::replaceCallSite(CallBase &OldCS, CallBase &NewCS) {
143*5ffd83dbSDimitry Andric   // This is only necessary in the (old) CG.
144*5ffd83dbSDimitry Andric   if (!CG)
145*5ffd83dbSDimitry Andric     return true;
146*5ffd83dbSDimitry Andric 
147*5ffd83dbSDimitry Andric   Function *Caller = OldCS.getCaller();
148*5ffd83dbSDimitry Andric   CallGraphNode *NewCalleeNode =
149*5ffd83dbSDimitry Andric       CG->getOrInsertFunction(NewCS.getCalledFunction());
150*5ffd83dbSDimitry Andric   CallGraphNode *CallerNode = (*CG)[Caller];
151*5ffd83dbSDimitry Andric   if (llvm::none_of(*CallerNode, [&OldCS](const CallGraphNode::CallRecord &CR) {
152*5ffd83dbSDimitry Andric         return CR.first && *CR.first == &OldCS;
153*5ffd83dbSDimitry Andric       }))
154*5ffd83dbSDimitry Andric     return false;
155*5ffd83dbSDimitry Andric   CallerNode->replaceCallEdge(OldCS, NewCS, NewCalleeNode);
156*5ffd83dbSDimitry Andric   return true;
157*5ffd83dbSDimitry Andric }
158*5ffd83dbSDimitry Andric 
159*5ffd83dbSDimitry Andric void CallGraphUpdater::removeCallSite(CallBase &CS) {
160*5ffd83dbSDimitry Andric   // This is only necessary in the (old) CG.
161*5ffd83dbSDimitry Andric   if (!CG)
162*5ffd83dbSDimitry Andric     return;
163*5ffd83dbSDimitry Andric 
164*5ffd83dbSDimitry Andric   Function *Caller = CS.getCaller();
165*5ffd83dbSDimitry Andric   CallGraphNode *CallerNode = (*CG)[Caller];
166*5ffd83dbSDimitry Andric   CallerNode->removeCallEdgeFor(CS);
167*5ffd83dbSDimitry Andric }
168