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(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 | |
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(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 | |
127 | PreservedAnalyses |
128 | EliminateAvailableExternallyPass::run(Module &M, ModuleAnalysisManager &) { |
129 | if (!eliminateAvailableExternally(M)) |
130 | return PreservedAnalyses::all(); |
131 | return PreservedAnalyses::none(); |
132 | } |
133 | |