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