diff options
| -rw-r--r-- | llvm/lib/LTO/LTO.cpp | 65 | ||||
| -rw-r--r-- | llvm/lib/Transforms/IPO/PassManagerBuilder.cpp | 8 | ||||
| -rw-r--r-- | llvm/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll | 8 | ||||
| -rw-r--r-- | llvm/test/LTO/Resolution/X86/dead-strip-fulllto.ll | 10 | 
4 files changed, 59 insertions, 32 deletions
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 4fb36e7998e..017dd201f9c 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -1098,42 +1098,45 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,        ThinLTO.ModuleMap.size());    StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR; -  if (Conf.OptLevel > 0) { +  if (Conf.OptLevel > 0)      ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,                               ImportLists, ExportLists); -    std::set<GlobalValue::GUID> ExportedGUIDs; -    for (auto &Res : GlobalResolutions) { -      // First check if the symbol was flagged as having external references. -      if (Res.second.Partition != GlobalResolution::External) -        continue; -      // IRName will be defined if we have seen the prevailing copy of -      // this value. If not, no need to mark as exported from a ThinLTO -      // partition (and we can't get the GUID). -      if (Res.second.IRName.empty()) -        continue; -      auto GUID = GlobalValue::getGUID( -          GlobalValue::dropLLVMManglingEscape(Res.second.IRName)); -      // Mark exported unless index-based analysis determined it to be dead. -      if (ThinLTO.CombinedIndex.isGUIDLive(GUID)) -        ExportedGUIDs.insert(GUID); -    } - -    // Any functions referenced by the jump table in the regular LTO object must -    // be exported. -    for (auto &Def : ThinLTO.CombinedIndex.cfiFunctionDefs()) -      ExportedGUIDs.insert( -          GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Def))); - -    auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { -      const auto &ExportList = ExportLists.find(ModuleIdentifier); -      return (ExportList != ExportLists.end() && -              ExportList->second.count(GUID)) || -             ExportedGUIDs.count(GUID); -    }; -    thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported); +  // Figure out which symbols need to be internalized. This also needs to happen +  // at -O0 because summary-based DCE is implemented using internalization, and +  // we must apply DCE consistently with the full LTO module in order to avoid +  // undefined references during the final link. +  std::set<GlobalValue::GUID> ExportedGUIDs; +  for (auto &Res : GlobalResolutions) { +    // First check if the symbol was flagged as having external references. +    if (Res.second.Partition != GlobalResolution::External) +      continue; +    // IRName will be defined if we have seen the prevailing copy of +    // this value. If not, no need to mark as exported from a ThinLTO +    // partition (and we can't get the GUID). +    if (Res.second.IRName.empty()) +      continue; +    auto GUID = GlobalValue::getGUID( +        GlobalValue::dropLLVMManglingEscape(Res.second.IRName)); +    // Mark exported unless index-based analysis determined it to be dead. +    if (ThinLTO.CombinedIndex.isGUIDLive(GUID)) +      ExportedGUIDs.insert(GUID);    } +  // Any functions referenced by the jump table in the regular LTO object must +  // be exported. +  for (auto &Def : ThinLTO.CombinedIndex.cfiFunctionDefs()) +    ExportedGUIDs.insert( +        GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Def))); + +  auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { +    const auto &ExportList = ExportLists.find(ModuleIdentifier); +    return (ExportList != ExportLists.end() && +            ExportList->second.count(GUID)) || +           ExportedGUIDs.count(GUID); +  }; +  thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported); +    auto isPrevailing = [&](GlobalValue::GUID GUID,                            const GlobalValueSummary *S) {      return ThinLTO.PrevailingModuleForGUID[GUID] == S->modulePath(); diff --git a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp index bb15cf510c7..828eb5eee29 100644 --- a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp +++ b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -418,6 +418,14 @@ void PassManagerBuilder::populateModulePassManager(      else if (GlobalExtensionsNotEmpty() || !Extensions.empty())        MPM.add(createBarrierNoopPass()); +    if (PerformThinLTO) { +      // Drop available_externally and unreferenced globals. This is necessary +      // with ThinLTO in order to avoid leaving undefined references to dead +      // globals in the object file. +      MPM.add(createEliminateAvailableExternallyPass()); +      MPM.add(createGlobalDCEPass()); +    } +      addExtensionsToPM(EP_EnabledOnOptLevel0, MPM);      // Rename anon globals to be able to export them in the summary. diff --git a/llvm/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll b/llvm/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll index 66754889f8b..cc508924c67 100644 --- a/llvm/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll +++ b/llvm/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll @@ -14,3 +14,11 @@ define void @dead1() {  }  declare void @dead2() + +define linkonce_odr i8* @odr() { +  ret i8* bitcast (void ()* @dead3 to i8*) +} + +define internal void @dead3() { +  ret void +} diff --git a/llvm/test/LTO/Resolution/X86/dead-strip-fulllto.ll b/llvm/test/LTO/Resolution/X86/dead-strip-fulllto.ll index a9be2751c81..02b0e38fb9b 100644 --- a/llvm/test/LTO/Resolution/X86/dead-strip-fulllto.ll +++ b/llvm/test/LTO/Resolution/X86/dead-strip-fulllto.ll @@ -1,11 +1,18 @@  ; RUN: opt -module-summary -o %t %s  ; RUN: opt -module-summary -o %t2 %S/Inputs/dead-strip-fulllto.ll +  ; RUN: llvm-lto2 run %t -r %t,main,px -r %t,live1,p -r %t,live2,p -r %t,dead2,p \ -; RUN:               %t2 -r %t2,live1,p -r %t2,live2, -r %t2,dead1,p -r %t2,dead2, \ +; RUN:               %t2 -r %t2,live1,p -r %t2,live2, -r %t2,dead1,p -r %t2,dead2, -r %t2,odr, \  ; RUN: -save-temps -o %t3  ; RUN: llvm-nm %t3.0 | FileCheck --check-prefix=FULL %s  ; RUN: llvm-nm %t3.1 | FileCheck --check-prefix=THIN %s +; RUN: llvm-lto2 run %t -r %t,main,px -r %t,live1,p -r %t,live2,p -r %t,dead2,p \ +; RUN:               %t2 -r %t2,live1,p -r %t2,live2, -r %t2,dead1,p -r %t2,dead2, -r %t2,odr, \ +; RUN: -save-temps -o %t3 -O0 +; RUN: llvm-nm %t3.0 | FileCheck --check-prefix=FULL %s +; RUN: llvm-nm %t3.1 | FileCheck --check-prefix=THIN %s +  ; FULL-NOT: dead  ; FULL: U live1  ; FULL: T live2 @@ -14,6 +21,7 @@  ; THIN-NOT: dead  ; THIN: T live1  ; THIN: U live2 +; THIN-NOT: odr  target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"  target triple = "x86_64-unknown-linux-gnu"  | 

