[llvm] r369766 - [ThinLTO] Fix handling of weak interposable symbols

Teresa Johnson via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 23 08:18:58 PDT 2019


Author: tejohnson
Date: Fri Aug 23 08:18:58 2019
New Revision: 369766

URL: http://llvm.org/viewvc/llvm-project?rev=369766&view=rev
Log:
[ThinLTO] Fix handling of weak interposable symbols

Summary:
Keep aliasees alive if their alias is live, otherwise we end up with an
alias to a declaration, which is invalid. This can happen when the
aliasee is weak and non-prevailing.

This fix exposed the fact that we were then attempting to internalize
the weak symbol, which was not exported as it was not prevailing. We
should not internalize interposable symbols in general, unless this is
the prevailing copy, since it can lead to incorrect inlining and other
optimizations. Most of the changes in this patch are due to the
restructuring required to pass down the prevailing callback.

Finally, while implementing the test cases, I found that in the case of
a weak aliasee that is still marked not live because its alias isn't
live, after dropping the definition we incorrectly marked the
declaration with weak linkage when resolving prevailing symbols in the
module. This was due to some special case handling for symbols marked
WeakLinkage in the summary located before instead of after a subsequent
check for the symbol being a declaration. It turns out that we don't
actually need this special case handling any more (looking back at the
history, when that was added the code was structured quite differently)
- we will correctly mark with weak linkage further below when the
definition hasn't been dropped.

Fixes PR42542.

Reviewers: pcc

Subscribers: mehdi_amini, inglorion, steven_wu, dexonsmith, dang, llvm-commits

Tags: #llvm

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

Added:
    llvm/trunk/test/LTO/Resolution/X86/not-prevailing-weak-aliasee.ll
    llvm/trunk/test/ThinLTO/X86/Inputs/internalize.ll
Modified:
    llvm/trunk/include/llvm/LTO/LTO.h
    llvm/trunk/lib/LTO/LTO.cpp
    llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp
    llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp
    llvm/trunk/test/ThinLTO/X86/internalize.ll

Modified: llvm/trunk/include/llvm/LTO/LTO.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/LTO/LTO.h?rev=369766&r1=369765&r2=369766&view=diff
==============================================================================
--- llvm/trunk/include/llvm/LTO/LTO.h (original)
+++ llvm/trunk/include/llvm/LTO/LTO.h Fri Aug 23 08:18:58 2019
@@ -59,7 +59,9 @@ void thinLTOResolvePrevailingInIndex(
 /// must apply the changes to the Module via thinLTOInternalizeModule.
 void thinLTOInternalizeAndPromoteInIndex(
     ModuleSummaryIndex &Index,
-    function_ref<bool(StringRef, GlobalValue::GUID)> isExported);
+    function_ref<bool(StringRef, GlobalValue::GUID)> isExported,
+    function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
+        isPrevailing);
 
 /// Computes a unique hash for the Module considering the current list of
 /// export/import and other global analysis results.

