xref: /freebsd/contrib/llvm-project/llvm/lib/Transforms/IPO/ElimAvailExtern.cpp (revision 0ad011ececb978e22a9bff2acf76633b094f1ff6)
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 
29 using namespace llvm;
30 
31 #define DEBUG_TYPE "elim-avail-extern"
32 
33 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 STATISTIC(NumRemovals, "Number of functions removed");
39 STATISTIC(NumConversions, "Number of functions converted");
40 STATISTIC(NumVariables, "Number of global variables removed");
41 
42 void 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).
56 static 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(F.uses(), [&](Use &U) {
61         return isa<CallBase>(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);
72   F.setName(NewName);
73   if (auto *SP = F.getSubprogram())
74     SP->replaceLinkageName(MDString::get(F.getParent()->getContext(), 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(F.getFunctionType(), GlobalValue::ExternalLinkage,
85                        F.getAddressSpace(), OrigName, F.getParent());
86   F.replaceUsesWithIf(Decl,
87                       [&](Use &U) { return !isa<CallBase>(U.getUser()); });
88   ++NumConversions;
89 }
90 
91 static 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(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(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 
127 PreservedAnalyses
128 EliminateAvailableExternallyPass::run(Module &M, ModuleAnalysisManager &) {
129   if (!eliminateAvailableExternally(M))
130     return PreservedAnalyses::all();
131   return PreservedAnalyses::none();
132 }
133