diff --git a/llvm/lib/Transforms/IPO/ExtractGV.cpp b/llvm/lib/Transforms/IPO/ExtractGV.cpp index fa3d72ddcf16..50fb3e691c5f 100644 --- a/llvm/lib/Transforms/IPO/ExtractGV.cpp +++ b/llvm/lib/Transforms/IPO/ExtractGV.cpp @@ -21,6 +21,38 @@ #include using namespace llvm; +/// Make sure GV is visible from both modules. Delete is true if it is +/// being deleted from this module. +/// This also makes sure GV cannot be dropped so that references from +/// the split module remain valid. +static void makeVisible(GlobalValue &GV, bool Delete) { + bool Local = GV.hasLocalLinkage(); + if (Local) + GV.setVisibility(GlobalValue::HiddenVisibility); + + if (Local || Delete) { + GV.setLinkage(GlobalValue::ExternalLinkage); + return; + } + + if (!GV.hasLinkOnceLinkage()) { + assert(!GV.isDiscardableIfUnused()); + return; + } + + // Map linkonce* to weak* so that llvm doesn't drop this GV. + 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 { /// @brief A pass to extract specific functions and their dependencies. class GVExtractorPass : public ModulePass { @@ -60,12 +92,7 @@ namespace { continue; } - bool Local = I->isDiscardableIfUnused(); - if (Local) - I->setVisibility(GlobalValue::HiddenVisibility); - - if (Local || Delete) - I->setLinkage(GlobalValue::ExternalLinkage); + makeVisible(*I, Delete); if (Delete) I->setInitializer(0); @@ -80,12 +107,7 @@ namespace { continue; } - bool Local = I->isDiscardableIfUnused(); - if (Local) - I->setVisibility(GlobalValue::HiddenVisibility); - - if (Local || Delete) - I->setLinkage(GlobalValue::ExternalLinkage); + makeVisible(*I, Delete); if (Delete) I->deleteBody(); @@ -97,12 +119,10 @@ namespace { Module::alias_iterator CurI = I; ++I; - if (CurI->isDiscardableIfUnused()) { - CurI->setVisibility(GlobalValue::HiddenVisibility); - CurI->setLinkage(GlobalValue::ExternalLinkage); - } + bool Delete = deleteStuff == (bool)Named.count(CurI); + makeVisible(*CurI, Delete); - if (deleteStuff == (bool)Named.count(CurI)) { + if (Delete) { Type *Ty = CurI->getType()->getElementType(); CurI->removeFromParent(); diff --git a/llvm/test/Other/extract-linkonce.ll b/llvm/test/Other/extract-linkonce.ll index 31fbf3ac4632..4c6b6b76a4ab 100644 --- a/llvm/test/Other/extract-linkonce.ll +++ b/llvm/test/Other/extract-linkonce.ll @@ -1,15 +1,16 @@ ; RUN: llvm-extract -func foo -S < %s | FileCheck %s ; RUN: llvm-extract -delete -func foo -S < %s | FileCheck --check-prefix=DELETE %s -; Test that we don't convert weak_odr to external definitions. +; Test that linkonce definitions are mapped to weak so that they are not +; dropped. -; CHECK: @bar = external hidden global i32 -; CHECK: define hidden i32* @foo() { +; CHECK: @bar = external global i32 +; CHECK: define weak i32* @foo() { ; CHECK-NEXT: ret i32* @bar ; CHECK-NEXT: } -; DELETE: @bar = hidden global i32 42 -; DELETE: declare hidden i32* @foo() +; DELETE: @bar = weak global i32 42 +; DELETE: declare i32* @foo() @bar = linkonce global i32 42