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 // If the function is used by metadata, we don't want it to be replaced with
33 // poison in the metadata, so we replace it with nullptr in the metadata
34 // before RAUW'ing the non-metadata uses below.
35 if (DeadFn->isUsedByMetadata())
36 ValueAsMetadata::handleDeletion(V: DeadFn);
37 DeadFn->replaceNonMetadataUsesWith(V: PoisonValue::get(T: DeadFn->getType()));
38
39 if (LCG && !ReplacedFunctions.count(Ptr: DeadFn)) {
40 // Taken mostly from the inliner:
41 LazyCallGraph::Node &N = LCG->get(F&: *DeadFn);
42 auto *DeadSCC = LCG->lookupSCC(N);
43 assert(DeadSCC && DeadSCC->size() == 1 &&
44 &DeadSCC->begin()->getFunction() == DeadFn);
45
46 FAM->clear(IR&: *DeadFn, Name: DeadFn->getName());
47 AM->clear(IR&: *DeadSCC, Name: DeadSCC->getName());
48 LCG->markDeadFunction(F&: *DeadFn);
49
50 // Mark the relevant parts of the call graph as invalid so we don't
51 // visit them.
52 UR->InvalidatedSCCs.insert(Ptr: LCG->lookupSCC(N));
53 UR->DeadFunctions.push_back(Elt: DeadFn);
54 } else {
55 // The CGSCC infrastructure batch deletes functions at the end of the
56 // call graph walk, so only erase the function if we're not using that
57 // infrastructure.
58 // The function is now really dead and de-attached from everything.
59 DeadFn->eraseFromParent();
60 }
61 }
62
63 bool Changed = !DeadFunctions.empty();
64 DeadFunctionsInComdats.clear();
65 DeadFunctions.clear();
66 return Changed;
67}
68
69void CallGraphUpdater::reanalyzeFunction(Function &Fn) {
70 if (LCG) {
71 LazyCallGraph::Node &N = LCG->get(F&: Fn);
72 LazyCallGraph::SCC *C = LCG->lookupSCC(N);
73 updateCGAndAnalysisManagerForCGSCCPass(G&: *LCG, C&: *C, N, AM&: *AM, UR&: *UR, FAM&: *FAM);
74 }
75}
76
77void CallGraphUpdater::registerOutlinedFunction(Function &OriginalFn,
78 Function &NewFn) {
79 if (LCG)
80 LCG->addSplitFunction(OriginalFunction&: OriginalFn, NewFunction&: NewFn);
81}
82
83void CallGraphUpdater::removeFunction(Function &DeadFn) {
84 DeadFn.deleteBody();
85 DeadFn.setLinkage(GlobalValue::ExternalLinkage);
86 if (DeadFn.hasComdat())
87 DeadFunctionsInComdats.push_back(Elt: &DeadFn);
88 else
89 DeadFunctions.push_back(Elt: &DeadFn);
90
91 if (FAM)
92 FAM->clear(IR&: DeadFn, Name: DeadFn.getName());
93}
94
95void CallGraphUpdater::replaceFunctionWith(Function &OldFn, Function &NewFn) {
96 OldFn.removeDeadConstantUsers();
97 ReplacedFunctions.insert(Ptr: &OldFn);
98 if (LCG) {
99 // Directly substitute the functions in the call graph.
100 LazyCallGraph::Node &OldLCGN = LCG->get(F&: OldFn);
101 SCC->getOuterRefSCC().replaceNodeFunction(N&: OldLCGN, NewF&: NewFn);
102 }
103 removeFunction(DeadFn&: OldFn);
104}
105