xref: /llvm-project/llvm/lib/Transforms/IPO/ExtractGV.cpp (revision 98ea1a81a28a6dd36941456c8ab4ce46f665f57a)
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::ExtractGVPass(std::vector<GlobalValue *> &GVs, bool deleteS,
54                              bool keepConstInit)
55     : Named(GVs.begin(), GVs.end()), deleteStuff(deleteS),
56       keepConstInit(keepConstInit) {}
57 
58 PreservedAnalyses ExtractGVPass::run(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(&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(&F) && !F.isDeclaration();
93     if (!Delete) {
94       if (F.hasAvailableExternallyLinkage())
95         continue;
96     }
97 
98     makeVisible(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(M.aliases())) {
109     bool Delete = deleteStuff == (bool)Named.count(&GA);
110     makeVisible(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>(Ty)) {
118         Declaration = Function::Create(FTy, GlobalValue::ExternalLinkage,
119                                        GA.getAddressSpace(), GA.getName(), &M);
120 
121       } else {
122         Declaration = new GlobalVariable(
123             M, Ty, false, GlobalValue::ExternalLinkage, nullptr, GA.getName());
124       }
125       GA.replaceAllUsesWith(Declaration);
126       delete &GA;
127     }
128   }
129 
130   // Visit the IFuncs.
131   for (GlobalIFunc &IF : llvm::make_early_inc_range(M.ifuncs())) {
132     bool Delete = deleteStuff == (bool)Named.count(&IF);
133     makeVisible(IF, Delete);
134 
135     if (!Delete)
136       continue;
137 
138     auto *FuncType = dyn_cast<FunctionType>(IF.getValueType());
139     IF.removeFromParent();
140     llvm::Value *Declaration =
141         Function::Create(FuncType, GlobalValue::ExternalLinkage,
142                          IF.getAddressSpace(), IF.getName(), &M);
143     IF.replaceAllUsesWith(Declaration);
144     delete &IF;
145   }
146 
147   return PreservedAnalyses::none();
148 }
149