1 //===-- ExtractGV.cpp - Global Value extraction pass ----------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This pass extracts global values
11 //===----------------------------------------------------------------------===//
13 #include "llvm/ADT/SetVector.h"
14 #include "llvm/IR/Module.h"
15 #include "llvm/Pass.h"
16 #include "llvm/Transforms/IPO.h"
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
);
29 GV
.setVisibility(GlobalValue::HiddenVisibility
);
33 if (!GV
.hasLinkOnceLinkage()) {
34 assert(!GV
.isDiscardableIfUnused());
38 // Map linkonce* to weak* so that llvm doesn't drop this GV.
39 switch(GV
.getLinkage()) {
41 llvm_unreachable("Unexpected linkage");
42 case GlobalValue::LinkOnceAnyLinkage
:
43 GV
.setLinkage(GlobalValue::WeakAnyLinkage
);
45 case GlobalValue::LinkOnceODRLinkage
:
46 GV
.setLinkage(GlobalValue::WeakODRLinkage
);
52 /// A pass to extract specific global values and their dependencies.
53 class GVExtractorPass
: public ModulePass
{
54 SetVector
<GlobalValue
*> Named
;
58 static char ID
; // Pass identification, replacement for typeid
60 /// If deleteS is true, this pass deletes the specified global values.
61 /// Otherwise, it deletes as much of the module as possible, except for the
62 /// global values specified.
63 explicit GVExtractorPass(std::vector
<GlobalValue
*> &GVs
,
64 bool deleteS
= true, bool keepConstInit
= false)
65 : ModulePass(ID
), Named(GVs
.begin(), GVs
.end()), deleteStuff(deleteS
),
66 keepConstInit(keepConstInit
) {}
68 bool runOnModule(Module
&M
) override
{
72 // Visit the global inline asm.
74 M
.setModuleInlineAsm("");
76 // For simplicity, just give all GlobalValues ExternalLinkage. A trickier
77 // implementation could figure out which GlobalValues are actually
78 // referenced by the Named set, and which GlobalValues in the rest of
79 // the module are referenced by the NamedSet, and get away with leaving
80 // more internal and private things internal and private. But for now,
81 // be conservative and simple.
83 // Visit the GlobalVariables.
84 for (GlobalVariable
&GV
: M
.globals()) {
85 bool Delete
= deleteStuff
== (bool)Named
.count(&GV
) &&
86 !GV
.isDeclaration() &&
87 (!GV
.isConstant() || !keepConstInit
);
89 if (GV
.hasAvailableExternallyLinkage())
91 if (GV
.getName() == "llvm.global_ctors")
95 makeVisible(GV
, Delete
);
98 // Make this a declaration and drop it's comdat.
99 GV
.setInitializer(nullptr);
100 GV
.setComdat(nullptr);
104 // Visit the Functions.
105 for (Function
&F
: M
) {
107 deleteStuff
== (bool)Named
.count(&F
) && !F
.isDeclaration();
109 if (F
.hasAvailableExternallyLinkage())
113 makeVisible(F
, Delete
);
116 // Make this a declaration and drop it's comdat.
118 F
.setComdat(nullptr);
122 // Visit the Aliases.
123 for (GlobalAlias
&GA
: llvm::make_early_inc_range(M
.aliases())) {
124 bool Delete
= deleteStuff
== (bool)Named
.count(&GA
);
125 makeVisible(GA
, Delete
);
128 Type
*Ty
= GA
.getValueType();
130 GA
.removeFromParent();
131 llvm::Value
*Declaration
;
132 if (FunctionType
*FTy
= dyn_cast
<FunctionType
>(Ty
)) {
134 Function::Create(FTy
, GlobalValue::ExternalLinkage
,
135 GA
.getAddressSpace(), GA
.getName(), &M
);
139 new GlobalVariable(M
, Ty
, false, GlobalValue::ExternalLinkage
,
140 nullptr, GA
.getName());
142 GA
.replaceAllUsesWith(Declaration
);
151 char GVExtractorPass::ID
= 0;
154 ModulePass
*llvm::createGVExtractionPass(std::vector
<GlobalValue
*> &GVs
,
155 bool deleteFn
, bool keepConstInit
) {
156 return new GVExtractorPass(GVs
, deleteFn
, keepConstInit
);