xref: /freebsd/contrib/llvm-project/llvm/lib/Transforms/IPO/ElimAvailExtern.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
10b57cec5SDimitry Andric //===- ElimAvailExtern.cpp - DCE unreachable internal functions -----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This transform is designed to eliminate available external global
100b57cec5SDimitry Andric // definitions from the program, turning them into declarations.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/Transforms/IPO/ElimAvailExtern.h"
15*06c3fb27SDimitry Andric #include "llvm/ADT/STLExtras.h"
160b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
170b57cec5SDimitry Andric #include "llvm/IR/Constant.h"
18*06c3fb27SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
190b57cec5SDimitry Andric #include "llvm/IR/Function.h"
200b57cec5SDimitry Andric #include "llvm/IR/GlobalValue.h"
210b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h"
22*06c3fb27SDimitry Andric #include "llvm/IR/MDBuilder.h"
230b57cec5SDimitry Andric #include "llvm/IR/Module.h"
24*06c3fb27SDimitry Andric #include "llvm/Support/CommandLine.h"
250b57cec5SDimitry Andric #include "llvm/Transforms/IPO.h"
260b57cec5SDimitry Andric #include "llvm/Transforms/Utils/GlobalStatus.h"
27*06c3fb27SDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h"
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric using namespace llvm;
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric #define DEBUG_TYPE "elim-avail-extern"
320b57cec5SDimitry Andric 
33*06c3fb27SDimitry Andric cl::opt<bool> ConvertToLocal(
34*06c3fb27SDimitry Andric     "avail-extern-to-local", cl::Hidden,
35*06c3fb27SDimitry Andric     cl::desc("Convert available_externally into locals, renaming them "
36*06c3fb27SDimitry Andric              "to avoid link-time clashes."));
37*06c3fb27SDimitry Andric 
38*06c3fb27SDimitry Andric STATISTIC(NumRemovals, "Number of functions removed");
39*06c3fb27SDimitry Andric STATISTIC(NumConversions, "Number of functions converted");
400b57cec5SDimitry Andric STATISTIC(NumVariables, "Number of global variables removed");
410b57cec5SDimitry Andric 
deleteFunction(Function & F)42*06c3fb27SDimitry Andric void deleteFunction(Function &F) {
43*06c3fb27SDimitry Andric   // This will set the linkage to external
44*06c3fb27SDimitry Andric   F.deleteBody();
45*06c3fb27SDimitry Andric   ++NumRemovals;
46*06c3fb27SDimitry Andric }
47*06c3fb27SDimitry Andric 
48*06c3fb27SDimitry Andric /// Create a copy of the thinlto import, mark it local, and redirect direct
49*06c3fb27SDimitry Andric /// calls to the copy. Only direct calls are replaced, so that e.g. indirect
50*06c3fb27SDimitry Andric /// call function pointer tests would use the global identity of the function.
51*06c3fb27SDimitry Andric ///
52*06c3fb27SDimitry Andric /// Currently, Value Profiling ("VP") MD_prof data isn't updated to refer to the
53*06c3fb27SDimitry Andric /// clone's GUID (which will be different, because the name and linkage is
54*06c3fb27SDimitry Andric /// different), under the assumption that the last consumer of this data is
55*06c3fb27SDimitry Andric /// upstream the pipeline (e.g. ICP).
convertToLocalCopy(Module & M,Function & F)56*06c3fb27SDimitry Andric static void convertToLocalCopy(Module &M, Function &F) {
57*06c3fb27SDimitry Andric   assert(F.hasAvailableExternallyLinkage());
58*06c3fb27SDimitry Andric   assert(!F.isDeclaration());
59*06c3fb27SDimitry Andric   // If we can't find a single use that's a call, just delete the function.
60*06c3fb27SDimitry Andric   if (F.uses().end() == llvm::find_if(F.uses(), [&](Use &U) {
61*06c3fb27SDimitry Andric         return isa<CallBase>(U.getUser());
62*06c3fb27SDimitry Andric       }))
63*06c3fb27SDimitry Andric     return deleteFunction(F);
64*06c3fb27SDimitry Andric 
65*06c3fb27SDimitry Andric   auto OrigName = F.getName().str();
66*06c3fb27SDimitry Andric   // Build a new name. We still need the old name (see below).
67*06c3fb27SDimitry Andric   // We could just rely on internal linking allowing 2 modules have internal
68*06c3fb27SDimitry Andric   // functions with the same name, but that just creates more trouble than
69*06c3fb27SDimitry Andric   // necessary e.g. distinguishing profiles or debugging. Instead, we append the
70*06c3fb27SDimitry Andric   // module identifier.
71*06c3fb27SDimitry Andric   auto NewName = OrigName + ".__uniq" + getUniqueModuleId(&M);
72*06c3fb27SDimitry Andric   F.setName(NewName);
73*06c3fb27SDimitry Andric   if (auto *SP = F.getSubprogram())
74*06c3fb27SDimitry Andric     SP->replaceLinkageName(MDString::get(F.getParent()->getContext(), NewName));
75*06c3fb27SDimitry Andric 
76*06c3fb27SDimitry Andric   F.setLinkage(GlobalValue::InternalLinkage);
77*06c3fb27SDimitry Andric   // Now make a declaration for the old name. We'll use it if there are non-call
78*06c3fb27SDimitry Andric   // uses. For those, it would be incorrect to replace them with the local copy:
79*06c3fb27SDimitry Andric   // for example, one such use could be taking the address of the function and
80*06c3fb27SDimitry Andric   // passing it to an external function, which, in turn, might compare the
81*06c3fb27SDimitry Andric   // function pointer to the original (non-local) function pointer, e.g. as part
82*06c3fb27SDimitry Andric   // of indirect call promotion.
83*06c3fb27SDimitry Andric   auto *Decl =
84*06c3fb27SDimitry Andric       Function::Create(F.getFunctionType(), GlobalValue::ExternalLinkage,
85*06c3fb27SDimitry Andric                        F.getAddressSpace(), OrigName, F.getParent());
86*06c3fb27SDimitry Andric   F.replaceUsesWithIf(Decl,
87*06c3fb27SDimitry Andric                       [&](Use &U) { return !isa<CallBase>(U.getUser()); });
88*06c3fb27SDimitry Andric   ++NumConversions;
89*06c3fb27SDimitry Andric }
90*06c3fb27SDimitry Andric 
eliminateAvailableExternally(Module & M)910b57cec5SDimitry Andric static bool eliminateAvailableExternally(Module &M) {
920b57cec5SDimitry Andric   bool Changed = false;
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric   // Drop initializers of available externally global variables.
950b57cec5SDimitry Andric   for (GlobalVariable &GV : M.globals()) {
960b57cec5SDimitry Andric     if (!GV.hasAvailableExternallyLinkage())
970b57cec5SDimitry Andric       continue;
980b57cec5SDimitry Andric     if (GV.hasInitializer()) {
990b57cec5SDimitry Andric       Constant *Init = GV.getInitializer();
1000b57cec5SDimitry Andric       GV.setInitializer(nullptr);
1010b57cec5SDimitry Andric       if (isSafeToDestroyConstant(Init))
1020b57cec5SDimitry Andric         Init->destroyConstant();
1030b57cec5SDimitry Andric     }
1040b57cec5SDimitry Andric     GV.removeDeadConstantUsers();
1050b57cec5SDimitry Andric     GV.setLinkage(GlobalValue::ExternalLinkage);
106*06c3fb27SDimitry Andric     ++NumVariables;
1070b57cec5SDimitry Andric     Changed = true;
1080b57cec5SDimitry Andric   }
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   // Drop the bodies of available externally functions.
111*06c3fb27SDimitry Andric   for (Function &F : llvm::make_early_inc_range(M)) {
112*06c3fb27SDimitry Andric     if (F.isDeclaration() || !F.hasAvailableExternallyLinkage())
1130b57cec5SDimitry Andric       continue;
114*06c3fb27SDimitry Andric 
115*06c3fb27SDimitry Andric     if (ConvertToLocal)
116*06c3fb27SDimitry Andric       convertToLocalCopy(M, F);
117*06c3fb27SDimitry Andric     else
118*06c3fb27SDimitry Andric       deleteFunction(F);
119*06c3fb27SDimitry Andric 
1200b57cec5SDimitry Andric     F.removeDeadConstantUsers();
1210b57cec5SDimitry Andric     Changed = true;
1220b57cec5SDimitry Andric   }
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   return Changed;
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric PreservedAnalyses
run(Module & M,ModuleAnalysisManager &)1280b57cec5SDimitry Andric EliminateAvailableExternallyPass::run(Module &M, ModuleAnalysisManager &) {
1290b57cec5SDimitry Andric   if (!eliminateAvailableExternally(M))
1300b57cec5SDimitry Andric     return PreservedAnalyses::all();
1310b57cec5SDimitry Andric   return PreservedAnalyses::none();
1320b57cec5SDimitry Andric }
133