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