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
18using 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.
24static 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.
54ExtractGVPass::ExtractGVPass(std::vector<GlobalValue *> &GVs, bool deleteS,
55 bool keepConstInit)
56 : Named(GVs.begin(), GVs.end()), deleteStuff(deleteS),
57 keepConstInit(keepConstInit) {}
58
59PreservedAnalyses 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(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