]> granicus.if.org Git - llvm/commitdiff
[ThinLTO] Fix handling of weak interposable symbols
authorTeresa Johnson <tejohnson@google.com>
Fri, 23 Aug 2019 15:18:58 +0000 (15:18 +0000)
committerTeresa Johnson <tejohnson@google.com>
Fri, 23 Aug 2019 15:18:58 +0000 (15:18 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@369766 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/LTO/LTO.h
lib/LTO/LTO.cpp
lib/LTO/ThinLTOCodeGenerator.cpp
lib/Transforms/IPO/FunctionImport.cpp
test/LTO/Resolution/X86/not-prevailing-weak-aliasee.ll [new file with mode: 0644]
test/ThinLTO/X86/Inputs/internalize.ll [new file with mode: 0644]
test/ThinLTO/X86/internalize.ll

index ca0a8b64523aca8eb082c464f3b7e2299e7a3a2c..4bf93c5ee44506bf4c960d35c128789d5b0d2488 100644 (file)
@@ -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.
index 0ada5015c0a927bda00a1a58ee6f60dd5c045f55..d6e7950b078a4b2063a10ba5a4077eb4bd962868 100644 (file)
@@ -384,7 +384,9 @@ static bool isWeakObjectWithRWAccess(GlobalValueSummary *GVS) {
 
 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 thinLTOInternalizeAndPromoteGUID(
                // 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 thinLTOInternalizeAndPromoteGUID(
 // 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 AddStream, NativeObjectCache Cache,
             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) {
index eada2529e82372ad0e14dc3d37aa18354e8cd1ac..6c8f827d59aeac4232d3fcc493a9e5294c2351b6 100644 (file)
@@ -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> ThinLTOCodeGenerator::linkCombinedIndex() {
 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(Module &TheModule, ModuleSummaryIndex &Index,
   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(Module &TheModule,
   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
index f915aea004fdd401581ab48f1decee08c0cb62e6..531dbb5b6f218c4b6f2873e3b357593f6035f76c 100644 (file)
@@ -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 (!IsAliasee) {
+        if (!KeepAliveLinkage)
+          return;
 
-      if (Interposable)
-        report_fatal_error(
-          "Interposable and available_externally/linkonce_odr/weak_odr symbol");
+        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::thinLTOResolvePrevailingInModule(
     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
diff --git a/test/LTO/Resolution/X86/not-prevailing-weak-aliasee.ll b/test/LTO/Resolution/X86/not-prevailing-weak-aliasee.ll
new file mode 100644 (file)
index 0000000..56dd092
--- /dev/null
@@ -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"
+
+@a = hidden alias void (), void ()* @__a
+
+define weak hidden void @__a() {
+entry:
+  ret void
+}
+
+@b = hidden alias void (), void ()* @__b
+
+define weak hidden void @__b() {
+entry:
+  ret void
+}
diff --git a/test/ThinLTO/X86/Inputs/internalize.ll b/test/ThinLTO/X86/Inputs/internalize.ll
new file mode 100644 (file)
index 0000000..d95078c
--- /dev/null
@@ -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
+}
index 49cab144b564b5490a6447a47d26337d47998167..0f7d4a5ca1f50a08f523a5a7bad74ec1e37e4b59 100644 (file)
@@ -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
 
 ; 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.
 ; 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
 ; 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.
+@alias1 = hidden alias void (), void ()* @weak_func_nonprevailing
+define weak void @weak_func_nonprevailing() {
+    ret void
+}