xref: /src/contrib/llvm-project/llvm/lib/Transforms/Utils/CallGraphUpdater.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1cfca06d7SDimitry Andric //===- CallGraphUpdater.cpp - A (lazy) call graph update helper -----------===//
2cfca06d7SDimitry Andric //
3cfca06d7SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4cfca06d7SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5cfca06d7SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cfca06d7SDimitry Andric //
7cfca06d7SDimitry Andric //===----------------------------------------------------------------------===//
8cfca06d7SDimitry Andric /// \file
9cfca06d7SDimitry Andric ///
10cfca06d7SDimitry Andric /// This file provides interfaces used to manipulate a call graph, regardless
11cfca06d7SDimitry Andric /// if it is a "old style" CallGraph or an "new style" LazyCallGraph.
12cfca06d7SDimitry Andric ///
13cfca06d7SDimitry Andric //===----------------------------------------------------------------------===//
14cfca06d7SDimitry Andric 
15cfca06d7SDimitry Andric #include "llvm/Transforms/Utils/CallGraphUpdater.h"
16145449b1SDimitry Andric #include "llvm/IR/Constants.h"
17cfca06d7SDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h"
18cfca06d7SDimitry Andric 
19cfca06d7SDimitry Andric using namespace llvm;
20cfca06d7SDimitry Andric 
finalize()21cfca06d7SDimitry Andric bool CallGraphUpdater::finalize() {
22cfca06d7SDimitry Andric   if (!DeadFunctionsInComdats.empty()) {
236f8fc217SDimitry Andric     filterDeadComdatFunctions(DeadFunctionsInComdats);
24cfca06d7SDimitry Andric     DeadFunctions.append(DeadFunctionsInComdats.begin(),
25cfca06d7SDimitry Andric                          DeadFunctionsInComdats.end());
26cfca06d7SDimitry Andric   }
27cfca06d7SDimitry Andric 
28cfca06d7SDimitry Andric   // This is the code path for the new lazy call graph and for the case were
29cfca06d7SDimitry Andric   // no call graph was provided.
30cfca06d7SDimitry Andric   for (Function *DeadFn : DeadFunctions) {
31cfca06d7SDimitry Andric     DeadFn->removeDeadConstantUsers();
32e3b55780SDimitry Andric     DeadFn->replaceAllUsesWith(PoisonValue::get(DeadFn->getType()));
33cfca06d7SDimitry Andric 
34cfca06d7SDimitry Andric     if (LCG && !ReplacedFunctions.count(DeadFn)) {
35cfca06d7SDimitry Andric       // Taken mostly from the inliner:
36cfca06d7SDimitry Andric       LazyCallGraph::Node &N = LCG->get(*DeadFn);
37cfca06d7SDimitry Andric       auto *DeadSCC = LCG->lookupSCC(N);
38cfca06d7SDimitry Andric       assert(DeadSCC && DeadSCC->size() == 1 &&
39cfca06d7SDimitry Andric              &DeadSCC->begin()->getFunction() == DeadFn);
40cfca06d7SDimitry Andric 
41ac9a064cSDimitry Andric       FAM->clear(*DeadFn, DeadFn->getName());
42cfca06d7SDimitry Andric       AM->clear(*DeadSCC, DeadSCC->getName());
43ac9a064cSDimitry Andric       LCG->markDeadFunction(*DeadFn);
44cfca06d7SDimitry Andric 
45cfca06d7SDimitry Andric       // Mark the relevant parts of the call graph as invalid so we don't
46cfca06d7SDimitry Andric       // visit them.
47ac9a064cSDimitry Andric       UR->InvalidatedSCCs.insert(LCG->lookupSCC(N));
48ac9a064cSDimitry Andric       UR->DeadFunctions.push_back(DeadFn);
49ac9a064cSDimitry Andric     } else {
50ac9a064cSDimitry Andric       // The CGSCC infrastructure batch deletes functions at the end of the
51ac9a064cSDimitry Andric       // call graph walk, so only erase the function if we're not using that
52ac9a064cSDimitry Andric       // infrastructure.
53cfca06d7SDimitry Andric       // The function is now really dead and de-attached from everything.
54cfca06d7SDimitry Andric       DeadFn->eraseFromParent();
55cfca06d7SDimitry Andric     }
56cfca06d7SDimitry Andric   }
57cfca06d7SDimitry Andric 
58cfca06d7SDimitry Andric   bool Changed = !DeadFunctions.empty();
59cfca06d7SDimitry Andric   DeadFunctionsInComdats.clear();
60cfca06d7SDimitry Andric   DeadFunctions.clear();
61cfca06d7SDimitry Andric   return Changed;
62cfca06d7SDimitry Andric }
63cfca06d7SDimitry Andric 
reanalyzeFunction(Function & Fn)64cfca06d7SDimitry Andric void CallGraphUpdater::reanalyzeFunction(Function &Fn) {
65ac9a064cSDimitry Andric   if (LCG) {
66cfca06d7SDimitry Andric     LazyCallGraph::Node &N = LCG->get(Fn);
67cfca06d7SDimitry Andric     LazyCallGraph::SCC *C = LCG->lookupSCC(N);
68cfca06d7SDimitry Andric     updateCGAndAnalysisManagerForCGSCCPass(*LCG, *C, N, *AM, *UR, *FAM);
69cfca06d7SDimitry Andric   }
70cfca06d7SDimitry Andric }
71cfca06d7SDimitry Andric 
registerOutlinedFunction(Function & OriginalFn,Function & NewFn)72b60736ecSDimitry Andric void CallGraphUpdater::registerOutlinedFunction(Function &OriginalFn,
73b60736ecSDimitry Andric                                                 Function &NewFn) {
74ac9a064cSDimitry Andric   if (LCG)
75b60736ecSDimitry Andric     LCG->addSplitFunction(OriginalFn, NewFn);
76cfca06d7SDimitry Andric }
77cfca06d7SDimitry Andric 
removeFunction(Function & DeadFn)78cfca06d7SDimitry Andric void CallGraphUpdater::removeFunction(Function &DeadFn) {
79cfca06d7SDimitry Andric   DeadFn.deleteBody();
80cfca06d7SDimitry Andric   DeadFn.setLinkage(GlobalValue::ExternalLinkage);
81cfca06d7SDimitry Andric   if (DeadFn.hasComdat())
82cfca06d7SDimitry Andric     DeadFunctionsInComdats.push_back(&DeadFn);
83cfca06d7SDimitry Andric   else
84cfca06d7SDimitry Andric     DeadFunctions.push_back(&DeadFn);
85cfca06d7SDimitry Andric 
867fa27ce4SDimitry Andric   if (FAM)
877fa27ce4SDimitry Andric     FAM->clear(DeadFn, DeadFn.getName());
88cfca06d7SDimitry Andric }
89cfca06d7SDimitry Andric 
replaceFunctionWith(Function & OldFn,Function & NewFn)90cfca06d7SDimitry Andric void CallGraphUpdater::replaceFunctionWith(Function &OldFn, Function &NewFn) {
91cfca06d7SDimitry Andric   OldFn.removeDeadConstantUsers();
92cfca06d7SDimitry Andric   ReplacedFunctions.insert(&OldFn);
93ac9a064cSDimitry Andric   if (LCG) {
94cfca06d7SDimitry Andric     // Directly substitute the functions in the call graph.
95cfca06d7SDimitry Andric     LazyCallGraph::Node &OldLCGN = LCG->get(OldFn);
96cfca06d7SDimitry Andric     SCC->getOuterRefSCC().replaceNodeFunction(OldLCGN, NewFn);
97cfca06d7SDimitry Andric   }
98cfca06d7SDimitry Andric   removeFunction(OldFn);
99cfca06d7SDimitry Andric }
100