#include "llvm/ADT/SetVector.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/IPO.h"
#include <algorithm>
using namespace llvm;
static void makeVisible(GlobalValue &GV, bool Delete) {
bool Local = GV.hasLocalLinkage();
if (Local || Delete) {
GV.setLinkage(GlobalValue::ExternalLinkage);
if (Local)
GV.setVisibility(GlobalValue::HiddenVisibility);
return;
}
if (!GV.hasLinkOnceLinkage()) {
assert(!GV.isDiscardableIfUnused());
return;
}
switch(GV.getLinkage()) {
default:
llvm_unreachable("Unexpected linkage");
case GlobalValue::LinkOnceAnyLinkage:
GV.setLinkage(GlobalValue::WeakAnyLinkage);
return;
case GlobalValue::LinkOnceODRLinkage:
GV.setLinkage(GlobalValue::WeakODRLinkage);
return;
}
}
namespace {
class GVExtractorPass : public ModulePass {
SetVector<GlobalValue *> Named;
bool deleteStuff;
bool keepConstInit;
public:
static char ID;
explicit GVExtractorPass(std::vector<GlobalValue*> &GVs,
bool deleteS = true, bool keepConstInit = false)
: ModulePass(ID), Named(GVs.begin(), GVs.end()), deleteStuff(deleteS),
keepConstInit(keepConstInit) {}
bool runOnModule(Module &M) override {
if (skipModule(M))
return false;
if (!deleteStuff)
M.setModuleInlineAsm("");
for (GlobalVariable &GV : M.globals()) {
bool Delete = deleteStuff == (bool)Named.count(&GV) &&
!GV.isDeclaration() &&
(!GV.isConstant() || !keepConstInit);
if (!Delete) {
if (GV.hasAvailableExternallyLinkage())
continue;
if (GV.getName() == "llvm.global_ctors")
continue;
}
makeVisible(GV, Delete);
if (Delete) {
GV.setInitializer(nullptr);
GV.setComdat(nullptr);
}
}
for (Function &F : M) {
bool Delete =
deleteStuff == (bool)Named.count(&F) && !F.isDeclaration();
if (!Delete) {
if (F.hasAvailableExternallyLinkage())
continue;
}
makeVisible(F, Delete);
if (Delete) {
F.deleteBody();
F.setComdat(nullptr);
}
}
for (GlobalAlias &GA : llvm::make_early_inc_range(M.aliases())) {
bool Delete = deleteStuff == (bool)Named.count(&GA);
makeVisible(GA, Delete);
if (Delete) {
Type *Ty = GA.getValueType();
GA.removeFromParent();
llvm::Value *Declaration;
if (FunctionType *FTy = dyn_cast<FunctionType>(Ty)) {
Declaration =
Function::Create(FTy, GlobalValue::ExternalLinkage,
GA.getAddressSpace(), GA.getName(), &M);
} else {
Declaration =
new GlobalVariable(M, Ty, false, GlobalValue::ExternalLinkage,
nullptr, GA.getName());
}
GA.replaceAllUsesWith(Declaration);
delete &GA;
}
}
return true;
}
};
char GVExtractorPass::ID = 0;
}
ModulePass *llvm::createGVExtractionPass(std::vector<GlobalValue *> &GVs,
bool deleteFn, bool keepConstInit) {
return new GVExtractorPass(GVs, deleteFn, keepConstInit);
}