Modified: llvm/trunk/lib/LTO/LTO.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/LTO/LTO.cpp?rev=369766&r1=369765&r2=369766&view=diff
==============================================================================
--- llvm/trunk/lib/LTO/LTO.cpp (original)
+++ llvm/trunk/lib/LTO/LTO.cpp Fri Aug 23 08:18:58 2019
@@ -384,7 +384,9 @@ static bool isWeakObjectWithRWAccess(Glo
 
 static void thinLTOInternalizeAndPromoteGUID(
     GlobalValueSummaryList &GVSummaryList, GlobalValue::GUID GUID,
-    function_ref<bool(StringRef, GlobalValue::GUID)> isExported) {
+    function_ref<bool(StringRef, GlobalValue::GUID)> isExported,
+    function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
+        isPrevailing) {
   for (auto &S : GVSummaryList) {
     if (isExported(S->modulePath(), GUID)) {
       if (GlobalValue::isLocalLinkage(S->linkage()))
@@ -393,6 +395,8 @@ static void thinLTOInternalizeAndPromote
                // Ignore local and appending linkage values since the linker
                // doesn't resolve them.
                !GlobalValue::isLocalLinkage(S->linkage()) &&
+               (!GlobalValue::isInterposableLinkage(S->linkage()) ||
+                isPrevailing(GUID, S.get())) &&
                S->linkage() != GlobalValue::AppendingLinkage &&
                // We can't internalize available_externally globals because this
                // can break function pointer equality.
@@ -411,9 +415,12 @@ static void thinLTOInternalizeAndPromote
 // as external and non-exported values as internal.
 void llvm::thinLTOInternalizeAndPromoteInIndex(
     ModuleSummaryIndex &Index,
-    function_ref<bool(StringRef, GlobalValue::GUID)> isExported) {
+    function_ref<bool(StringRef, GlobalValue::GUID)> isExported,
+    function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
+        isPrevailing) {
   for (auto &I : Index)
-    thinLTOInternalizeAndPromoteGUID(I.second.SummaryList, I.first, isExported);
+    thinLTOInternalizeAndPromoteGUID(I.second.SummaryList, I.first, isExported,
+                                     isPrevailing);
 }
 
 // Requires a destructor for std::vector<InputModule>.
@@ -1322,12 +1329,13 @@ Error LTO::runThinLTO(AddStreamFn AddStr
             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();
   };
+  thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported,
+                                      isPrevailing);
+
   auto recordNewLinkage = [&](StringRef ModuleIdentifier,
                               GlobalValue::GUID GUID,
                               GlobalValue::LinkageTypes NewLinkage) {

Modified: llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp?rev=369766&r1=369765&r2=369766&view=diff
==============================================================================
--- llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp (original)
+++ llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp Fri Aug 23 08:18:58 2019
@@ -457,10 +457,9 @@ static void resolvePrevailingInIndex(
     ModuleSummaryIndex &Index,
     StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>>
         &ResolvedODR,
-    const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) {
-
-  DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
-  computePrevailingCopies(Index, PrevailingCopy);
+    const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols,
+    const DenseMap<GlobalValue::GUID, const GlobalValueSummary *>
+        &PrevailingCopy) {
 
   auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
     const auto &Prevailing = PrevailingCopy.find(GUID);
@@ -576,6 +575,8 @@ std::unique_ptr<ModuleSummaryIndex> Thin
 static void internalizeAndPromoteInIndex(
     const StringMap<FunctionImporter::ExportSetTy> &ExportLists,
     const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols,
+    const DenseMap<GlobalValue::GUID, const GlobalValueSummary *>
+        &PrevailingCopy,
     ModuleSummaryIndex &Index) {
   auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
     const auto &ExportList = ExportLists.find(ModuleIdentifier);
@@ -584,7 +585,15 @@ static void internalizeAndPromoteInIndex
            GUIDPreservedSymbols.count(GUID);
   };
 
-  thinLTOInternalizeAndPromoteInIndex(Index, isExported);
+  auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
+    const auto &Prevailing = PrevailingCopy.find(GUID);
+    // Not in map means that there was only one copy, which must be prevailing.
+    if (Prevailing == PrevailingCopy.end())
+      return true;
+    return Prevailing->second == S;
+  };
+
+  thinLTOInternalizeAndPromoteInIndex(Index, isExported, isPrevailing);
 }
 
 static void computeDeadSymbolsInIndex(
@@ -629,16 +638,21 @@ void ThinLTOCodeGenerator::promote(Modul
   ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
                            ExportLists);
 
+  DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
+  computePrevailingCopies(Index, PrevailingCopy);
+
   // Resolve prevailing symbols
   StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
-  resolvePrevailingInIndex(Index, ResolvedODR, GUIDPreservedSymbols);
+  resolvePrevailingInIndex(Index, ResolvedODR, GUIDPreservedSymbols,
+                           PrevailingCopy);
 
   thinLTOResolvePrevailingInModule(
       TheModule, ModuleToDefinedGVSummaries[ModuleIdentifier]);
 
   // Promote the exported values in the index, so that they are promoted
   // in the module.
-  internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols, Index);
+  internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols,
+                               PrevailingCopy, Index);
 
   promoteModule(TheModule, Index);
 }
@@ -785,13 +799,18 @@ void ThinLTOCodeGenerator::internalize(M
   if (ExportList.empty() && GUIDPreservedSymbols.empty())
     return;
 
+  DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
+  computePrevailingCopies(Index, PrevailingCopy);
+
   // Resolve prevailing symbols
   StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
-  resolvePrevailingInIndex(Index, ResolvedODR, GUIDPreservedSymbols);
+  resolvePrevailingInIndex(Index, ResolvedODR, GUIDPreservedSymbols,
+                           PrevailingCopy);
 
   // Promote the exported values in the index, so that they are promoted
   // in the module.
-  internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols, Index);
+  internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols,
+                               PrevailingCopy, Index);
 
   promoteModule(TheModule, Index);
 
