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::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::run(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(&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(&F) && !F.isDeclaration();
94     if (!Delete) {
95       if (F.hasAvailableExternallyLinkage())
96         continue;
97     }
98 
99     makeVisible(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(M.aliases())) {
110     bool Delete = deleteStuff == (bool)Named.count(&GA);
111     makeVisible(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>(Ty)) {
119         Declaration = Function::Create(FTy, GlobalValue::ExternalLinkage,
120                                        GA.getAddressSpace(), GA.getName(), &M);
121 
122       } else {
123         Declaration = new GlobalVariable(
124             M, Ty, false, GlobalValue::ExternalLinkage, nullptr, GA.getName());
125       }
126       GA.replaceAllUsesWith(Declaration);
127       delete &GA;
128     }
129   }
130 
131   // Visit the IFuncs.
132   for (GlobalIFunc &IF : llvm::make_early_inc_range(M.ifuncs())) {
133     bool Delete = deleteStuff == (bool)Named.count(&IF);
134     makeVisible(IF, Delete);
135 
136     if (!Delete)
137       continue;
138 
139     auto *FuncType = dyn_cast<FunctionType>(IF.getValueType());
140     IF.removeFromParent();
141     llvm::Value *Declaration =
142         Function::Create(FuncType, GlobalValue::ExternalLinkage,
143                          IF.getAddressSpace(), IF.getName(), &M);
144     IF.replaceAllUsesWith(Declaration);
145     delete &IF;
146   }
147 
148   return PreservedAnalyses::none();
149 }
150