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