@@ -944,14 +963,19 @@ void ThinLTOCodeGenerator::run() {
   // on the index, and nuke this map.
   StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
 
+  DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
+  computePrevailingCopies(*Index, PrevailingCopy);
+
   // Resolve prevailing symbols, this has to be computed early because it
   // impacts the caching.
-  resolvePrevailingInIndex(*Index, ResolvedODR, GUIDPreservedSymbols);
+  resolvePrevailingInIndex(*Index, ResolvedODR, GUIDPreservedSymbols,
+                           PrevailingCopy);
 
   // Use global summary-based analysis to identify symbols that can be
   // internalized (because they aren't exported or preserved as per callback).
   // Changes are made in the index, consumed in the ThinLTO backends.
-  internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols, *Index);
+  internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols,
+                               PrevailingCopy, *Index);
 
   // Make sure that every module has an entry in the ExportLists, ImportList,
   // GVSummary and ResolvedODR maps to enable threaded access to these maps

Modified: llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp?rev=369766&r1=369765&r2=369766&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp Fri Aug 23 08:18:58 2019
@@ -764,7 +764,7 @@ void llvm::computeDeadSymbols(
   }
 
   // Make value live and add it to the worklist if it was not live before.
-  auto visit = [&](ValueInfo VI) {
+  auto visit = [&](ValueInfo VI, bool IsAliasee) {
     // FIXME: If we knew which edges were created for indirect call profiles,
     // we could skip them here. Any that are live should be reached via
     // other edges, e.g. reference edges. Otherwise, using a profile collected
@@ -800,12 +800,15 @@ void llvm::computeDeadSymbols(
           Interposable = true;
       }
 
-      if (!KeepAliveLinkage)
-        return;
-
-      if (Interposable)
-        report_fatal_error(
-          "Interposable and available_externally/linkonce_odr/weak_odr symbol");
+      if (!IsAliasee) {
+        if (!KeepAliveLinkage)
+          return;
+
+        if (Interposable)
+          report_fatal_error(
+              "Interposable and available_externally/linkonce_odr/weak_odr "
+              "symbol");
+      }
     }
 
     for (auto &S : VI.getSummaryList())
@@ -821,16 +824,16 @@ void llvm::computeDeadSymbols(
         // If this is an alias, visit the aliasee VI to ensure that all copies
         // are marked live and it is added to the worklist for further
         // processing of its references.
-        visit(AS->getAliaseeVI());
+        visit(AS->getAliaseeVI(), true);
         continue;
       }
 
       Summary->setLive(true);
       for (auto Ref : Summary->refs())
-        visit(Ref);
+        visit(Ref, false);
       if (auto *FS = dyn_cast<FunctionSummary>(Summary.get()))
         for (auto Call : FS->calls())
-          visit(Call.first);
+          visit(Call.first, false);
     }
   }
   Index.setWithGlobalValueDeadStripping();
@@ -948,23 +951,11 @@ void llvm::thinLTOResolvePrevailingInMod
     auto NewLinkage = GS->second->linkage();
     if (NewLinkage == GV.getLinkage())
       return;
