Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/IPO/ElimAvailExtern.cpp
35269 views
//===- ElimAvailExtern.cpp - DCE unreachable internal functions -----------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This transform is designed to eliminate available external global9// definitions from the program, turning them into declarations.10//11//===----------------------------------------------------------------------===//1213#include "llvm/Transforms/IPO/ElimAvailExtern.h"14#include "llvm/ADT/STLExtras.h"15#include "llvm/ADT/Statistic.h"16#include "llvm/IR/Constant.h"17#include "llvm/IR/DebugInfoMetadata.h"18#include "llvm/IR/Function.h"19#include "llvm/IR/GlobalValue.h"20#include "llvm/IR/GlobalVariable.h"21#include "llvm/IR/MDBuilder.h"22#include "llvm/IR/Module.h"23#include "llvm/Support/CommandLine.h"24#include "llvm/Transforms/IPO.h"25#include "llvm/Transforms/Utils/GlobalStatus.h"26#include "llvm/Transforms/Utils/ModuleUtils.h"2728using namespace llvm;2930#define DEBUG_TYPE "elim-avail-extern"3132cl::opt<bool> ConvertToLocal(33"avail-extern-to-local", cl::Hidden,34cl::desc("Convert available_externally into locals, renaming them "35"to avoid link-time clashes."));3637STATISTIC(NumRemovals, "Number of functions removed");38STATISTIC(NumConversions, "Number of functions converted");39STATISTIC(NumVariables, "Number of global variables removed");4041void deleteFunction(Function &F) {42// This will set the linkage to external43F.deleteBody();44++NumRemovals;45}4647/// Create a copy of the thinlto import, mark it local, and redirect direct48/// calls to the copy. Only direct calls are replaced, so that e.g. indirect49/// call function pointer tests would use the global identity of the function.50///51/// Currently, Value Profiling ("VP") MD_prof data isn't updated to refer to the52/// clone's GUID (which will be different, because the name and linkage is53/// different), under the assumption that the last consumer of this data is54/// upstream the pipeline (e.g. ICP).55static void convertToLocalCopy(Module &M, Function &F) {56assert(F.hasAvailableExternallyLinkage());57assert(!F.isDeclaration());58// If we can't find a single use that's a call, just delete the function.59if (F.uses().end() == llvm::find_if(F.uses(), [&](Use &U) {60return isa<CallBase>(U.getUser());61}))62return deleteFunction(F);6364auto OrigName = F.getName().str();65// Build a new name. We still need the old name (see below).66// We could just rely on internal linking allowing 2 modules have internal67// functions with the same name, but that just creates more trouble than68// necessary e.g. distinguishing profiles or debugging. Instead, we append the69// module identifier.70auto NewName = OrigName + ".__uniq" + getUniqueModuleId(&M);71F.setName(NewName);72if (auto *SP = F.getSubprogram())73SP->replaceLinkageName(MDString::get(F.getParent()->getContext(), NewName));7475F.setLinkage(GlobalValue::InternalLinkage);76// Now make a declaration for the old name. We'll use it if there are non-call77// uses. For those, it would be incorrect to replace them with the local copy:78// for example, one such use could be taking the address of the function and79// passing it to an external function, which, in turn, might compare the80// function pointer to the original (non-local) function pointer, e.g. as part81// of indirect call promotion.82auto *Decl =83Function::Create(F.getFunctionType(), GlobalValue::ExternalLinkage,84F.getAddressSpace(), OrigName, F.getParent());85F.replaceUsesWithIf(Decl,86[&](Use &U) { return !isa<CallBase>(U.getUser()); });87++NumConversions;88}8990static bool eliminateAvailableExternally(Module &M) {91bool Changed = false;9293// Drop initializers of available externally global variables.94for (GlobalVariable &GV : M.globals()) {95if (!GV.hasAvailableExternallyLinkage())96continue;97if (GV.hasInitializer()) {98Constant *Init = GV.getInitializer();99GV.setInitializer(nullptr);100if (isSafeToDestroyConstant(Init))101Init->destroyConstant();102}103GV.removeDeadConstantUsers();104GV.setLinkage(GlobalValue::ExternalLinkage);105++NumVariables;106Changed = true;107}108109// Drop the bodies of available externally functions.110for (Function &F : llvm::make_early_inc_range(M)) {111if (F.isDeclaration() || !F.hasAvailableExternallyLinkage())112continue;113114if (ConvertToLocal)115convertToLocalCopy(M, F);116else117deleteFunction(F);118119F.removeDeadConstantUsers();120Changed = true;121}122123return Changed;124}125126PreservedAnalyses127EliminateAvailableExternallyPass::run(Module &M, ModuleAnalysisManager &) {128if (!eliminateAvailableExternally(M))129return PreservedAnalyses::all();130return PreservedAnalyses::none();131}132133134