1//===- ElimAvailExtern.cpp - DCE unreachable internal functions -----------===//
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//
9// This transform is designed to eliminate available external global
10// definitions from the program, turning them into declarations.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Transforms/IPO/ElimAvailExtern.h"
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/Statistic.h"
17#include "llvm/IR/Constant.h"
18#include "llvm/IR/DebugInfoMetadata.h"
19#include "llvm/IR/Function.h"
20#include "llvm/IR/GlobalValue.h"
21#include "llvm/IR/GlobalVariable.h"
22#include "llvm/IR/MDBuilder.h"
23#include "llvm/IR/Module.h"
24#include "llvm/Support/CommandLine.h"
25#include "llvm/Transforms/IPO.h"
26#include "llvm/Transforms/Utils/GlobalStatus.h"
27#include "llvm/Transforms/Utils/ModuleUtils.h"
28
29using namespace llvm;
30
31#define DEBUG_TYPE "elim-avail-extern"
32
33cl::opt<bool> ConvertToLocal(
34 "avail-extern-to-local", cl::Hidden,
35 cl::desc("Convert available_externally into locals, renaming them "
36 "to avoid link-time clashes."));
37
38STATISTIC(NumRemovals, "Number of functions removed");
39STATISTIC(NumConversions, "Number of functions converted");
40STATISTIC(NumVariables, "Number of global variables removed");
41
42void deleteFunction(Function &F) {
43 // This will set the linkage to external
44 F.deleteBody();
45 ++NumRemovals;
46}
47
48/// Create a copy of the thinlto import, mark it local, and redirect direct
49/// calls to the copy. Only direct calls are replaced, so that e.g. indirect
50/// call function pointer tests would use the global identity of the function.
51///
52/// Currently, Value Profiling ("VP") MD_prof data isn't updated to refer to the
53/// clone's GUID (which will be different, because the name and linkage is
54/// different), under the assumption that the last consumer of this data is
55/// upstream the pipeline (e.g. ICP).
56static void convertToLocalCopy(Module &M, Function &F) {
57 assert(F.hasAvailableExternallyLinkage());
58 assert(!F.isDeclaration());
59 // If we can't find a single use that's a call, just delete the function.
60 if (F.uses().end() == llvm::find_if(Range: F.uses(), P: [&](Use &U) {
61 return isa<CallBase>(Val: U.getUser());
62 }))
63 return deleteFunction(F);
64
65 auto OrigName = F.getName().str();
66 // Build a new name. We still need the old name (see below).
67 // We could just rely on internal linking allowing 2 modules have internal
68 // functions with the same name, but that just creates more trouble than
69 // necessary e.g. distinguishing profiles or debugging. Instead, we append the
70 // module identifier.
71 auto NewName = OrigName + ".__uniq" + getUniqueModuleId(M: &M);
72 F.setName(NewName);
73 if (auto *SP = F.getSubprogram())
74 SP->replaceLinkageName(LN: MDString::get(Context&: F.getParent()->getContext(), Str: NewName));
75
76 F.setLinkage(GlobalValue::InternalLinkage);
77 // Now make a declaration for the old name. We'll use it if there are non-call
78 // uses. For those, it would be incorrect to replace them with the local copy:
79 // for example, one such use could be taking the address of the function and
80 // passing it to an external function, which, in turn, might compare the
81 // function pointer to the original (non-local) function pointer, e.g. as part
82 // of indirect call promotion.
83 auto *Decl =
84 Function::Create(Ty: F.getFunctionType(), Linkage: GlobalValue::ExternalLinkage,
85 AddrSpace: F.getAddressSpace(), N: OrigName, M: F.getParent());
86 F.replaceUsesWithIf(New: Decl,
87 ShouldReplace: [&](Use &U) { return !isa<CallBase>(Val: U.getUser()); });
88 ++NumConversions;
89}
90
91static bool eliminateAvailableExternally(Module &M) {
92 bool Changed = false;
93
94 // Drop initializers of available externally global variables.
95 for (GlobalVariable &GV : M.globals()) {
96 if (!GV.hasAvailableExternallyLinkage())
97 continue;
98 if (GV.hasInitializer()) {
99 Constant *Init = GV.getInitializer();
100 GV.setInitializer(nullptr);
101 if (isSafeToDestroyConstant(C: Init))
102 Init->destroyConstant();
103 }
104 GV.removeDeadConstantUsers();
105 GV.setLinkage(GlobalValue::ExternalLinkage);
106 ++NumVariables;
107 Changed = true;
108 }
109
110 // Drop the bodies of available externally functions.
111 for (Function &F : llvm::make_early_inc_range(Range&: M)) {
112 if (F.isDeclaration() || !F.hasAvailableExternallyLinkage())
113 continue;
114
115 if (ConvertToLocal)
116 convertToLocalCopy(M, F);
117 else
118 deleteFunction(F);
119
120 F.removeDeadConstantUsers();
121 Changed = true;
122 }
123
124 return Changed;
125}
126
127PreservedAnalyses
128EliminateAvailableExternallyPass::run(Module &M, ModuleAnalysisManager &) {
129 if (!eliminateAvailableExternally(M))
130 return PreservedAnalyses::all();
131 return PreservedAnalyses::none();
132}
133