-
-    // Switch the linkage to weakany if asked for, e.g. we do this for
-    // linker redefined symbols (via --wrap or --defsym).
-    // We record that the visibility should be changed here in `addThinLTO`
-    // as we need access to the resolution vectors for each input file in
-    // order to find which symbols have been redefined.
-    // We may consider reorganizing this code and moving the linkage recording
-    // somewhere else, e.g. in thinLTOResolvePrevailingInIndex.
-    if (NewLinkage == GlobalValue::WeakAnyLinkage) {
-      GV.setLinkage(NewLinkage);
-      return;
-    }
-
     if (GlobalValue::isLocalLinkage(GV.getLinkage()) ||
         // In case it was dead and already converted to declaration.
         GV.isDeclaration())
       return;
+
     // Check for a non-prevailing def that has interposable linkage
     // (e.g. non-odr weak or linkonce). In that case we can't simply
     // convert to available_externally, since it would lose the

Added: llvm/trunk/test/LTO/Resolution/X86/not-prevailing-weak-aliasee.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LTO/Resolution/X86/not-prevailing-weak-aliasee.ll?rev=369766&view=auto
==============================================================================
--- llvm/trunk/test/LTO/Resolution/X86/not-prevailing-weak-aliasee.ll (added)
+++ llvm/trunk/test/LTO/Resolution/X86/not-prevailing-weak-aliasee.ll Fri Aug 23 08:18:58 2019
@@ -0,0 +1,33 @@
+; Test to ensure that non-prevailing weak aliasee is kept as a weak definition
+; when the alias is not dead.
+; RUN: opt -module-summary %s -o %t1.bc
+; RUN: llvm-lto2 run %t1.bc \
+; RUN:	 -r=%t1.bc,__a,lx \
+; RUN:	 -r=%t1.bc,__b,l \
+; RUN:	 -r=%t1.bc,a,plx \
+; RUN:	 -r=%t1.bc,b,pl \
+; RUN:   -o %t2.o -save-temps
+
+; Check that __a is kept as a weak def. __b can be dropped since its alias is
+; not live and will also be dropped.
+; RUN: llvm-dis %t2.o.1.1.promote.bc -o - | FileCheck %s
+; CHECK: define weak hidden void @__a
+; CHECK: declare hidden void @__b
+; CHECK: declare void @b
+
+target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-unknown-linux-gnu"
+
+ at a = hidden alias void (), void ()* @__a
+
+define weak hidden void @__a() {
+entry:
+  ret void
+}
+
+ at b = hidden alias void (), void ()* @__b
+
+define weak hidden void @__b() {
+entry:
+  ret void
+}

Added: llvm/trunk/test/ThinLTO/X86/Inputs/internalize.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/Inputs/internalize.ll?rev=369766&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/Inputs/internalize.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/Inputs/internalize.ll Fri Aug 23 08:18:58 2019
@@ -0,0 +1,6 @@
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.11.0"
+
+define weak void @weak_func_nonprevailing() {
+    ret void
+}

Modified: llvm/trunk/test/ThinLTO/X86/internalize.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/internalize.ll?rev=369766&r1=369765&r2=369766&view=diff
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/internalize.ll (original)
+++ llvm/trunk/test/ThinLTO/X86/internalize.ll Fri Aug 23 08:18:58 2019
@@ -1,5 +1,8 @@
 ; RUN: opt -module-summary %s -o %t1.bc
-; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t1.bc
+; RUN: opt -module-summary %p/Inputs/internalize.ll -o %t2.bc
+; Link in %t2.bc first to force its copy of @weak_func_nonprevailing as
+; prevailing the %t1.bc copy as non-prevailing.
+; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t2.bc %t1.bc
 ; RUN: llvm-lto -thinlto-action=internalize -thinlto-index %t.index.bc %t1.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=REGULAR
 ; RUN: llvm-lto -thinlto-action=internalize -thinlto-index %t.index.bc %t1.bc -o -  --exported-symbol=foo | llvm-dis -o - | FileCheck %s --check-prefix=INTERNALIZE
 
