1 | //===-- ExtractGV.cpp - Global Value extraction pass ----------------------===// |
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 pass extracts global values |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/Transforms/IPO/ExtractGV.h" |
14 | #include "llvm/IR/Module.h" |
15 | #include "llvm/IR/PassManager.h" |
16 | #include <algorithm> |
17 | |
18 | using namespace llvm; |
19 | |
20 | /// Make sure GV is visible from both modules. Delete is true if it is |
21 | /// being deleted from this module. |
22 | /// This also makes sure GV cannot be dropped so that references from |
23 | /// the split module remain valid. |
24 | static void makeVisible(GlobalValue &GV, bool Delete) { |
25 | bool Local = GV.hasLocalLinkage(); |
26 | if (Local || Delete) { |
27 | GV.setLinkage(GlobalValue::ExternalLinkage); |
28 | if (Local) |
29 | GV.setVisibility(GlobalValue::HiddenVisibility); |
30 | return; |
31 | } |
32 | |
33 | if (!GV.hasLinkOnceLinkage()) { |
34 | assert(!GV.isDiscardableIfUnused()); |
35 | return; |
36 | } |
37 | |
38 | // Map linkonce* to weak* so that llvm doesn't drop this GV. |
39 | switch (GV.getLinkage()) { |
40 | default: |
41 | llvm_unreachable("Unexpected linkage" ); |
42 | case GlobalValue::LinkOnceAnyLinkage: |
43 | GV.setLinkage(GlobalValue::WeakAnyLinkage); |
44 | return; |
45 | case GlobalValue::LinkOnceODRLinkage: |
46 | GV.setLinkage(GlobalValue::WeakODRLinkage); |
47 | return; |
48 | } |
49 | } |
50 | |
51 | /// If deleteS is true, this pass deletes the specified global values. |
52 | /// Otherwise, it deletes as much of the module as possible, except for the |
53 | /// global values specified. |
54 | ExtractGVPass::(std::vector<GlobalValue *> &GVs, bool deleteS, |
55 | bool keepConstInit) |
56 | : Named(GVs.begin(), GVs.end()), deleteStuff(deleteS), |
57 | keepConstInit(keepConstInit) {} |
58 | |
59 | PreservedAnalyses ExtractGVPass::(Module &M, ModuleAnalysisManager &) { |
60 | // Visit the global inline asm. |
61 | if (!deleteStuff) |
62 | M.setModuleInlineAsm("" ); |
63 | |
64 | // For simplicity, just give all GlobalValues ExternalLinkage. A trickier |
65 | // implementation could figure out which GlobalValues are actually |
66 | // referenced by the Named set, and which GlobalValues in the rest of |
67 | // the module are referenced by the NamedSet, and get away with leaving |
68 | // more internal and private things internal and private. But for now, |
69 | // be conservative and simple. |
70 | |
71 | // Visit the GlobalVariables. |
72 | for (GlobalVariable &GV : M.globals()) { |
73 | bool Delete = deleteStuff == (bool)Named.count(key: &GV) && |
74 | !GV.isDeclaration() && (!GV.isConstant() || !keepConstInit); |
75 | if (!Delete) { |
76 | if (GV.hasAvailableExternallyLinkage()) |
77 | continue; |
78 | if (GV.getName() == "llvm.global_ctors" ) |
79 | continue; |
80 | } |
81 | |
82 | makeVisible(GV, Delete); |
83 | |
84 | if (Delete) { |
85 | // Make this a declaration and drop it's comdat. |
86 | GV.setInitializer(nullptr); |
87 | GV.setComdat(nullptr); |
88 | } |
89 | } |
90 | |
91 | // Visit the Functions. |
92 | for (Function &F : M) { |
93 | bool Delete = deleteStuff == (bool)Named.count(key: &F) && !F.isDeclaration(); |
94 | if (!Delete) { |
95 | if (F.hasAvailableExternallyLinkage()) |
96 | continue; |
97 | } |
98 | |
99 | makeVisible(GV&: F, Delete); |
100 | |
101 | if (Delete) { |
102 | // Make this a declaration and drop it's comdat. |
103 | F.deleteBody(); |
104 | F.setComdat(nullptr); |
105 | } |
106 | } |
107 | |
108 | // Visit the Aliases. |
109 | for (GlobalAlias &GA : llvm::make_early_inc_range(Range: M.aliases())) { |
110 | bool Delete = deleteStuff == (bool)Named.count(key: &GA); |
111 | makeVisible(GV&: GA, Delete); |
112 | |
113 | if (Delete) { |
114 | Type *Ty = GA.getValueType(); |
115 | |
116 | GA.removeFromParent(); |
117 | llvm::Value *Declaration; |
118 | if (FunctionType *FTy = dyn_cast<FunctionType>(Val: Ty)) { |
119 | Declaration = Function::Create(Ty: FTy, Linkage: GlobalValue::ExternalLinkage, |
120 | AddrSpace: GA.getAddressSpace(), N: GA.getName(), M: &M); |
121 | |
122 | } else { |
123 | Declaration = new GlobalVariable( |
124 | M, Ty, false, GlobalValue::ExternalLinkage, nullptr, GA.getName()); |
125 | } |
126 | GA.replaceAllUsesWith(V: Declaration); |
127 | delete &GA; |
128 | } |
129 | } |
130 | |
131 | // Visit the IFuncs. |
132 | for (GlobalIFunc &IF : llvm::make_early_inc_range(Range: M.ifuncs())) { |
133 | bool Delete = deleteStuff == (bool)Named.count(key: &IF); |
134 | makeVisible(GV&: IF, Delete); |
135 | |
136 | if (!Delete) |
137 | continue; |
138 | |
139 | auto *FuncType = dyn_cast<FunctionType>(Val: IF.getValueType()); |
140 | IF.removeFromParent(); |
141 | llvm::Value *Declaration = |
142 | Function::Create(Ty: FuncType, Linkage: GlobalValue::ExternalLinkage, |
143 | AddrSpace: IF.getAddressSpace(), N: IF.getName(), M: &M); |
144 | IF.replaceAllUsesWith(V: Declaration); |
145 | delete &IF; |
146 | } |
147 | |
148 | return PreservedAnalyses::none(); |
149 | } |
150 | |