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