[llvm] r317108 - LTO: Apply global DCE to ThinLTO modules at LTO opt level 0.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 1 10:58:39 PDT 2017


Author: pcc
Date: Wed Nov  1 10:58:39 2017
New Revision: 317108

URL: http://llvm.org/viewvc/llvm-project?rev=317108&view=rev
Log:
LTO: Apply global DCE to ThinLTO modules at LTO opt level 0.

This is necessary because DCE is applied to full LTO modules. Without
this change, a reference from a dead ThinLTO global to a dead full
LTO global will result in an undefined reference at link time.

This problem is only observable when --gc-sections is disabled, or
when targeting COFF, as the COFF port of lld requires all symbols to
have a definition even if all references are dead (this is consistent
with link.exe).

This change also adds an EliminateAvailableExternally pass at -O0. This
is necessary to handle the situation on Windows where a non-prevailing
copy of a linkonce_odr function has an SEH filter function; any
such filters must be DCE'd because they will contain a call to the
llvm.localrecover intrinsic, passing as an argument the address of the
function that the filter belongs to, and llvm.localrecover requires
this function to be defined locally.

Fixes PR35142.

Differential Revision: https://reviews.llvm.org/D39484

Modified:
    llvm/trunk/lib/LTO/LTO.cpp
    llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp
    llvm/trunk/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll
    llvm/trunk/test/LTO/Resolution/X86/dead-strip-fulllto.ll

Modified: llvm/trunk/lib/LTO/LTO.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/LTO/LTO.cpp?rev=317108&r1=317107&r2=317108&view=diff
==============================================================================
--- llvm/trunk/lib/LTO/LTO.cpp (original)
+++ llvm/trunk/lib/LTO/LTO.cpp Wed Nov  1 10:58:39 2017
@@ -1098,41 +1098,44 @@ Error LTO::runThinLTO(AddStreamFn AddStr
       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);
-    }
+  // 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)));
+  // 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 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) {

Modified: llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp?rev=317108&r1=317107&r2=317108&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp Wed Nov  1 10:58:39 2017
@@ -418,6 +418,14 @@ void PassManagerBuilder::populateModuleP
     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.

Modified: llvm/trunk/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll?rev=317108&r1=317107&r2=317108&view=diff
==============================================================================
--- llvm/trunk/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll (original)
+++ llvm/trunk/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll Wed Nov  1 10:58:39 2017
@@ -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
+}

Modified: llvm/trunk/test/LTO/Resolution/X86/dead-strip-fulllto.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/Resolution/X86/dead-strip-fulllto.ll?rev=317108&r1=317107&r2=317108&view=diff
==============================================================================
--- llvm/trunk/test/LTO/Resolution/X86/dead-strip-fulllto.ll (original)
+++ llvm/trunk/test/LTO/Resolution/X86/dead-strip-fulllto.ll Wed Nov  1 10:58:39 2017
@@ -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"




More information about the llvm-commits mailing list