[llvm] r266519 - ThinLTO: Move the ODR resolution to be based purely on the summary.

Mehdi Amini via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 16 00:02:16 PDT 2016


Author: mehdi_amini
Date: Sat Apr 16 02:02:16 2016
New Revision: 266519

URL: http://llvm.org/viewvc/llvm-project?rev=266519&view=rev
Log:
ThinLTO: Move the ODR resolution to be based purely on the summary.

This is a requirement for the cache handling in D18494

Differential Revision: http://reviews.llvm.org/D18908

From: Mehdi Amini <mehdi.amini at apple.com>

Modified:
    llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h
    llvm/trunk/include/llvm/Transforms/IPO/FunctionImport.h
    llvm/trunk/lib/IR/ModuleSummaryIndex.cpp
    llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp
    llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp

Modified: llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h?rev=266519&r1=266518&r2=266519&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h (original)
+++ llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h Sat Apr 16 02:02:16 2016
@@ -466,6 +466,12 @@ public:
   void collectDefinedFunctionsForModule(
       StringRef ModulePath,
       std::map<GlobalValue::GUID, GlobalValueSummary *> &FunctionInfoMap) const;
+
+  /// Collect for each module the list of Summaries it defines (GUID ->
+  /// Summary).
+  void collectDefinedGVSummariesPerModule(
+      StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>> &
+          ModuleToDefinedGVSummaries) const;
 };
 
 } // End llvm namespace

Modified: llvm/trunk/include/llvm/Transforms/IPO/FunctionImport.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/FunctionImport.h?rev=266519&r1=266518&r2=266519&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/IPO/FunctionImport.h (original)
+++ llvm/trunk/include/llvm/Transforms/IPO/FunctionImport.h Sat Apr 16 02:02:16 2016
@@ -19,6 +19,7 @@
 
 namespace llvm {
 class LLVMContext;
+class GlobalValueSummary;
 class Module;
 class ModuleSummaryIndex;
 
@@ -59,6 +60,9 @@ private:
 
 /// Compute all the imports and exports for every module in the Index.
 ///
+/// \p ModuleToDefinedGVSummaries contains for each Module a map
+/// (GUID -> Summary) for every global defined in the module.
+///
 /// \p ImportLists will be populated with an entry for every Module we are
 /// importing into. This entry is itself a map that can be passed to
 /// FunctionImporter::importFunctions() above (see description there).
@@ -68,6 +72,8 @@ private:
 /// is the set of globals that need to be promoted/renamed appropriately.
 void ComputeCrossModuleImport(
     const ModuleSummaryIndex &Index,
+    const StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>> &
+        ModuleToDefinedGVSummaries,
     StringMap<FunctionImporter::ImportMapTy> &ImportLists,
     StringMap<FunctionImporter::ExportSetTy> &ExportLists);
 

Modified: llvm/trunk/lib/IR/ModuleSummaryIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/ModuleSummaryIndex.cpp?rev=266519&r1=266518&r2=266519&view=diff
==============================================================================
--- llvm/trunk/lib/IR/ModuleSummaryIndex.cpp (original)
+++ llvm/trunk/lib/IR/ModuleSummaryIndex.cpp Sat Apr 16 02:02:16 2016
@@ -89,6 +89,19 @@ void ModuleSummaryIndex::collectDefinedF
   }
 }
 
