blob: 3b6fce578ffcc5afc9e2c623ddbfc702c5007328 [file] [log] [blame]
//===- 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();
DeadFn->replaceAllUsesWith(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);
}