10b57cec5SDimitry Andric //===-- ExtractGV.cpp - Global Value extraction pass ----------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This pass extracts global values
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
13bdd1243dSDimitry Andric #include "llvm/Transforms/IPO/ExtractGV.h"
140b57cec5SDimitry Andric #include "llvm/IR/Module.h"
15bdd1243dSDimitry Andric #include "llvm/IR/PassManager.h"
160b57cec5SDimitry Andric #include <algorithm>
17bdd1243dSDimitry Andric
180b57cec5SDimitry Andric using namespace llvm;
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric /// Make sure GV is visible from both modules. Delete is true if it is
210b57cec5SDimitry Andric /// being deleted from this module.
220b57cec5SDimitry Andric /// This also makes sure GV cannot be dropped so that references from
230b57cec5SDimitry Andric /// the split module remain valid.
makeVisible(GlobalValue & GV,bool Delete)240b57cec5SDimitry Andric static void makeVisible(GlobalValue &GV, bool Delete) {
250b57cec5SDimitry Andric bool Local = GV.hasLocalLinkage();
260b57cec5SDimitry Andric if (Local || Delete) {
270b57cec5SDimitry Andric GV.setLinkage(GlobalValue::ExternalLinkage);
280b57cec5SDimitry Andric if (Local)
290b57cec5SDimitry Andric GV.setVisibility(GlobalValue::HiddenVisibility);
300b57cec5SDimitry Andric return;
310b57cec5SDimitry Andric }
320b57cec5SDimitry Andric
330b57cec5SDimitry Andric if (!GV.hasLinkOnceLinkage()) {
340b57cec5SDimitry Andric assert(!GV.isDiscardableIfUnused());
350b57cec5SDimitry Andric return;
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric
380b57cec5SDimitry Andric // Map linkonce* to weak* so that llvm doesn't drop this GV.
390b57cec5SDimitry Andric switch (GV.getLinkage()) {
400b57cec5SDimitry Andric default:
410b57cec5SDimitry Andric llvm_unreachable("Unexpected linkage");
420b57cec5SDimitry Andric case GlobalValue::LinkOnceAnyLinkage:
430b57cec5SDimitry Andric GV.setLinkage(GlobalValue::WeakAnyLinkage);
440b57cec5SDimitry Andric return;
450b57cec5SDimitry Andric case GlobalValue::LinkOnceODRLinkage:
460b57cec5SDimitry Andric GV.setLinkage(GlobalValue::WeakODRLinkage);
470b57cec5SDimitry Andric return;
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric /// If deleteS is true, this pass deletes the specified global values.
520b57cec5SDimitry Andric /// Otherwise, it deletes as much of the module as possible, except for the
530b57cec5SDimitry Andric /// global values specified.
ExtractGVPass(std::vector<GlobalValue * > & GVs,bool deleteS,bool keepConstInit)54bdd1243dSDimitry Andric ExtractGVPass::ExtractGVPass(std::vector<GlobalValue *> &GVs, bool deleteS,
55bdd1243dSDimitry Andric bool keepConstInit)
56bdd1243dSDimitry Andric : Named(GVs.begin(), GVs.end()), deleteStuff(deleteS),
575ffd83dbSDimitry Andric keepConstInit(keepConstInit) {}
580b57cec5SDimitry Andric
run(Module & M,ModuleAnalysisManager &)59bdd1243dSDimitry Andric PreservedAnalyses ExtractGVPass::run(Module &M, ModuleAnalysisManager &) {
600b57cec5SDimitry Andric // Visit the global inline asm.
610b57cec5SDimitry Andric if (!deleteStuff)
620b57cec5SDimitry Andric M.setModuleInlineAsm("");
630b57cec5SDimitry Andric
640b57cec5SDimitry Andric // For simplicity, just give all GlobalValues ExternalLinkage. A trickier
650b57cec5SDimitry Andric // implementation could figure out which GlobalValues are actually
660b57cec5SDimitry Andric // referenced by the Named set, and which GlobalValues in the rest of
670b57cec5SDimitry Andric // the module are referenced by the NamedSet, and get away with leaving
680b57cec5SDimitry Andric // more internal and private things internal and private. But for now,
690b57cec5SDimitry Andric // be conservative and simple.
700b57cec5SDimitry Andric
710b57cec5SDimitry Andric // Visit the GlobalVariables.
72fe6060f1SDimitry Andric for (GlobalVariable &GV : M.globals()) {
73fe6060f1SDimitry Andric bool Delete = deleteStuff == (bool)Named.count(&GV) &&
74bdd1243dSDimitry Andric !GV.isDeclaration() && (!GV.isConstant() || !keepConstInit);
750b57cec5SDimitry Andric if (!Delete) {
76fe6060f1SDimitry Andric if (GV.hasAvailableExternallyLinkage())
770b57cec5SDimitry Andric continue;
78fe6060f1SDimitry Andric if (GV.getName() == "llvm.global_ctors")
790b57cec5SDimitry Andric continue;
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric
82fe6060f1SDimitry Andric makeVisible(GV, Delete);
830b57cec5SDimitry Andric
840b57cec5SDimitry Andric if (Delete) {
850b57cec5SDimitry Andric // Make this a declaration and drop it's comdat.
86fe6060f1SDimitry Andric GV.setInitializer(nullptr);
87fe6060f1SDimitry Andric GV.setComdat(nullptr);
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric
910b57cec5SDimitry Andric // Visit the Functions.
920b57cec5SDimitry Andric for (Function &F : M) {
93bdd1243dSDimitry Andric bool Delete = deleteStuff == (bool)Named.count(&F) && !F.isDeclaration();
940b57cec5SDimitry Andric if (!Delete) {
950b57cec5SDimitry Andric if (F.hasAvailableExternallyLinkage())
960b57cec5SDimitry Andric continue;
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric
990b57cec5SDimitry Andric makeVisible(F, Delete);
1000b57cec5SDimitry Andric
1010b57cec5SDimitry Andric if (Delete) {
1020b57cec5SDimitry Andric // Make this a declaration and drop it's comdat.
1030b57cec5SDimitry Andric F.deleteBody();
1040b57cec5SDimitry Andric F.setComdat(nullptr);
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric
1080b57cec5SDimitry Andric // Visit the Aliases.
109349cc55cSDimitry Andric for (GlobalAlias &GA : llvm::make_early_inc_range(M.aliases())) {
110349cc55cSDimitry Andric bool Delete = deleteStuff == (bool)Named.count(&GA);
111349cc55cSDimitry Andric makeVisible(GA, Delete);
1120b57cec5SDimitry Andric
1130b57cec5SDimitry Andric if (Delete) {
114349cc55cSDimitry Andric Type *Ty = GA.getValueType();
1150b57cec5SDimitry Andric
116349cc55cSDimitry Andric GA.removeFromParent();
1170b57cec5SDimitry Andric llvm::Value *Declaration;
1180b57cec5SDimitry Andric if (FunctionType *FTy = dyn_cast<FunctionType>(Ty)) {
119bdd1243dSDimitry Andric Declaration = Function::Create(FTy, GlobalValue::ExternalLinkage,
120349cc55cSDimitry Andric GA.getAddressSpace(), GA.getName(), &M);
1210b57cec5SDimitry Andric
1220b57cec5SDimitry Andric } else {
123bdd1243dSDimitry Andric Declaration = new GlobalVariable(
124bdd1243dSDimitry Andric M, Ty, false, GlobalValue::ExternalLinkage, nullptr, GA.getName());
1250b57cec5SDimitry Andric }
126349cc55cSDimitry Andric GA.replaceAllUsesWith(Declaration);
127349cc55cSDimitry Andric delete &GA;
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric
131*06c3fb27SDimitry Andric // Visit the IFuncs.
132*06c3fb27SDimitry Andric for (GlobalIFunc &IF : llvm::make_early_inc_range(M.ifuncs())) {
133*06c3fb27SDimitry Andric bool Delete = deleteStuff == (bool)Named.count(&IF);
134*06c3fb27SDimitry Andric makeVisible(IF, Delete);
135*06c3fb27SDimitry Andric
136*06c3fb27SDimitry Andric if (!Delete)
137*06c3fb27SDimitry Andric continue;
138*06c3fb27SDimitry Andric
139*06c3fb27SDimitry Andric auto *FuncType = dyn_cast<FunctionType>(IF.getValueType());
140*06c3fb27SDimitry Andric IF.removeFromParent();
141*06c3fb27SDimitry Andric llvm::Value *Declaration =
142*06c3fb27SDimitry Andric Function::Create(FuncType, GlobalValue::ExternalLinkage,
143*06c3fb27SDimitry Andric IF.getAddressSpace(), IF.getName(), &M);
144*06c3fb27SDimitry Andric IF.replaceAllUsesWith(Declaration);
145*06c3fb27SDimitry Andric delete &IF;
146*06c3fb27SDimitry Andric }
147*06c3fb27SDimitry Andric
148bdd1243dSDimitry Andric return PreservedAnalyses::none();
1490b57cec5SDimitry Andric }
150