+// Collect for each module the list of function it defines (GUID -> Summary).
+void ModuleSummaryIndex::collectDefinedGVSummariesPerModule(
+    StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>> &
+        Module2FunctionInfoMap) const {
+  for (auto &GlobalList : *this) {
+    auto GUID = GlobalList.first;
+    for (auto &GlobInfo : GlobalList.second) {
+      auto *Summary = GlobInfo->summary();
+      Module2FunctionInfoMap[Summary->modulePath()][GUID] = Summary;
+    }
+  }
+}
+
 GlobalValueInfo *
 ModuleSummaryIndex::getGlobalValueInfo(uint64_t ValueGUID,
                                        bool PerModuleIndex) const {

Modified: llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp?rev=266519&r1=266518&r2=266519&view=diff
==============================================================================
--- llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp (original)
+++ llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp Sat Apr 16 02:02:16 2016
@@ -30,6 +30,7 @@
 #include "llvm/Linker/Linker.h"
 #include "llvm/MC/SubtargetFeature.h"
 #include "llvm/Object/ModuleSummaryIndexObjectFile.h"
+#include "llvm/Support/Debug.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/TargetRegistry.h"
 #include "llvm/Support/ThreadPool.h"
@@ -42,6 +43,8 @@
 
 using namespace llvm;
 
+#define DEBUG_TYPE "thinlto"
+
 namespace llvm {
 // Flags -discard-value-names, defined in LTOCodeGenerator.cpp
 extern cl::opt<bool> LTODiscardValueNames;
@@ -119,24 +122,15 @@ bool IsFirstDefinitionForLinker(const Gl
   return true;
 }
 
-static void ResolveODR(GlobalValue &GV, const ModuleSummaryIndex &Index,
-                             StringRef ModulePath) {
-  if (GV.isDeclaration())
-    return;
-
+static GlobalValue::LinkageTypes ResolveODR(const ModuleSummaryIndex &Index,
+                                            StringRef ModuleIdentifier,
+                                            GlobalValue::GUID GUID,
+                                            const GlobalValueSummary &GV) {
   auto HasMultipleCopies =
       [&](const GlobalValueInfoList &GVInfo) { return GVInfo.size() > 1; };
 
-  auto getGVInfo = [&](GlobalValue &GV) -> const GlobalValueInfoList *{
-    auto GUID = Function::getGlobalIdentifier(GV.getName(), GV.getLinkage(),
-                                              ModulePath);
-    auto It = Index.findGlobalValueInfoList(GV.getName());
-    if (It == Index.end())
-      return nullptr;
-    return &It->second;
-  };
-
-  switch (GV.getLinkage()) {
+  auto OriginalLinkage = GV.linkage();
+  switch (OriginalLinkage) {
   case GlobalValue::ExternalLinkage:
   case GlobalValue::AvailableExternallyLinkage:
   case GlobalValue::AppendingLinkage:
@@ -149,20 +143,19 @@ static void ResolveODR(GlobalValue &GV,
     break;
   case GlobalValue::LinkOnceODRLinkage:
   case GlobalValue::WeakODRLinkage: {
-    auto *GVInfo = getGVInfo(GV);
-    if (!GVInfo)
-      break;
+    auto &GVInfo = Index.findGlobalValueInfoList(GUID)->second;
     // We need to emit only one of these, the first module will keep
     // it, but turned into a weak while the others will drop it.
-    if (!HasMultipleCopies(*GVInfo))
+    if (!HasMultipleCopies(GVInfo))
       break;
-    if (IsFirstDefinitionForLinker(*GVInfo, Index, ModulePath))
-      GV.setLinkage(GlobalValue::WeakODRLinkage);
+    if (IsFirstDefinitionForLinker(GVInfo, Index, ModuleIdentifier))
+      return GlobalValue::WeakODRLinkage;
     else
-      GV.setLinkage(GlobalValue::AvailableExternallyLinkage);
+      return GlobalValue::AvailableExternallyLinkage;
     break;
   }
   }
+  return OriginalLinkage;
 }
 
 /// Resolve LinkOnceODR and WeakODR.
@@ -171,8 +164,11 @@ static void ResolveODR(GlobalValue &GV,
 /// current module. However there is a chance that another module is still
 /// referencing them because of the import. We make sure we always emit at least
 /// one copy.
-static void ResolveODR(Module &TheModule,
-                             const ModuleSummaryIndex &Index) {
+static void ResolveODR(
+    const ModuleSummaryIndex &Index,
+    const std::map<GlobalValue::GUID, GlobalValueSummary *> &DefinedGlobals,
+    StringRef ModuleIdentifier,
+    DenseMap<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR) {
   if (Index.modulePaths().size() == 1)
     // Nothing to do if we don't have multiple modules
     return;
@@ -180,20 +176,42 @@ static void ResolveODR(Module &TheModule
   // We won't optimize the globals that are referenced by an alias for now
   // Ideally we should turn the alias into a global and duplicate the definition
   // when needed.
-  DenseSet<GlobalValue *> GlobalInvolvedWithAlias;
-  for (auto &GA : TheModule.aliases()) {
-    auto *GO = GA.getBaseObject();
-    if (auto *GV = dyn_cast<GlobalValue>(GO))
-      GlobalInvolvedWithAlias.insert(GV);
+  DenseSet<GlobalValueSummary *> GlobalInvolvedWithAlias;
+  for (auto &GA : DefinedGlobals) {
+    if (auto AS = dyn_cast<AliasSummary>(GA.second))
+      GlobalInvolvedWithAlias.insert(&AS->getAliasee());
+  }
+
+  for (auto &GV : DefinedGlobals) {
+    if (GlobalInvolvedWithAlias.count(GV.second))
+      continue;
+    auto NewLinkage = ResolveODR(Index, ModuleIdentifier, GV.first, *GV.second);
+    if (NewLinkage != GV.second->linkage()) {
+      ResolvedODR[GV.first] = NewLinkage;
+    }
   }
+}
+
+/// Fixup linkage, see ResolveODR() above.
+void fixupODR(
+    Module &TheModule,
+    const DenseMap<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR) {
   // Process functions and global now
   for (auto &GV : TheModule) {
-    if (!GlobalInvolvedWithAlias.count(&GV))
-      ResolveODR(GV, Index, TheModule.getModuleIdentifier());
+    auto NewLinkage = ResolvedODR.find(GV.getGUID());
+    if (NewLinkage == ResolvedODR.end())
+      continue;
+    DEBUG(dbgs() << "ODR fixing up linkage for `" << GV.getName() << "` from "
+                 << GV.getLinkage() << " to " << NewLinkage->second << "\n");
+    GV.setLinkage(NewLinkage->second);
   }
   for (auto &GV : TheModule.globals()) {
-    if (!GlobalInvolvedWithAlias.count(&GV))
-      ResolveODR(GV, Index, TheModule.getModuleIdentifier());
+    auto NewLinkage = ResolvedODR.find(GV.getGUID());
+    if (NewLinkage == ResolvedODR.end())
+      continue;
+    DEBUG(dbgs() << "ODR fixing up linkage for `" << GV.getName() << "` from "
+                 << GV.getLinkage() << " to " << NewLinkage->second << "\n");
+    GV.setLinkage(NewLinkage->second);
   }
 }
 
@@ -291,13 +309,13 @@ std::unique_ptr<MemoryBuffer> codegenMod
   return make_unique<ObjectMemoryBuffer>(std::move(OutputBuffer));
 }
 
-static std::unique_ptr<MemoryBuffer>
-ProcessThinLTOModule(Module &TheModule, const ModuleSummaryIndex &Index,
-                     StringMap<MemoryBufferRef> &ModuleMap, TargetMachine &TM,
-                     const FunctionImporter::ImportMapTy &ImportList,
-                     ThinLTOCodeGenerator::CachingOptions CacheOptions,
-                     bool DisableCodeGen, StringRef SaveTempsDir,
-                     unsigned count) {
+static std::unique_ptr<MemoryBuffer> ProcessThinLTOModule(
+    Module &TheModule, const ModuleSummaryIndex &Index,
+    StringMap<MemoryBufferRef> &ModuleMap, TargetMachine &TM,
+    const FunctionImporter::ImportMapTy &ImportList,
+    DenseMap<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
+    ThinLTOCodeGenerator::CachingOptions CacheOptions, bool DisableCodeGen,
+    StringRef SaveTempsDir, unsigned count) {
 
   // Save temps: after IPO.
   saveTempBitcode(TheModule, SaveTempsDir, count, ".1.IPO.bc");
@@ -311,7 +329,7 @@ ProcessThinLTOModule(Module &TheModule,
     // Resolve the LinkOnce/Weak ODR, trying to turn them into
     // "available_externally" when possible.
     // This is a compile-time optimization.
-    ResolveODR(TheModule, Index);
+    fixupODR(TheModule, ResolvedODR);
 
     // Save temps: after promotion.
     saveTempBitcode(TheModule, SaveTempsDir, count, ".2.promoted.bc");
@@ -435,10 +453,19 @@ std::unique_ptr<ModuleSummaryIndex> Thin
  */
 void ThinLTOCodeGenerator::promote(Module &TheModule,
                                    ModuleSummaryIndex &Index) {
+  auto ModuleIdentifier = TheModule.getModuleIdentifier();
+  // Collect for each module the list of function it defines (GUID -> Summary).
+  StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>>
+      ModuleToDefinedGVSummaries;
+  Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
 
   // Resolve the LinkOnceODR, trying to turn them into "available_externally"
   // where possible.
-  ResolveODR(TheModule, Index);
+  // This is a compile-time optimization.
+  DenseMap<GlobalValue::GUID, GlobalValue::LinkageTypes> ResolvedODR;
+  ResolveODR(Index, ModuleToDefinedGVSummaries[ModuleIdentifier],
+             ModuleIdentifier, ResolvedODR);
+  fixupODR(TheModule, ResolvedODR);
 
   promoteModule(TheModule, Index);
 }
@@ -449,12 +476,18 @@ void ThinLTOCodeGenerator::promote(Modul
 void ThinLTOCodeGenerator::crossModuleImport(Module &TheModule,
                                              ModuleSummaryIndex &Index) {
   auto ModuleMap = generateModuleMap(Modules);
+  auto ModuleCount = Index.modulePaths().size();
+
+  // Collect for each module the list of function it defines (GUID -> Summary).
+  StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>>
+      ModuleToDefinedGVSummaries(ModuleCount);
+  Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
 
   // Generate import/export list
-  auto ModuleCount = Index.modulePaths().size();
   StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
   StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
-  ComputeCrossModuleImport(Index, ImportLists, ExportLists);
+  ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
+                           ExportLists);
   auto &ImportList = ImportLists[TheModule.getModuleIdentifier()];
 
   crossImportIntoModule(TheModule, Index, ModuleMap, ImportList);
@@ -522,11 +555,17 @@ void ThinLTOCodeGenerator::run() {
   auto ModuleMap = generateModuleMap(Modules);
   auto ModuleCount = Modules.size();
 
+  // Collect for each module the list of function it defines (GUID -> Summary).
+  StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>>
+      ModuleToDefinedGVSummaries(ModuleCount);
+  Index->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries);
+
   // Collect the import/export lists for all modules from the call-graph in the
   // combined index.
   StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
   StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
-  ComputeCrossModuleImport(*Index, ImportLists, ExportLists);
+  ComputeCrossModuleImport(*Index, ModuleToDefinedGVSummaries, ImportLists,
+                           ExportLists);
 
   // Parallel optimizer + codegen
   {
@@ -536,6 +575,11 @@ void ThinLTOCodeGenerator::run() {
       Pool.async([&](int count) {
         LLVMContext Context;
         Context.setDiscardValueNames(LTODiscardValueNames);
+        auto ModuleIdentifier = ModuleBuffer.getBufferIdentifier();
+
+        DenseMap<GlobalValue::GUID, GlobalValue::LinkageTypes> ResolvedODR;
+        ResolveODR(*Index, ModuleToDefinedGVSummaries[ModuleIdentifier],
+                   ModuleIdentifier, ResolvedODR);
 
         // Parse module now
         auto TheModule = loadModuleFromBuffer(ModuleBuffer, Context, false);
@@ -545,10 +589,10 @@ void ThinLTOCodeGenerator::run() {
           saveTempBitcode(*TheModule, SaveTempsDir, count, ".0.original.bc");
         }
 
-        auto &ImportList = ImportLists[TheModule->getModuleIdentifier()];
+        auto &ImportList = ImportLists[ModuleIdentifier];
         ProducedBinaries[count] = ProcessThinLTOModule(
             *TheModule, *Index, ModuleMap, *TMBuilder.create(), ImportList,
-            CacheOptions, DisableCodeGen, SaveTempsDir, count);
+            ResolvedODR, CacheOptions, DisableCodeGen, SaveTempsDir, count);
       }, count);
       count++;
     }

Modified: llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp?rev=266519&r1=266518&r2=266519&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp Sat Apr 16 02:02:16 2016
@@ -143,7 +143,7 @@ using EdgeInfo = std::pair<const Functio
 static void computeImportForFunction(
     const FunctionSummary &Summary, const ModuleSummaryIndex &Index,
     unsigned Threshold,
-    const std::map<GlobalValue::GUID, GlobalValueSummary *> &DefinedFunctions,
+    const std::map<GlobalValue::GUID, GlobalValueSummary *> &DefinedGVSummaries,
     SmallVectorImpl<EdgeInfo> &Worklist,
     FunctionImporter::ImportMapTy &ImportsForModule,
     StringMap<FunctionImporter::ExportSetTy> *ExportLists = nullptr) {
@@ -151,7 +151,7 @@ static void computeImportForFunction(
     auto GUID = Edge.first.getGUID();
     DEBUG(dbgs() << " edge -> " << GUID << " Threshold:" << Threshold << "\n");
 
-    if (DefinedFunctions.count(GUID)) {
+    if (DefinedGVSummaries.count(GUID)) {
       DEBUG(dbgs() << "ignored! Target already in destination module.\n");
       continue;
     }
@@ -212,7 +212,7 @@ static void computeImportForFunction(
 /// as well as the list of "exports", i.e. the list of symbols referenced from
 /// another module (that may require promotion).
 static void ComputeImportForModule(
-    const std::map<GlobalValue::GUID, GlobalValueSummary *> &DefinedFunctions,
+    const std::map<GlobalValue::GUID, GlobalValueSummary *> &DefinedGVSummaries,
     const ModuleSummaryIndex &Index,
     FunctionImporter::ImportMapTy &ImportsForModule,
     StringMap<FunctionImporter::ExportSetTy> *ExportLists = nullptr) {
@@ -222,14 +222,17 @@ static void ComputeImportForModule(
 
   // Populate the worklist with the import for the functions in the current
   // module
-  for (auto &FuncInfo : DefinedFunctions) {
-    auto *Summary = FuncInfo.second;
+  for (auto &GVInfo : DefinedGVSummaries) {
+    auto *Summary = GVInfo.second;
     if (auto *AS = dyn_cast<AliasSummary>(Summary))
       Summary = &AS->getAliasee();
-    auto *FuncSummary = cast<FunctionSummary>(Summary);
-    DEBUG(dbgs() << "Initalize import for " << FuncInfo.first << "\n");
+    auto *FuncSummary = dyn_cast<FunctionSummary>(Summary);
+    if (!FuncSummary)
+      // Skip import for global variables
+      continue;
+    DEBUG(dbgs() << "Initalize import for " << GVInfo.first << "\n");
     computeImportForFunction(*FuncSummary, Index, ImportInstrLimit,
-                             DefinedFunctions, Worklist, ImportsForModule,
+                             DefinedGVSummaries, Worklist, ImportsForModule,
                              ExportLists);
   }
 
@@ -242,7 +245,7 @@ static void ComputeImportForModule(
     // Adjust the threshold
     Threshold = Threshold * ImportInstrFactor;
 
-    computeImportForFunction(*Summary, Index, Threshold, DefinedFunctions,
+    computeImportForFunction(*Summary, Index, Threshold, DefinedGVSummaries,
                              Worklist, ImportsForModule, ExportLists);
   }
 }
@@ -252,38 +255,16 @@ static void ComputeImportForModule(
 /// Compute all the import and export for every module using the Index.
 void llvm::ComputeCrossModuleImport(
     const ModuleSummaryIndex &Index,
+    const StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>> &
+        ModuleToDefinedGVSummaries,
     StringMap<FunctionImporter::ImportMapTy> &ImportLists,
     StringMap<FunctionImporter::ExportSetTy> &ExportLists) {
-  auto ModuleCount = Index.modulePaths().size();
-
-  // Collect for each module the list of function it defines.
-  // GUID -> Summary
-  StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>>
-      Module2FunctionInfoMap(ModuleCount);
-
-  for (auto &GlobalList : Index) {
-    auto GUID = GlobalList.first;
-    for (auto &GlobInfo : GlobalList.second) {
-      auto *Summary = GlobInfo->summary();
-      if (isa<GlobalVarSummary>(Summary))
-        /// Ignore global variable, focus on functions
-        continue;
-      if (auto *AS = dyn_cast<AliasSummary>(Summary))
-        if (isa<GlobalVarSummary>(&AS->getAliasee()))
-          /// Ignore alias to global variable, focus on functions
-          continue;
-      DEBUG(dbgs() << "Adding definition: Module '" << Summary->modulePath()
-                   << "' defines '" << GUID << "'\n");
-      Module2FunctionInfoMap[Summary->modulePath()][GUID] = Summary;
-    }
-  }
-
   // For each module that has function defined, compute the import/export lists.
-  for (auto &DefinedFunctions : Module2FunctionInfoMap) {
-    auto &ImportsForModule = ImportLists[DefinedFunctions.first()];
-    DEBUG(dbgs() << "Computing import for Module '" << DefinedFunctions.first()
-                 << "'\n");
-    ComputeImportForModule(DefinedFunctions.second, Index, ImportsForModule,
+  for (auto &DefinedGVSummaries : ModuleToDefinedGVSummaries) {
+    auto &ImportsForModule = ImportLists[DefinedGVSummaries.first()];
+    DEBUG(dbgs() << "Computing import for Module '"
+                 << DefinedGVSummaries.first() << "'\n");
+    ComputeImportForModule(DefinedGVSummaries.second, Index, ImportsForModule,
                            &ExportLists);
   }
 




More information about the llvm-commits mailing list