xref: /freebsd/contrib/llvm-project/llvm/lib/Transforms/IPO/ElimAvailExtern.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/Analysis/CtxProfAnalysis.h"
18 #include "llvm/IR/Constant.h"
19 #include "llvm/IR/DebugInfoMetadata.h"
20 #include "llvm/IR/Function.h"
21 #include "llvm/IR/GlobalValue.h"
22 #include "llvm/IR/GlobalVariable.h"
23 #include "llvm/IR/MDBuilder.h"
24 #include "llvm/IR/Module.h"
25 #include "llvm/Support/CommandLine.h"
26 #include "llvm/Transforms/Utils/GlobalStatus.h"
27 #include "llvm/Transforms/Utils/ModuleUtils.h"
28 
29 using namespace llvm;
30 
31 #define DEBUG_TYPE "elim-avail-extern"
32 
33 static cl::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 
38 // This option was originally introduced to correctly support the lowering of
39 // LDS variables for AMDGPU when ThinLTO is enabled. It can be utilized for
40 // other purposes, but make sure it is safe to do so, as privatizing global
41 // variables is generally not safe.
42 static cl::opt<unsigned> ConvertGlobalVariableInAddrSpace(
43     "avail-extern-gv-in-addrspace-to-local", cl::Hidden,
44     cl::desc(
45         "Convert available_externally global variables into locals if they are "
46         "in specificed addrspace, renaming them to avoid link-time clashes."));
47 
48 STATISTIC(NumRemovals, "Number of functions removed");
49 STATISTIC(NumFunctionsConverted, "Number of functions converted");
50 STATISTIC(NumGlobalVariablesConverted, "Number of global variables converted");
51 STATISTIC(NumVariables, "Number of global variables removed");
52 
deleteFunction(Function & F)53 void deleteFunction(Function &F) {
54   // This will set the linkage to external
55   F.deleteBody();
56   ++NumRemovals;
57 }
58 
getNewName(Module & M,const GlobalValue & GV)59 static std::string getNewName(Module &M, const GlobalValue &GV) {
60   return GV.getName().str() + ".__uniq" + getUniqueModuleId(&M);
61 }
62 
63 /// Create a copy of the thinlto import, mark it local, and redirect direct
64 /// calls to the copy. Only direct calls are replaced, so that e.g. indirect
65 /// call function pointer tests would use the global identity of the function.
66 ///
67 /// Currently, Value Profiling ("VP") MD_prof data isn't updated to refer to the
68 /// clone's GUID (which will be different, because the name and linkage is
69 /// different), under the assumption that the last consumer of this data is
70 /// upstream the pipeline (e.g. ICP).
convertToLocalCopy(Module & M,Function & F)71 static void convertToLocalCopy(Module &M, Function &F) {
72   assert(F.hasAvailableExternallyLinkage());
73   assert(!F.isDeclaration());
74   // If we can't find a single use that's a call, just delete the function.
75   if (F.uses().end() == llvm::find_if(F.uses(), [&](Use &U) {
76         return isa<CallBase>(U.getUser());
77       }))
78     return deleteFunction(F);
79 
80   auto OrigName = F.getName().str();
81   // Build a new name. We still need the old name (see below).
82   // We could just rely on internal linking allowing 2 modules have internal
83   // functions with the same name, but that just creates more trouble than
84   // necessary e.g. distinguishing profiles or debugging. Instead, we append the
85   // module identifier.
86   std::string NewName = getNewName(M, F);
87   F.setName(NewName);
88   if (auto *SP = F.getSubprogram())
89     SP->replaceLinkageName(MDString::get(F.getParent()->getContext(), NewName));
90 
91   F.setLinkage(GlobalValue::InternalLinkage);
92   // Now make a declaration for the old name. We'll use it if there are non-call
93   // uses. For those, it would be incorrect to replace them with the local copy:
94   // for example, one such use could be taking the address of the function and
95   // passing it to an external function, which, in turn, might compare the
96   // function pointer to the original (non-local) function pointer, e.g. as part
97   // of indirect call promotion.
98   auto *Decl =
99       Function::Create(F.getFunctionType(), GlobalValue::ExternalLinkage,
100                        F.getAddressSpace(), OrigName, F.getParent());
101   F.replaceUsesWithIf(Decl,
102                       [&](Use &U) { return !isa<CallBase>(U.getUser()); });
103   ++NumFunctionsConverted;
104 }
105 
106 /// Similar to the function above, this is to convert an externally available
107 /// global variable to local.
convertToLocalCopy(Module & M,GlobalVariable & GV)108 static void convertToLocalCopy(Module &M, GlobalVariable &GV) {
109   assert(GV.hasAvailableExternallyLinkage());
110   GV.setName(getNewName(M, GV));
111   GV.setLinkage(GlobalValue::InternalLinkage);
112   ++NumGlobalVariablesConverted;
113 }
114 
eliminateAvailableExternally(Module & M,bool Convert)115 static bool eliminateAvailableExternally(Module &M, bool Convert) {
116   bool Changed = false;
117 
118   // If a global variable is available externally and in the specified address
119   // space, convert it to local linkage; otherwise, drop its initializer.
120   for (GlobalVariable &GV : M.globals()) {
121     if (!GV.hasAvailableExternallyLinkage())
122       continue;
123     if (ConvertGlobalVariableInAddrSpace.getNumOccurrences() &&
124         GV.getAddressSpace() == ConvertGlobalVariableInAddrSpace &&
125         !GV.use_empty()) {
126       convertToLocalCopy(M, GV);
127       Changed = true;
128       continue;
129     }
130     if (GV.hasInitializer()) {
131       Constant *Init = GV.getInitializer();
132       GV.setInitializer(nullptr);
133       if (isSafeToDestroyConstant(Init))
134         Init->destroyConstant();
135     }
136     GV.removeDeadConstantUsers();
137     GV.setLinkage(GlobalValue::ExternalLinkage);
138     ++NumVariables;
139     Changed = true;
140   }
141 
142   // Drop the bodies of available externally functions.
143   for (Function &F : llvm::make_early_inc_range(M)) {
144     if (F.isDeclaration() || !F.hasAvailableExternallyLinkage())
145       continue;
146 
147     if (Convert || ConvertToLocal)
148       convertToLocalCopy(M, F);
149     else
150       deleteFunction(F);
151 
152     F.removeDeadConstantUsers();
153     Changed = true;
154   }
155 
156   return Changed;
157 }
158 
159 PreservedAnalyses
run(Module & M,ModuleAnalysisManager & MAM)160 EliminateAvailableExternallyPass::run(Module &M, ModuleAnalysisManager &MAM) {
161   auto *CtxProf = MAM.getCachedResult<CtxProfAnalysis>(M);
162   // Convert to local instead of eliding if we use contextual profiling in this
163   // module. This is because the IPO decisions performed with contextual
164   // information will likely differ from decisions made without. For a function
165   // that's imported, its optimizations will, thus, differ, and be specialized
166   // for this contextual information. Eliding it in favor of the original would
167   // undo these optimizations.
168   if (!eliminateAvailableExternally(
169           M, /*Convert=*/(CtxProf && CtxProf->isInSpecializedModule())))
170     return PreservedAnalyses::all();
171   return PreservedAnalyses::none();
172 }
173