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/ADT/SetVector.h" 14 #include "llvm/IR/Module.h" 15 #include "llvm/Pass.h" 16 #include "llvm/Transforms/IPO.h" 17 #include <algorithm> 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 namespace { 52 /// A pass to extract specific global values and their dependencies. 53 class GVExtractorPass : public ModulePass { 54 SetVector<GlobalValue *> Named; 55 bool deleteStuff; 56 bool keepConstInit; 57 public: 58 static char ID; // Pass identification, replacement for typeid 59 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) {} 67 68 bool runOnModule(Module &M) override { 69 if (skipModule(M)) 70 return false; 71 72 // Visit the global inline asm. 73 if (!deleteStuff) 74 M.setModuleInlineAsm(""); 75 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. 82 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); 88 if (!Delete) { 89 if (GV.hasAvailableExternallyLinkage()) 90 continue; 91 if (GV.getName() == "llvm.global_ctors") 92 continue; 93 } 94 95 makeVisible(GV, Delete); 96 97 if (Delete) { 98 // Make this a declaration and drop it's comdat. 99 GV.setInitializer(nullptr); 100 GV.setComdat(nullptr); 101 } 102 } 103 104 // Visit the Functions. 105 for (Function &F : M) { 106 bool Delete = 107 deleteStuff == (bool)Named.count(&F) && !F.isDeclaration(); 108 if (!Delete) { 109 if (F.hasAvailableExternallyLinkage()) 110 continue; 111 } 112 113 makeVisible(F, Delete); 114 115 if (Delete) { 116 // Make this a declaration and drop it's comdat. 117 F.deleteBody(); 118 F.setComdat(nullptr); 119 } 120 } 121 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); 126 127 if (Delete) { 128 Type *Ty = GA.getValueType(); 129 130 GA.removeFromParent(); 131 llvm::Value *Declaration; 132 if (FunctionType *FTy = dyn_cast<FunctionType>(Ty)) { 133 Declaration = 134 Function::Create(FTy, GlobalValue::ExternalLinkage, 135 GA.getAddressSpace(), GA.getName(), &M); 136 137 } else { 138 Declaration = 139 new GlobalVariable(M, Ty, false, GlobalValue::ExternalLinkage, 140 nullptr, GA.getName()); 141 } 142 GA.replaceAllUsesWith(Declaration); 143 delete &GA; 144 } 145 } 146 147 return true; 148 } 149 }; 150 151 char GVExtractorPass::ID = 0; 152 } 153 154 ModulePass *llvm::createGVExtractionPass(std::vector<GlobalValue *> &GVs, 155 bool deleteFn, bool keepConstInit) { 156 return new GVExtractorPass(GVs, deleteFn, keepConstInit); 157 } 158