| //===- CallGraphUpdater.cpp - A (lazy) call graph update helper -----------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// \file | |
| /// | |
| /// This file provides interfaces used to manipulate a call graph, regardless | |
| /// if it is a "old style" CallGraph or an "new style" LazyCallGraph. | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/Transforms/Utils/CallGraphUpdater.h" | |
| #include "llvm/IR/Constants.h" | |
| #include "llvm/Transforms/Utils/ModuleUtils.h" | |
| using namespace llvm; | |
| bool CallGraphUpdater::finalize() { | |
| if (!DeadFunctionsInComdats.empty()) { | |
| filterDeadComdatFunctions(DeadFunctionsInComdats); | |
| DeadFunctions.append(DeadFunctionsInComdats.begin(), | |
| DeadFunctionsInComdats.end()); | |
| } | |
| // This is the code path for the new lazy call graph and for the case were | |
| // no call graph was provided. | |
| for (Function *DeadFn : DeadFunctions) { | |
| DeadFn->removeDeadConstantUsers(); | |
| // If the function is used by metadata, we don't want it to be replaced with | |
| // poison in the metadata, so we replace it with nullptr in the metadata | |
| // before RAUW'ing the non-metadata uses below. | |
| if (DeadFn->isUsedByMetadata()) | |
| ValueAsMetadata::handleDeletion(DeadFn); | |
| DeadFn->replaceNonMetadataUsesWith(PoisonValue::get(DeadFn->getType())); | |
| if (LCG && !ReplacedFunctions.count(DeadFn)) { | |
| // Taken mostly from the inliner: | |
| LazyCallGraph::Node &N = LCG->get(*DeadFn); | |
| auto *DeadSCC = LCG->lookupSCC(N); | |
| assert(DeadSCC && DeadSCC->size() == 1 && | |
| &DeadSCC->begin()->getFunction() == DeadFn); | |
| FAM->clear(*DeadFn, DeadFn->getName()); | |
| AM->clear(*DeadSCC, DeadSCC->getName()); | |
| LCG->markDeadFunction(*DeadFn); | |
| // Mark the relevant parts of the call graph as invalid so we don't | |
| // visit them. | |
| UR->InvalidatedSCCs.insert(LCG->lookupSCC(N)); | |
| UR->DeadFunctions.push_back(DeadFn); | |
| } else { | |
| // The CGSCC infrastructure batch deletes functions at the end of the | |
| // call graph walk, so only erase the function if we're not using that | |
| // infrastructure. | |
| // The function is now really dead and de-attached from everything. | |
| DeadFn->eraseFromParent(); | |
| } | |
| } | |
| bool Changed = !DeadFunctions.empty(); | |
| DeadFunctionsInComdats.clear(); | |
| DeadFunctions.clear(); | |
| return Changed; | |
| } | |
| void CallGraphUpdater::reanalyzeFunction(Function &Fn) { | |
| if (LCG) { | |
| LazyCallGraph::Node &N = LCG->get(Fn); | |
| LazyCallGraph::SCC *C = LCG->lookupSCC(N); | |
| updateCGAndAnalysisManagerForCGSCCPass(*LCG, *C, N, *AM, *UR, *FAM); | |
| } | |
| } | |
| void CallGraphUpdater::registerOutlinedFunction(Function &OriginalFn, | |
| Function &NewFn) { | |
| if (LCG) | |
| LCG->addSplitFunction(OriginalFn, NewFn); | |
| } | |
| void CallGraphUpdater::removeFunction(Function &DeadFn) { | |
| DeadFn.deleteBody(); | |
| DeadFn.setLinkage(GlobalValue::ExternalLinkage); | |
| if (DeadFn.hasComdat()) | |
| DeadFunctionsInComdats.push_back(&DeadFn); | |
| else | |
| DeadFunctions.push_back(&DeadFn); | |
| if (FAM) | |
| FAM->clear(DeadFn, DeadFn.getName()); | |
| } | |
| void CallGraphUpdater::replaceFunctionWith(Function &OldFn, Function &NewFn) { | |
| OldFn.removeDeadConstantUsers(); | |
| ReplacedFunctions.insert(&OldFn); | |
| if (LCG) { | |
| // Directly substitute the functions in the call graph. | |
| LazyCallGraph::Node &OldLCGN = LCG->get(OldFn); | |
| SCC->getOuterRefSCC().replaceNodeFunction(OldLCGN, NewFn); | |
| } | |
| removeFunction(OldFn); | |
| } |