@@ -13,7 +16,10 @@
 ; RUN: llvm-lto2 run %t1.bc -o %t.o -save-temps \
 ; RUN:     -r=%t1.bc,_foo,pxl \
 ; RUN:     -r=%t1.bc,_bar,pl \
-; RUN:     -r=%t1.bc,_linkonce_func,pl
+; RUN:     -r=%t1.bc,_linkonce_func,pl \
+; RUN:     -r=%t1.bc,_weak_func_prevailing,pl \
+; RUN:     -r=%t1.bc,_alias1,plx \
+; RUN:     -r=%t1.bc,_weak_func_nonprevailing,l
 ; RUN: llvm-dis < %t.o.1.2.internalize.bc | FileCheck  %s --check-prefix=INTERNALIZE2
 
 ; Test the enable-lto-internalization option by setting it to false.
@@ -22,7 +28,10 @@
 ; RUN: llvm-lto2 run %t1.bc -o %t.o -save-temps -enable-lto-internalization=false \
 ; RUN:     -r=%t1.bc,_foo,pxl \
 ; RUN:     -r=%t1.bc,_bar,pl \
-; RUN:     -r=%t1.bc,_linkonce_func,pl
+; RUN:     -r=%t1.bc,_linkonce_func,pl \
+; RUN:     -r=%t1.bc,_weak_func_prevailing,pl \
+; RUN:     -r=%t1.bc,_alias1,plx \
+; RUN:     -r=%t1.bc,_weak_func_nonprevailing,l
 ; RUN: llvm-dis < %t.o.1.2.internalize.bc | FileCheck  %s --check-prefix=INTERNALIZE2-OPTION-DISABLE
 
 ; REGULAR: define void @foo
@@ -31,15 +40,23 @@
 ; INTERNALIZE: define void @foo
 ; INTERNALIZE: define internal void @bar
 ; INTERNALIZE: define internal void @linkonce_func()
+; INTERNALIZE: define internal void @weak_func_prevailing()
+; INTERNALIZE: define weak void @weak_func_nonprevailing()
 ; INTERNALIZE-OPTION-DISABLE: define void @foo
 ; INTERNALIZE-OPTION-DISABLE: define void @bar
 ; INTERNALIZE-OPTION-DISABLE: define weak void @linkonce_func()
+; INTERNALIZE-OPTION-DISABLE: define weak void @weak_func_prevailing()
+; INTERNALIZE-OPTION-DISABLE: define weak void @weak_func_nonprevailing()
 ; INTERNALIZE2: define dso_local void @foo
 ; INTERNALIZE2: define internal void @bar
 ; INTERNALIZE2: define internal void @linkonce_func()
+; INTERNALIZE2: define internal void @weak_func_prevailing()
+; INTERNALIZE2: define weak dso_local void @weak_func_nonprevailing()
 ; INTERNALIZE2-OPTION-DISABLE: define dso_local void @foo
 ; INTERNALIZE2-OPTION-DISABLE: define dso_local void @bar
 ; INTERNALIZE2-OPTION-DISABLE: define weak dso_local void @linkonce_func()
+; INTERNALIZE2-OPTION-DISABLE: define weak dso_local void @weak_func_prevailing()
+; INTERNALIZE2-OPTION-DISABLE: define weak dso_local void @weak_func_nonprevailing()
 
 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-apple-macosx10.11.0"
@@ -50,8 +67,20 @@ define void @foo() {
 }
 define void @bar() {
     call void @linkonce_func()
+    call void @weak_func_prevailing()
+    call void @weak_func_nonprevailing()
 	ret void
 }
 define linkonce void @linkonce_func() {
     ret void
 }
+define weak void @weak_func_prevailing() {
+    ret void
+}
+; Make @weak_func_nonprevailing an aliasee to ensure it is still marked
+; live and kept as a definition even when non-prevailing. We want to ensure
+; this definition is not internalized.
+ at alias1 = hidden alias void (), void ()* @weak_func_nonprevailing
+define weak void @weak_func_nonprevailing() {
+    ret void
+}




More information about the llvm-commits mailing list