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.
makeVisible(GlobalValue & GV,bool Delete)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
52 /// If deleteS is true, this pass deletes the specified global values.
53 /// Otherwise, it deletes as much of the module as possible, except for the
54 /// global values specified.
ExtractGVPass(std::vector<GlobalValue * > & GVs,bool deleteS,bool keepConstInit)55 ExtractGVPass::ExtractGVPass(std::vector<GlobalValue *> &GVs, bool deleteS,
56 bool keepConstInit)
57 : Named(GVs.begin(), GVs.end()), deleteStuff(deleteS),
58 keepConstInit(keepConstInit) {}
59
run(Module & M,ModuleAnalysisManager &)60 PreservedAnalyses ExtractGVPass::run(Module &M, ModuleAnalysisManager &) {
61 // Visit the global inline asm.
62 if (!deleteStuff)
63 M.setModuleInlineAsm("");
64
65 // For simplicity, just give all GlobalValues ExternalLinkage. A trickier
66 // implementation could figure out which GlobalValues are actually
67 // referenced by the Named set, and which GlobalValues in the rest of
68 // the module are referenced by the NamedSet, and get away with leaving
69 // more internal and private things internal and private. But for now,
70 // be conservative and simple.
71
72 // Visit the GlobalVariables.
73 for (GlobalVariable &GV : M.globals()) {
74 bool Delete = deleteStuff == (bool)Named.count(&GV) &&
75 !GV.isDeclaration() && (!GV.isConstant() || !keepConstInit);
76 if (!Delete) {
77 if (GV.hasAvailableExternallyLinkage())
78 continue;
79 if (GV.getName() == "llvm.global_ctors")
80 continue;
81 }
82
83 makeVisible(GV, Delete);
84
85 if (Delete) {
86 // Make this a declaration and drop it's comdat.
87 GV.setInitializer(nullptr);
88 GV.setComdat(nullptr);
89 }
90 }
91
92 // Visit the Functions.
93 for (Function &F : M) {
94 bool Delete = deleteStuff == (bool)Named.count(&F) && !F.isDeclaration();
95 if (!Delete) {
96 if (F.hasAvailableExternallyLinkage())
97 continue;
98 }
99
100 makeVisible(F, Delete);
101
102 if (Delete) {
103 // Make this a declaration and drop it's comdat.
104 F.deleteBody();
105 F.setComdat(nullptr);
106 }
107 }
108
109 // Visit the Aliases.
110 for (GlobalAlias &GA : llvm::make_early_inc_range(M.aliases())) {
111 bool Delete = deleteStuff == (bool)Named.count(&GA);
112 makeVisible(GA, Delete);
113
114 if (Delete) {
115 Type *Ty = GA.getValueType();
116
117 GA.removeFromParent();
118 llvm::Value *Declaration;
119 if (FunctionType *FTy = dyn_cast<FunctionType>(Ty)) {
120 Declaration = Function::Create(FTy, GlobalValue::ExternalLinkage,
121 GA.getAddressSpace(), GA.getName(), &M);
122
123 } else {
124 Declaration = new GlobalVariable(
125 M, Ty, false, GlobalValue::ExternalLinkage, nullptr, GA.getName());
126 }
127 GA.replaceAllUsesWith(Declaration);
128 delete &GA;
129 }
130 }
131
132 return PreservedAnalyses::none();
133 }
134