[llvm] r347033 - [ThinLTO] Internalize readonly globals

Eugene Leviant via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 15 23:08:01 PST 2018


Author: evgeny777
Date: Thu Nov 15 23:08:00 2018
New Revision: 347033

URL: http://llvm.org/viewvc/llvm-project?rev=347033&view=rev
Log:
[ThinLTO] Internalize readonly globals

An attempt to recommit r346584 after failure on OSX build bot.
Fixed cache key computation in ThinLTOCodeGenerator and added
test case

Added:
    llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-alias.ll
    llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-foo.ll
    llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-test1.ll
    llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-test2.ll
    llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-comdat.ll
    llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-define-g.ll
    llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-full-lto.ll
    llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-gvref.ll
    llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-linkage.ll
    llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop.ll
    llvm/trunk/test/ThinLTO/X86/index-const-prop-O0.ll
    llvm/trunk/test/ThinLTO/X86/index-const-prop-alias.ll
    llvm/trunk/test/ThinLTO/X86/index-const-prop-cache.ll
    llvm/trunk/test/ThinLTO/X86/index-const-prop-comdat.ll
    llvm/trunk/test/ThinLTO/X86/index-const-prop-dead.ll
    llvm/trunk/test/ThinLTO/X86/index-const-prop-full-lto.ll
    llvm/trunk/test/ThinLTO/X86/index-const-prop-gvref.ll
    llvm/trunk/test/ThinLTO/X86/index-const-prop-ldst.ll
    llvm/trunk/test/ThinLTO/X86/index-const-prop-linkage.ll
    llvm/trunk/test/ThinLTO/X86/index-const-prop.ll
    llvm/trunk/test/ThinLTO/X86/index-const-prop2.ll
Modified:
    llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h
    llvm/trunk/include/llvm/Transforms/IPO/FunctionImport.h
    llvm/trunk/include/llvm/Transforms/Utils/FunctionImportUtils.h
    llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp
    llvm/trunk/lib/AsmParser/LLParser.cpp
    llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
    llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
    llvm/trunk/lib/IR/ModuleSummaryIndex.cpp
    llvm/trunk/lib/LTO/LTO.cpp
    llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp
    llvm/trunk/lib/Linker/IRMover.cpp
    llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp
    llvm/trunk/lib/Transforms/Utils/FunctionImportUtils.cpp
    llvm/trunk/test/Bitcode/summary_version.ll
    llvm/trunk/test/Bitcode/thinlto-alias.ll
    llvm/trunk/test/Bitcode/thinlto-alias2.ll
    llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-cast.ll
    llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-pgo.ll
    llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll
    llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll
    llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll
    llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph.ll
    llvm/trunk/test/Bitcode/thinlto-function-summary-refgraph.ll
    llvm/trunk/test/ThinLTO/X86/dot-dumper.ll
    llvm/trunk/test/ThinLTO/X86/globals-import-const-fold.ll

Modified: llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h (original)
+++ llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h Thu Nov 15 23:08:00 2018
@@ -163,13 +163,13 @@ using GlobalValueSummaryMapTy =
 /// Struct that holds a reference to a particular GUID in a global value
 /// summary.
 struct ValueInfo {
-  PointerIntPair<const GlobalValueSummaryMapTy::value_type *, 1, bool>
-      RefAndFlag;
+  PointerIntPair<const GlobalValueSummaryMapTy::value_type *, 2, int>
+      RefAndFlags;
 
   ValueInfo() = default;
   ValueInfo(bool HaveGVs, const GlobalValueSummaryMapTy::value_type *R) {
-    RefAndFlag.setPointer(R);
-    RefAndFlag.setInt(HaveGVs);
+    RefAndFlags.setPointer(R);
+    RefAndFlags.setInt(HaveGVs);
   }
 
   operator bool() const { return getRef(); }
@@ -189,10 +189,12 @@ struct ValueInfo {
                      : getRef()->second.U.Name;
   }
 
-  bool haveGVs() const { return RefAndFlag.getInt(); }
+  bool haveGVs() const { return RefAndFlags.getInt() & 0x1; }
+  bool isReadOnly() const { return RefAndFlags.getInt() & 0x2; }
+  void setReadOnly() { RefAndFlags.setInt(RefAndFlags.getInt() | 0x2); }
 
   const GlobalValueSummaryMapTy::value_type *getRef() const {
-    return RefAndFlag.getPointer();
+    return RefAndFlags.getPointer();
   }
 
   bool isDSOLocal() const;
@@ -543,6 +545,8 @@ public:
           std::move(TypeTestAssumeConstVCalls),
           std::move(TypeCheckedLoadConstVCalls)});
   }
+  // Gets the number of immutable refs in RefEdgeList
+  unsigned immutableRefCount() const;
 
   /// Check if this is a function summary.
   static bool classof(const GlobalValueSummary *GVS) {
@@ -652,19 +656,30 @@ template <> struct DenseMapInfo<Function
 /// Global variable summary information to aid decisions and
 /// implementation of importing.
 ///
-/// Currently this doesn't add anything to the base \p GlobalValueSummary,
-/// but is a placeholder as additional info may be added to the summary
-/// for variables.
+/// Global variable summary has extra flag, telling if it is
+/// modified during the program run or not. This affects ThinLTO
+/// internalization
 class GlobalVarSummary : public GlobalValueSummary {
-
 public:
-  GlobalVarSummary(GVFlags Flags, std::vector<ValueInfo> Refs)
-      : GlobalValueSummary(GlobalVarKind, Flags, std::move(Refs)) {}
+  struct GVarFlags {
+    GVarFlags(bool ReadOnly = false) : ReadOnly(ReadOnly) {}
+
+    unsigned ReadOnly : 1;
+  } VarFlags;
+
+  GlobalVarSummary(GVFlags Flags, GVarFlags VarFlags,
+                   std::vector<ValueInfo> Refs)
+      : GlobalValueSummary(GlobalVarKind, Flags, std::move(Refs)),
+        VarFlags(VarFlags) {}
 
   /// Check if this is a global variable summary.
   static bool classof(const GlobalValueSummary *GVS) {
     return GVS->getSummaryKind() == GlobalVarKind;
   }
+
+  GVarFlags varflags() const { return VarFlags; }
+  void setReadOnly(bool RO) { VarFlags.ReadOnly = RO; }
+  bool isReadOnly() const { return VarFlags.ReadOnly; }
 };
 
 struct TypeTestResolution {
@@ -1135,6 +1150,9 @@ public:
 
   /// Print out strongly connected components for debugging.
   void dumpSCCs(raw_ostream &OS);
+
+  /// Analyze index and detect unmodified globals
+  void propagateConstants(const DenseSet<GlobalValue::GUID> &PreservedSymbols);
 };
 
 /// GraphTraits definition to build SCC for the index
@@ -1184,6 +1202,14 @@ struct GraphTraits<ModuleSummaryIndex *>
   }
 };
 
+static inline bool canImportGlobalVar(GlobalValueSummary *S) {
+  assert(isa<GlobalVarSummary>(S->getBaseObject()));
+
+  // We don't import GV with references, because it can result
+  // in promotion of local variables in the source module.
+  return !GlobalValue::isInterposableLinkage(S->linkage()) &&
+         !S->notEligibleToImport() && S->refs().empty();
+}
 } // end namespace llvm
 
 #endif // LLVM_IR_MODULESUMMARYINDEX_H

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=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/IPO/FunctionImport.h (original)
+++ llvm/trunk/include/llvm/Transforms/IPO/FunctionImport.h Thu Nov 15 23:08:00 2018
@@ -176,6 +176,14 @@ void computeDeadSymbols(
     const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols,
     function_ref<PrevailingType(GlobalValue::GUID)> isPrevailing);
 
+/// Compute dead symbols and run constant propagation in combined index
+/// after that.
+void computeDeadSymbolsWithConstProp(
+    ModuleSummaryIndex &Index,
+    const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols,
+    function_ref<PrevailingType(GlobalValue::GUID)> isPrevailing,
+    bool ImportEnabled);
+
 /// Converts value \p GV to declaration, or replaces with a declaration if
 /// it is an alias. Returns true if converted, false if replaced.
 bool convertToDeclaration(GlobalValue &GV);

Modified: llvm/trunk/include/llvm/Transforms/Utils/FunctionImportUtils.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Utils/FunctionImportUtils.h?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Utils/FunctionImportUtils.h (original)
+++ llvm/trunk/include/llvm/Transforms/Utils/FunctionImportUtils.h Thu Nov 15 23:08:00 2018
@@ -113,7 +113,6 @@ public:
 bool renameModuleForThinLTO(
     Module &M, const ModuleSummaryIndex &Index,
     SetVector<GlobalValue *> *GlobalsToImport = nullptr);
-
 } // End llvm namespace
 
 #endif

Modified: llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp (original)
+++ llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp Thu Nov 15 23:08:00 2018
@@ -220,10 +220,19 @@ static void addIntrinsicToSummary(
   }
 }
 
-static void computeFunctionSummary(
-    ModuleSummaryIndex &Index, const Module &M, const Function &F,
-    BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, DominatorTree &DT,
-    bool HasLocalsInUsedOrAsm, DenseSet<GlobalValue::GUID> &CantBePromoted) {
+static bool isNonVolatileLoad(const Instruction *I) {
+  if (const auto *LI = dyn_cast<LoadInst>(I))
+    return !LI->isVolatile();
+
+  return false;
+}
+
+static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M,
+                                   const Function &F, BlockFrequencyInfo *BFI,
+                                   ProfileSummaryInfo *PSI, DominatorTree &DT,
+                                   bool HasLocalsInUsedOrAsm,
+                                   DenseSet<GlobalValue::GUID> &CantBePromoted,
+                                   bool IsThinLTO) {
   // Summary not currently supported for anonymous functions, they should
   // have been named.
   assert(F.hasName());
@@ -244,6 +253,7 @@ static void computeFunctionSummary(
   // Add personality function, prefix data and prologue data to function's ref
   // list.
   findRefEdges(Index, &F, RefEdges, Visited);
+  std::vector<const Instruction *> NonVolatileLoads;
 
   bool HasInlineAsmMaybeReferencingInternal = false;
   bool InitsVarArgs = false;
@@ -256,6 +266,13 @@ static void computeFunctionSummary(
           InitsVarArgs = true;
       }
       ++NumInsts;
+      if (isNonVolatileLoad(&I)) {
+        // Postpone processing of non-volatile load instructions
+        // See comments below
+        Visited.insert(&I);
+        NonVolatileLoads.push_back(&I);
+        continue;
+      }
       findRefEdges(Index, &I, RefEdges, Visited);
       auto CS = ImmutableCallSite(&I);
       if (!CS)
@@ -345,6 +362,24 @@ static void computeFunctionSummary(
       }
     }
 
+  // By now we processed all instructions in a function, except
+  // non-volatile loads. All new refs we add in a loop below
+  // are obviously constant. All constant refs are grouped in the
+  // end of RefEdges vector, so we can use a single integer value
+  // to identify them.
+  unsigned RefCnt = RefEdges.size();
+  for (const Instruction *I : NonVolatileLoads) {
+    Visited.erase(I);
+    findRefEdges(Index, I, RefEdges, Visited);
+  }
+  std::vector<ValueInfo> Refs = RefEdges.takeVector();
+  // Regular LTO module doesn't participate in ThinLTO import,
+  // so no reference from it can be readonly, since this would
+  // require importing variable as local copy
+  if (IsThinLTO)
+    for (; RefCnt < Refs.size(); ++RefCnt)
+      Refs[RefCnt].setReadOnly();
+
   // Explicit add hot edges to enforce importing for designated GUIDs for
   // sample PGO, to enable the same inlines as the profiled optimized binary.
   for (auto &I : F.getImportGUIDs())
@@ -368,9 +403,9 @@ static void computeFunctionSummary(
           // Don't try to import functions with noinline attribute.
           F.getAttributes().hasFnAttribute(Attribute::NoInline)};
   auto FuncSummary = llvm::make_unique<FunctionSummary>(
-      Flags, NumInsts, FunFlags, RefEdges.takeVector(),
-      CallGraphEdges.takeVector(), TypeTests.takeVector(),
-      TypeTestAssumeVCalls.takeVector(), TypeCheckedLoadVCalls.takeVector(),
+      Flags, NumInsts, FunFlags, std::move(Refs), CallGraphEdges.takeVector(),
+      TypeTests.takeVector(), TypeTestAssumeVCalls.takeVector(),
+      TypeCheckedLoadVCalls.takeVector(),
       TypeTestAssumeConstVCalls.takeVector(),
       TypeCheckedLoadConstVCalls.takeVector());
   if (NonRenamableLocal)
@@ -387,8 +422,13 @@ computeVariableSummary(ModuleSummaryInde
   bool NonRenamableLocal = isNonRenamableLocal(V);
   GlobalValueSummary::GVFlags Flags(V.getLinkage(), NonRenamableLocal,
                                     /* Live = */ false, V.isDSOLocal());
-  auto GVarSummary =
-      llvm::make_unique<GlobalVarSummary>(Flags, RefEdges.takeVector());
+
+  // Don't mark variables we won't be able to internalize as read-only.
+  GlobalVarSummary::GVarFlags VarFlags(
+      !V.hasComdat() && !V.hasAppendingLinkage() && !V.isInterposable() &&
+      !V.hasAvailableExternallyLinkage() && !V.hasDLLExportStorageClass());
+  auto GVarSummary = llvm::make_unique<GlobalVarSummary>(Flags, VarFlags,
+                                                         RefEdges.takeVector());
   if (NonRenamableLocal)
     CantBePromoted.insert(V.getGUID());
   if (HasBlockAddress)
@@ -492,13 +532,19 @@ ModuleSummaryIndex llvm::buildModuleSumm
             Index.addGlobalValueSummary(*GV, std::move(Summary));
           } else {
             std::unique_ptr<GlobalVarSummary> Summary =
-                llvm::make_unique<GlobalVarSummary>(GVFlags,
-                                                    ArrayRef<ValueInfo>{});
+                llvm::make_unique<GlobalVarSummary>(
+                    GVFlags, GlobalVarSummary::GVarFlags(),
+                    ArrayRef<ValueInfo>{});
             Index.addGlobalValueSummary(*GV, std::move(Summary));
           }
         });
   }
 
+  bool IsThinLTO = true;
+  if (auto *MD =
+          mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("ThinLTO")))
+    IsThinLTO = MD->getZExtValue();
+
   // Compute summaries for all functions defined in module, and save in the
   // index.
   for (auto &F : M) {
@@ -519,7 +565,7 @@ ModuleSummaryIndex llvm::buildModuleSumm
 
     computeFunctionSummary(Index, M, F, BFI, PSI, DT,
                            !LocalsUsed.empty() || HasLocalInlineAsmSymbol,
-                           CantBePromoted);
+                           CantBePromoted, IsThinLTO);
   }
 
   // Compute summaries for all variables defined in module, and save in the
@@ -550,11 +596,6 @@ ModuleSummaryIndex llvm::buildModuleSumm
   setLiveRoot(Index, "llvm.global_dtors");
   setLiveRoot(Index, "llvm.global.annotations");
 
-  bool IsThinLTO = true;
-  if (auto *MD =
-          mdconst::extract_or_null<ConstantInt>(M.getModuleFlag("ThinLTO")))
-    IsThinLTO = MD->getZExtValue();
-
   for (auto &GlobalList : Index) {
     // Ignore entries for references that are undefined in the current module.
     if (GlobalList.second.SummaryList.empty())

Modified: llvm/trunk/lib/AsmParser/LLParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.cpp?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/lib/AsmParser/LLParser.cpp (original)
+++ llvm/trunk/lib/AsmParser/LLParser.cpp Thu Nov 15 23:08:00 2018
@@ -7715,7 +7715,8 @@ bool LLParser::ParseVariableSummary(std:
   if (ParseToken(lltok::rparen, "expected ')' here"))
     return true;
 
-  auto GS = llvm::make_unique<GlobalVarSummary>(GVFlags, std::move(Refs));
+  auto GS = llvm::make_unique<GlobalVarSummary>(
+      GVFlags, GlobalVarSummary::GVarFlags(), std::move(Refs));
 
   GS->setModulePath(ModulePath);
 

Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)
+++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Thu Nov 15 23:08:00 2018
@@ -898,6 +898,11 @@ static GlobalValueSummary::GVFlags getDe
   return GlobalValueSummary::GVFlags(Linkage, NotEligibleToImport, Live, Local);
 }
 
+// Decode the flags for GlobalVariable in the summary
+static GlobalVarSummary::GVarFlags getDecodedGVarFlags(uint64_t RawFlags) {
+  return GlobalVarSummary::GVarFlags((RawFlags & 0x1) ? true : false);
+}
+
 static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) {
   switch (Val) {
   default: // Map unknown visibilities to default.
@@ -5219,6 +5224,12 @@ static void parseTypeIdSummaryRecord(Arr
     parseWholeProgramDevirtResolution(Record, Strtab, Slot, TypeId);
 }
 
+static void setImmutableRefs(std::vector<ValueInfo> &Refs, unsigned Count) {
+  // Read-only refs are in the end of the refs list.
+  for (unsigned RefNo = Refs.size() - Count; RefNo < Refs.size(); ++RefNo)
+    Refs[RefNo].setReadOnly();
+}
+
 // Eagerly parse the entire summary block. This populates the GlobalValueSummary
 // objects in the index.
 Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
@@ -5236,9 +5247,9 @@ Error ModuleSummaryIndexBitcodeReader::p
   }
   const uint64_t Version = Record[0];
   const bool IsOldProfileFormat = Version == 1;
-  if (Version < 1 || Version > 4)
+  if (Version < 1 || Version > 5)
     return error("Invalid summary version " + Twine(Version) +
-                 ", 1, 2, 3 or 4 expected");
+                 ", 1, 2, 3, 4 or 5 expected");
   Record.clear();
 
   // Keep around the last seen summary to be used when we see an optional
@@ -5317,11 +5328,16 @@ Error ModuleSummaryIndexBitcodeReader::p
       unsigned InstCount = Record[2];
       uint64_t RawFunFlags = 0;
       unsigned NumRefs = Record[3];
+      unsigned NumImmutableRefs = 0;
       int RefListStartIndex = 4;
       if (Version >= 4) {
         RawFunFlags = Record[3];
         NumRefs = Record[4];
         RefListStartIndex = 5;
+        if (Version >= 5) {
+          NumImmutableRefs = Record[5];
+          RefListStartIndex = 6;
+        }
       }
 
       auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);
@@ -5340,6 +5356,7 @@ Error ModuleSummaryIndexBitcodeReader::p
       std::vector<FunctionSummary::EdgeTy> Calls = makeCallList(
           ArrayRef<uint64_t>(Record).slice(CallGraphEdgeStartIndex),
           IsOldProfileFormat, HasProfile, HasRelBF);
+      setImmutableRefs(Refs, NumImmutableRefs);
       auto FS = llvm::make_unique<FunctionSummary>(
           Flags, InstCount, getDecodedFFlags(RawFunFlags), std::move(Refs),
           std::move(Calls), std::move(PendingTypeTests),
@@ -5388,14 +5405,21 @@ Error ModuleSummaryIndexBitcodeReader::p
       TheIndex.addGlobalValueSummary(GUID.first, std::move(AS));
       break;
     }
-    // FS_PERMODULE_GLOBALVAR_INIT_REFS: [valueid, flags, n x valueid]
+    // FS_PERMODULE_GLOBALVAR_INIT_REFS: [valueid, flags, varflags, n x valueid]
     case bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS: {
       unsigned ValueID = Record[0];
       uint64_t RawFlags = Record[1];
+      unsigned RefArrayStart = 2;
+      GlobalVarSummary::GVarFlags GVF;
       auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);
+      if (Version >= 5) {
+        GVF = getDecodedGVarFlags(Record[2]);
+        RefArrayStart = 3;
+      }
       std::vector<ValueInfo> Refs =
-          makeRefList(ArrayRef<uint64_t>(Record).slice(2));
-      auto FS = llvm::make_unique<GlobalVarSummary>(Flags, std::move(Refs));
+          makeRefList(ArrayRef<uint64_t>(Record).slice(RefArrayStart));
+      auto FS =
+          llvm::make_unique<GlobalVarSummary>(Flags, GVF, std::move(Refs));
       FS->setModulePath(getThisModule()->first());
       auto GUID = getValueInfoFromValueId(ValueID);
       FS->setOriginalName(GUID.second);
@@ -5414,12 +5438,17 @@ Error ModuleSummaryIndexBitcodeReader::p
       unsigned InstCount = Record[3];
       uint64_t RawFunFlags = 0;
       unsigned NumRefs = Record[4];
+      unsigned NumImmutableRefs = 0;
       int RefListStartIndex = 5;
 
       if (Version >= 4) {
         RawFunFlags = Record[4];
         NumRefs = Record[5];
         RefListStartIndex = 6;
+        if (Version >= 5) {
+          NumImmutableRefs = Record[6];
+          RefListStartIndex = 7;
+        }
       }
 
       auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);
@@ -5433,6 +5462,7 @@ Error ModuleSummaryIndexBitcodeReader::p
           ArrayRef<uint64_t>(Record).slice(CallGraphEdgeStartIndex),
           IsOldProfileFormat, HasProfile, false);
       ValueInfo VI = getValueInfoFromValueId(ValueID).first;
+      setImmutableRefs(Refs, NumImmutableRefs);
       auto FS = llvm::make_unique<FunctionSummary>(
           Flags, InstCount, getDecodedFFlags(RawFunFlags), std::move(Refs),
           std::move(Edges), std::move(PendingTypeTests),
@@ -5481,10 +5511,17 @@ Error ModuleSummaryIndexBitcodeReader::p
       unsigned ValueID = Record[0];
       uint64_t ModuleId = Record[1];
       uint64_t RawFlags = Record[2];
+      unsigned RefArrayStart = 3;
+      GlobalVarSummary::GVarFlags GVF;
       auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);
+      if (Version >= 5) {
+        GVF = getDecodedGVarFlags(Record[3]);
+        RefArrayStart = 4;
+      }
       std::vector<ValueInfo> Refs =
-          makeRefList(ArrayRef<uint64_t>(Record).slice(3));
-      auto FS = llvm::make_unique<GlobalVarSummary>(Flags, std::move(Refs));
+          makeRefList(ArrayRef<uint64_t>(Record).slice(RefArrayStart));
+      auto FS =
+          llvm::make_unique<GlobalVarSummary>(Flags, GVF, std::move(Refs));
       LastSeenSummary = FS.get();
       FS->setModulePath(ModuleIdMap[ModuleId]);
       ValueInfo VI = getValueInfoFromValueId(ValueID).first;

Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original)
+++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Thu Nov 15 23:08:00 2018
@@ -1000,6 +1000,11 @@ static uint64_t getEncodedGVSummaryFlags
   return RawFlags;
 }
 
+static uint64_t getEncodedGVarFlags(GlobalVarSummary::GVarFlags Flags) {
+  uint64_t RawFlags = Flags.ReadOnly;
+  return RawFlags;
+}
+
 static unsigned getEncodedVisibility(const GlobalValue &GV) {
   switch (GV.getVisibility()) {
   case GlobalValue::DefaultVisibility:   return 0;
@@ -3539,6 +3544,7 @@ void ModuleBitcodeWriterBase::writePerMo
   NameVals.push_back(FS->instCount());
   NameVals.push_back(getEncodedFFlags(FS->fflags()));
   NameVals.push_back(FS->refs().size());
+  NameVals.push_back(FS->immutableRefCount());
 
   for (auto &RI : FS->refs())
     NameVals.push_back(VE.getValueID(RI.getValue()));
@@ -3580,6 +3586,7 @@ void ModuleBitcodeWriterBase::writeModul
   NameVals.push_back(VE.getValueID(&V));
   GlobalVarSummary *VS = cast<GlobalVarSummary>(Summary);
   NameVals.push_back(getEncodedGVSummaryFlags(VS->flags()));
+  NameVals.push_back(getEncodedGVarFlags(VS->varflags()));
 
   unsigned SizeBeforeRefs = NameVals.size();
   for (auto &RI : VS->refs())
@@ -3596,7 +3603,7 @@ void ModuleBitcodeWriterBase::writeModul
 // Current version for the summary.
 // This is bumped whenever we introduce changes in the way some record are
 // interpreted, like flags for instance.
-static const uint64_t INDEX_VERSION = 4;
+static const uint64_t INDEX_VERSION = 5;
 
 /// Emit the per-module summary section alongside the rest of
 /// the module's bitcode.
@@ -3631,6 +3638,7 @@ void ModuleBitcodeWriterBase::writePerMo
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));   // instcount
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4));   // fflags
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4));   // numrefs
+  Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4));   // immutablerefcnt
   // numrefs x valueid, n x (valueid, hotness)
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
@@ -3647,6 +3655,7 @@ void ModuleBitcodeWriterBase::writePerMo
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));   // instcount
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4));   // fflags
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4));   // numrefs
+  Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4));   // immutablerefcnt
   // numrefs x valueid, n x (valueid [, rel_block_freq])
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
@@ -3741,6 +3750,7 @@ void IndexBitcodeWriter::writeCombinedGl
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));   // instcount
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4));   // fflags
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4));   // numrefs
+  Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4));   // immutablerefcnt
   // numrefs x valueid, n x (valueid)
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
@@ -3755,6 +3765,7 @@ void IndexBitcodeWriter::writeCombinedGl
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));   // instcount
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4));   // fflags
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4));   // numrefs
+  Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4));   // immutablerefcnt
   // numrefs x valueid, n x (valueid, hotness)
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
   Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
@@ -3827,6 +3838,7 @@ void IndexBitcodeWriter::writeCombinedGl
       NameVals.push_back(*ValueId);
       NameVals.push_back(Index.getModuleId(VS->modulePath()));
       NameVals.push_back(getEncodedGVSummaryFlags(VS->flags()));
+      NameVals.push_back(getEncodedGVarFlags(VS->varflags()));
       for (auto &RI : VS->refs()) {
         auto RefValueId = getValueId(RI.getGUID());
         if (!RefValueId)
@@ -3852,17 +3864,21 @@ void IndexBitcodeWriter::writeCombinedGl
     NameVals.push_back(FS->instCount());
     NameVals.push_back(getEncodedFFlags(FS->fflags()));
     // Fill in below
-    NameVals.push_back(0);
+    NameVals.push_back(0); // numrefs
+    NameVals.push_back(0); // immutablerefcnt
 
-    unsigned Count = 0;
+    unsigned Count = 0, ImmutableRefCnt = 0;
     for (auto &RI : FS->refs()) {
       auto RefValueId = getValueId(RI.getGUID());
       if (!RefValueId)
         continue;
       NameVals.push_back(*RefValueId);
+      if (RI.isReadOnly())
+        ImmutableRefCnt++;
       Count++;
     }
     NameVals[5] = Count;
+    NameVals[6] = ImmutableRefCnt;
 
     bool HasProfileData = false;
     for (auto &EI : FS->calls()) {

Modified: llvm/trunk/lib/IR/ModuleSummaryIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/ModuleSummaryIndex.cpp?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/lib/IR/ModuleSummaryIndex.cpp (original)
+++ llvm/trunk/lib/IR/ModuleSummaryIndex.cpp Thu Nov 15 23:08:00 2018
@@ -30,6 +30,17 @@ bool ValueInfo::isDSOLocal() const {
                       });
 }
 
+// Gets the number of immutable refs in RefEdgeList
+unsigned FunctionSummary::immutableRefCount() const {
+  // Here we take advantage of having all readonly references
+  // located in the end of the RefEdgeList.
+  auto Refs = refs();
+  unsigned ImmutableRefCnt = 0;
+  for (int I = Refs.size() - 1; I >= 0 && Refs[I].isReadOnly(); --I)
+    ImmutableRefCnt++;
+  return ImmutableRefCnt;
+}
+
 // Collect for the given module the list of function it defines
 // (GUID -> Summary).
 void ModuleSummaryIndex::collectDefinedFunctionsForModule(
@@ -84,6 +95,73 @@ bool ModuleSummaryIndex::isGUIDLive(Glob
   return false;
 }
 
+static void propagateConstantsToRefs(GlobalValueSummary *S) {
+  // If reference is not readonly then referenced summary is not
+  // readonly either. Note that:
+  // - All references from GlobalVarSummary are conservatively considered as
+  //   not readonly. Tracking them properly requires more complex analysis
+  //   then we have now.
+  //
+  // - AliasSummary objects have no refs at all so this function is a no-op
+  //   for them.
+  for (auto &VI : S->refs()) {
+    if (VI.isReadOnly()) {
+      // We only mark refs as readonly when computing function summaries on
+      // analysis phase.
+      assert(isa<FunctionSummary>(S));
+      continue;
+    }
+    for (auto &Ref : VI.getSummaryList())
+      // If references to alias is not readonly then aliasee is not readonly
+      if (auto *GVS = dyn_cast<GlobalVarSummary>(Ref->getBaseObject()))
+        GVS->setReadOnly(false);
+  }
+}
+
+// Do the constant propagation in combined index.
+// The goal of constant propagation is internalization of readonly
+// variables. To determine which variables are readonly and which
+// are not we take following steps:
+// - During analysis we speculatively assign readonly attribute to
+//   all variables which can be internalized. When computing function
+//   summary we also assign readonly attribute to a reference if
+//   function doesn't modify referenced variable.
+//
+// - After computing dead symbols in combined index we do the constant
+//   propagation. During this step we clear readonly attribute from
+//   all variables which:
+//   a. are dead, preserved or can't be imported
+//   b. referenced by any global variable initializer
+//   c. referenced by a function and reference is not readonly
+//
+// Internalization itself happens in the backend after import is finished
+// See internalizeImmutableGVs.
+void ModuleSummaryIndex::propagateConstants(
+    const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) {
+  for (auto &P : *this)
+    for (auto &S : P.second.SummaryList) {
+      if (!isGlobalValueLive(S.get()))
+        // We don't examine references from dead objects
+        continue;
+
+      // Global variable can't be marked read only if it is not eligible
+      // to import since we need to ensure that all external references
+      // get a local (imported) copy. It also can't be marked read only
+      // if it or any alias (since alias points to the same memory) are
+      // preserved or notEligibleToImport, since either of those means
+      // there could be writes that are not visible (because preserved
+      // means it could have external to DSO writes, and notEligibleToImport
+      // means it could have writes via inline assembly leading it to be
+      // in the @llvm.*used).
+      if (auto *GVS = dyn_cast<GlobalVarSummary>(S->getBaseObject()))
+        // Here we intentionally pass S.get() not GVS, because S could be
+        // an alias.
+        if (!canImportGlobalVar(S.get()) || GUIDPreservedSymbols.count(P.first))
+          GVS->setReadOnly(false);
+      propagateConstantsToRefs(S.get());
+    }
+}
+
 // TODO: write a graphviz dumper for SCCs (see ModuleSummaryIndex::exportToDot)
 // then delete this function and update its tests
 LLVM_DUMP_METHOD
@@ -108,6 +186,7 @@ namespace {
 struct Attributes {
   void add(const Twine &Name, const Twine &Value,
            const Twine &Comment = Twine());
+  void addComment(const Twine &Comment);
   std::string getAsString() const;
 
   std::vector<std::string> Attrs;
@@ -129,6 +208,10 @@ void Attributes::add(const Twine &Name,
   A += Value.str();
   A += "\"";
   Attrs.push_back(A);
+  addComment(Comment);
+}
+
+void Attributes::addComment(const Twine &Comment) {
   if (!Comment.isTriviallyEmpty()) {
     if (Comments.empty())
       Comments = " // ";
@@ -237,6 +320,12 @@ static void defineExternalNode(raw_ostre
   OS << "\"]; // defined externally\n";
 }
 
+static bool hasReadOnlyFlag(const GlobalValueSummary *S) {
+  if (auto *GVS = dyn_cast<GlobalVarSummary>(S))
+    return GVS->isReadOnly();
+  return false;
+}
+
 void ModuleSummaryIndex::exportToDot(raw_ostream &OS) const {
   std::vector<Edge> CrossModuleEdges;
   DenseMap<GlobalValue::GUID, std::vector<uint64_t>> NodeMap;
@@ -252,13 +341,17 @@ void ModuleSummaryIndex::exportToDot(raw
   };
 
   auto DrawEdge = [&](const char *Pfx, uint64_t SrcMod, GlobalValue::GUID SrcId,
-                      uint64_t DstMod, GlobalValue::GUID DstId, int TypeOrHotness) {
-    // 0 corresponds to alias edge, 1 to ref edge, 2 to call with unknown
-    // hotness, ...
-    TypeOrHotness += 2;
+                      uint64_t DstMod, GlobalValue::GUID DstId,
+                      int TypeOrHotness) {
+    // 0 - alias
+    // 1 - reference
+    // 2 - constant reference
+    // Other value: (hotness - 3).
+    TypeOrHotness += 3;
     static const char *EdgeAttrs[] = {
         " [style=dotted]; // alias",
         " [style=dashed]; // ref",
+        " [style=dashed,color=forestgreen]; // const-ref",
         " // call (hotness : Unknown)",
         " [color=blue]; // call (hotness : Cold)",
         " // call (hotness : None)",
@@ -301,6 +394,8 @@ void ModuleSummaryIndex::exportToDot(raw
         A.add("shape", "box");
       } else {
         A.add("shape", "Mrecord", "variable");
+        if (Flags.Live && hasReadOnlyFlag(SummaryIt.second))
+          A.addComment("immutable");
       }
 
       auto VI = getValueInfo(SummaryIt.first);
@@ -318,7 +413,7 @@ void ModuleSummaryIndex::exportToDot(raw
     for (auto &SummaryIt : GVSMap) {
       auto *GVS = SummaryIt.second;
       for (auto &R : GVS->refs())
-        Draw(SummaryIt.first, R.getGUID(), -1);
+        Draw(SummaryIt.first, R.getGUID(), R.isReadOnly() ? -1 : -2);
 
       if (auto *AS = dyn_cast_or_null<AliasSummary>(SummaryIt.second)) {
         GlobalValue::GUID AliaseeId;
@@ -331,7 +426,7 @@ void ModuleSummaryIndex::exportToDot(raw
             AliaseeId = AliaseeOrigId;
         }
 
-        Draw(SummaryIt.first, AliaseeId, -2);
+        Draw(SummaryIt.first, AliaseeId, -3);
         continue;
       }
 

Modified: llvm/trunk/lib/LTO/LTO.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/LTO/LTO.cpp?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/lib/LTO/LTO.cpp (original)
+++ llvm/trunk/lib/LTO/LTO.cpp Thu Nov 15 23:08:00 2018
@@ -187,6 +187,8 @@ static void computeCacheKey(
       AddUnsigned(VI.isDSOLocal());
       AddUsedCfiGlobal(VI.getGUID());
     }
+    if (auto *GVS = dyn_cast<GlobalVarSummary>(GS))
+      AddUnsigned(GVS->isReadOnly());
     if (auto *FS = dyn_cast<FunctionSummary>(GS)) {
       for (auto &TT : FS->type_tests())
         UsedTypeIds.insert(TT);
@@ -809,7 +811,8 @@ Error LTO::run(AddStreamFn AddStream, Na
       return PrevailingType::Unknown;
     return It->second;
   };
-  computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols, isPrevailing);
+  computeDeadSymbolsWithConstProp(ThinLTO.CombinedIndex, GUIDPreservedSymbols,
+                                  isPrevailing, Conf.OptLevel > 0);
 
   // Setup output file to emit statistics.
   std::unique_ptr<ToolOutputFile> StatsFile = nullptr;

Modified: llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp (original)
+++ llvm/trunk/lib/LTO/ThinLTOCodeGenerator.cpp Thu Nov 15 23:08:00 2018
@@ -298,7 +298,7 @@ public:
       const FunctionImporter::ImportMapTy &ImportList,
       const FunctionImporter::ExportSetTy &ExportList,
       const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
-      const GVSummaryMapTy &DefinedFunctions,
+      const GVSummaryMapTy &DefinedGVSummaries,
       const DenseSet<GlobalValue::GUID> &PreservedSymbols, unsigned OptLevel,
       bool Freestanding, const TargetMachineBuilder &TMBuilder) {
     if (CachePath.empty())
@@ -368,6 +368,10 @@ public:
     for (auto &Entry : ImportList) {
       auto ModHash = Index.getModuleHash(Entry.first());
       Hasher.update(ArrayRef<uint8_t>((uint8_t *)&ModHash[0], sizeof(ModHash)));
+      for (auto Guid : Entry.second)
+        if (auto *GVS = dyn_cast<GlobalVarSummary>(
+                Index.getGlobalValueSummary(Guid, false)))
+          AddUnsigned(GVS->isReadOnly());
     }
 
     // Include the hash for the resolved ODR.
@@ -380,11 +384,15 @@ public:
 
     // Include the hash for the preserved symbols.
     for (auto &Entry : PreservedSymbols) {
-      if (DefinedFunctions.count(Entry))
+      if (DefinedGVSummaries.count(Entry))
         Hasher.update(
             ArrayRef<uint8_t>((const uint8_t *)&Entry, sizeof(GlobalValue::GUID)));
     }
 
+    for (auto &Entry : DefinedGVSummaries)
+      if (auto *GVS = dyn_cast<GlobalVarSummary>(Entry.second))
+        AddUnsigned(GVS->isReadOnly());
+
     // This choice of file name allows the cache to be pruned (see pruneCache()
     // in include/llvm/Support/CachePruning.h).
     sys::path::append(EntryPath, CachePath,
@@ -646,7 +654,8 @@ static void computeDeadSymbolsInIndex(
   auto isPrevailing = [&](GlobalValue::GUID G) {
     return PrevailingType::Unknown;
   };
-  computeDeadSymbols(Index, GUIDPreservedSymbols, isPrevailing);
+  computeDeadSymbolsWithConstProp(Index, GUIDPreservedSymbols, isPrevailing,
+                                  /* ImportEnabled = */ true);
 }
 
 /**
@@ -983,13 +992,13 @@ void ThinLTOCodeGenerator::run() {
         auto ModuleIdentifier = ModuleBuffer.getBufferIdentifier();
         auto &ExportList = ExportLists[ModuleIdentifier];
 
-        auto &DefinedFunctions = ModuleToDefinedGVSummaries[ModuleIdentifier];
+        auto &DefinedGVSummaries = ModuleToDefinedGVSummaries[ModuleIdentifier];
 
         // The module may be cached, this helps handling it.
         ModuleCacheEntry CacheEntry(CacheOptions.Path, *Index, ModuleIdentifier,
                                     ImportLists[ModuleIdentifier], ExportList,
                                     ResolvedODR[ModuleIdentifier],
-                                    DefinedFunctions, GUIDPreservedSymbols,
+                                    DefinedGVSummaries, GUIDPreservedSymbols,
                                     OptLevel, Freestanding, TMBuilder);
         auto CacheEntryPath = CacheEntry.getEntryPath();
 

Modified: llvm/trunk/lib/Linker/IRMover.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Linker/IRMover.cpp?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/lib/Linker/IRMover.cpp (original)
+++ llvm/trunk/lib/Linker/IRMover.cpp Thu Nov 15 23:08:00 2018
@@ -1062,11 +1062,6 @@ void IRLinker::prepareCompileUnitsForImp
     ValueMap.MD()[CU->getRawEnumTypes()].reset(nullptr);
     ValueMap.MD()[CU->getRawMacros()].reset(nullptr);
     ValueMap.MD()[CU->getRawRetainedTypes()].reset(nullptr);
-    // We import global variables only temporarily in order for instcombine
-    // and globalopt to perform constant folding and static constructor
-    // evaluation. After that elim-avail-extern will covert imported globals
-    // back to declarations, so we don't need debug info for them.
-    ValueMap.MD()[CU->getRawGlobalVariables()].reset(nullptr);
 
     // Imported entities only need to be mapped in if they have local
     // scope, as those might correspond to an imported entity inside a

Modified: llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp Thu Nov 15 23:08:00 2018
@@ -294,10 +294,8 @@ static void computeImportForReferencedGl
     LLVM_DEBUG(dbgs() << " ref -> " << VI << "\n");
 
     for (auto &RefSummary : VI.getSummaryList())
-      if (RefSummary->getSummaryKind() == GlobalValueSummary::GlobalVarKind &&
-          !RefSummary->notEligibleToImport() &&
-          !GlobalValue::isInterposableLinkage(RefSummary->linkage()) &&
-          RefSummary->refs().empty()) {
+      if (isa<GlobalVarSummary>(RefSummary.get()) &&
+          canImportGlobalVar(RefSummary.get())) {
         auto ILI = ImportList[RefSummary->modulePath()].insert(VI.getGUID());
         // Only update stat if we haven't already imported this variable.
         if (ILI.second)
@@ -824,6 +822,25 @@ void llvm::computeDeadSymbols(
   NumLiveSymbols += LiveSymbols;
 }
 
+// Compute dead symbols and propagate constants in combined index.
+void llvm::computeDeadSymbolsWithConstProp(
+    ModuleSummaryIndex &Index,
+    const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols,
+    function_ref<PrevailingType(GlobalValue::GUID)> isPrevailing,
+    bool ImportEnabled) {
+  computeDeadSymbols(Index, GUIDPreservedSymbols, isPrevailing);
+  if (ImportEnabled) {
+    Index.propagateConstants(GUIDPreservedSymbols);
+  } else {
+    // If import is disabled we should drop read-only attribute
+    // from all summaries to prevent internalization.
+    for (auto &P : Index)
+      for (auto &S : P.second.SummaryList)
+        if (auto *GVS = dyn_cast<GlobalVarSummary>(S.get()))
+          GVS->setReadOnly(false);
+  }
+}
+
 /// Compute the set of summaries needed for a ThinLTO backend compilation of
 /// \p ModulePath.
 void llvm::gatherImportedSummariesForModule(
@@ -1020,6 +1037,18 @@ static Function *replaceAliasWithAliasee
   return NewFn;
 }
 
+// Internalize values that we marked with specific attribute
+// in processGlobalForThinLTO.
+static void internalizeImmutableGVs(Module &M) {
+  for (auto &GV : M.globals())
+    // Skip GVs which have been converted to declarations
+    // by dropDeadSymbols.
+    if (!GV.isDeclaration() && GV.hasAttribute("thinlto-internalize")) {
+      GV.setLinkage(GlobalValue::InternalLinkage);
+      GV.setVisibility(GlobalValue::DefaultVisibility);
+    }
+}
+
 // Automatically import functions in Module \p DestModule based on the summaries
 // index.
 Expected<bool> FunctionImporter::importFunctions(
@@ -1143,6 +1172,8 @@ Expected<bool> FunctionImporter::importF
     NumImportedModules++;
   }
 
+  internalizeImmutableGVs(DestModule);
+
   NumImportedFunctions += (ImportedCount - ImportedGVCount);
   NumImportedGlobalVars += ImportedGVCount;
 

Modified: llvm/trunk/lib/Transforms/Utils/FunctionImportUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/FunctionImportUtils.cpp?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/FunctionImportUtils.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/FunctionImportUtils.cpp Thu Nov 15 23:08:00 2018
@@ -204,8 +204,9 @@ void FunctionImportGlobalProcessing::pro
 
   // Check the summaries to see if the symbol gets resolved to a known local
   // definition.
+  ValueInfo VI;
   if (GV.hasName()) {
-    ValueInfo VI = ImportIndex.getValueInfo(GV.getGUID());
+    VI = ImportIndex.getValueInfo(GV.getGUID());
     if (VI && VI.isDSOLocal()) {
       GV.setDSOLocal(true);
       if (GV.hasDLLImportStorageClass())
@@ -213,6 +214,22 @@ void FunctionImportGlobalProcessing::pro
     }
   }
 
+  // Mark read-only variables which can be imported with specific attribute.
+  // We can't internalize them now because IRMover will fail to link variable
+  // definitions to their external declarations during ThinLTO import. We'll
+  // internalize read-only variables later, after import is finished.
+  // See internalizeImmutableGVs.
+  //
+  // If global value dead stripping is not enabled in summary then
+  // propagateConstants hasn't been run. We can't internalize GV
+  // in such case.
+  if (!GV.isDeclaration() && VI && ImportIndex.withGlobalValueDeadStripping()) {
+    const auto &SL = VI.getSummaryList();
+    auto *GVS = SL.empty() ? nullptr : dyn_cast<GlobalVarSummary>(SL[0].get());
+    if (GVS && GVS->isReadOnly())
+      cast<GlobalVariable>(&GV)->addAttribute("thinlto-internalize");
+  }
+
   bool DoPromote = false;
   if (GV.hasLocalLinkage() &&
       ((DoPromote = shouldPromoteLocalToGlobal(&GV)) || isPerformingImport())) {
@@ -230,7 +247,7 @@ void FunctionImportGlobalProcessing::pro
   // Remove functions imported as available externally defs from comdats,
   // as this is a declaration for the linker, and will be dropped eventually.
   // It is illegal for comdats to contain declarations.
-  auto *GO = dyn_cast_or_null<GlobalObject>(&GV);
+  auto *GO = dyn_cast<GlobalObject>(&GV);
   if (GO && GO->isDeclarationForLinker() && GO->hasComdat()) {
     // The IRMover should not have placed any imported declarations in
     // a comdat, so the only declaration that should be in a comdat

Modified: llvm/trunk/test/Bitcode/summary_version.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/summary_version.ll?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/summary_version.ll (original)
+++ llvm/trunk/test/Bitcode/summary_version.ll Thu Nov 15 23:08:00 2018
@@ -2,7 +2,7 @@
 ; RUN: opt  -module-summary  %s -o - | llvm-bcanalyzer -dump | FileCheck %s
 
 ; CHECK: <GLOBALVAL_SUMMARY_BLOCK
-; CHECK: <VERSION op0=4/>
+; CHECK: <VERSION op0=5/>
 
 
 

Modified: llvm/trunk/test/Bitcode/thinlto-alias.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-alias.ll?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-alias.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-alias.ll Thu Nov 15 23:08:00 2018
@@ -20,7 +20,7 @@
 ; CHECK-NEXT:    <VERSION
 ; See if the call to func is registered.
 ; The value id 1 matches the second FUNCTION record above.
-; CHECK-NEXT:    <PERMODULE {{.*}} op5=1/>
+; CHECK-NEXT:    <PERMODULE {{.*}} op6=1/>
 ; CHECK-NEXT:  </GLOBALVAL_SUMMARY_BLOCK>
 
 ; CHECK: <STRTAB_BLOCK
@@ -33,7 +33,7 @@
 ; COMBINED-NEXT:    <VALUE_GUID op0=[[ALIASID:[0-9]+]] op1=-5751648690987223394/>
 ; COMBINED-NEXT:    <VALUE_GUID
 ; COMBINED-NEXT:    <VALUE_GUID op0=[[ALIASEEID:[0-9]+]] op1=-1039159065113703048/>
-; COMBINED-NEXT:    <COMBINED {{.*}} op6=[[ALIASID]]/>
+; COMBINED-NEXT:    <COMBINED {{.*}} op7=[[ALIASID]]/>
 ; COMBINED-NEXT:    <COMBINED {{.*}}
 ; COMBINED-NEXT:    <COMBINED_ALIAS  {{.*}} op3=[[ALIASEEID]]
 ; COMBINED-NEXT:  </GLOBALVAL_SUMMARY_BLOCK

Modified: llvm/trunk/test/Bitcode/thinlto-alias2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-alias2.ll?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-alias2.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-alias2.ll Thu Nov 15 23:08:00 2018
@@ -4,7 +4,7 @@
 
 ; CHECK:       <GLOBALVAL_SUMMARY_BLOCK
 ; CHECK-NEXT:    <VERSION
-; CHECK-NEXT:    <PERMODULE {{.*}} op4=0 op5=[[ALIASID:[0-9]+]]/>
+; CHECK-NEXT:    <PERMODULE {{.*}} op4=0 op5=0 op6=[[ALIASID:[0-9]+]]/>
 ; CHECK-NEXT:    <PERMODULE {{.*}} op0=[[ALIASEEID:[0-9]+]]
 ; CHECK-NEXT:    <ALIAS {{.*}} op0=[[ALIASID]] {{.*}} op2=[[ALIASEEID]]/>
 ; CHECK-NEXT:  </GLOBALVAL_SUMMARY_BLOCK>

Modified: llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-cast.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-cast.ll?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-cast.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-cast.ll Thu Nov 15 23:08:00 2018
@@ -6,9 +6,9 @@
 ; CHECK:       <GLOBALVAL_SUMMARY_BLOCK
 ; CHECK-NEXT:    <VERSION
 ; "op7" is a call to "callee" function.
-; CHECK-NEXT:    <PERMODULE {{.*}} op7=3 op8=[[ALIASID:[0-9]+]]/>
+; CHECK-NEXT:    <PERMODULE {{.*}} op8=3 op9=[[ALIASID:[0-9]+]]/>
 ; "another_caller" has only references but no calls.
-; CHECK-NEXT:    <PERMODULE {{.*}} op4=3 {{.*}} op7={{[0-9]+}}/>
+; CHECK-NEXT:    <PERMODULE {{.*}} op4=3 {{.*}} op8={{[0-9]+}}/>
 ; CHECK-NEXT:    <PERMODULE {{.*}} op0=[[ALIASEEID:[0-9]+]]
 ; CHECK-NEXT:    <ALIAS {{.*}} op0=[[ALIASID]] {{.*}} op2=[[ALIASEEID]]/>
 ; CHECK-NEXT:  </GLOBALVAL_SUMMARY_BLOCK>

Modified: llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-pgo.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-pgo.ll?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-pgo.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-pgo.ll Thu Nov 15 23:08:00 2018
@@ -17,7 +17,7 @@
 ; CHECK:       <GLOBALVAL_SUMMARY_BLOCK
 ; CHECK-NEXT:    <VERSION
 ; See if the call to func is registered, using the expected hotness type.
-; CHECK-NEXT:    <PERMODULE_PROFILE {{.*}} op5=1 op6=2/>
+; CHECK-NEXT:    <PERMODULE_PROFILE {{.*}} op6=1 op7=2/>
 ; CHECK-NEXT:  </GLOBALVAL_SUMMARY_BLOCK>
 ; CHECK: <STRTAB_BLOCK
 ; CHECK-NEXT: blob data = 'mainfunc{{.*}}'
@@ -30,7 +30,7 @@
 ; COMBINED-NEXT:    <COMBINED
 ; See if the call to func is registered, using the expected hotness type.
 ; op6=2 which is hotnessType::None.
-; COMBINED-NEXT:    <COMBINED_PROFILE {{.*}} op6=[[FUNCID]] op7=2/>
+; COMBINED-NEXT:    <COMBINED_PROFILE {{.*}} op7=[[FUNCID]] op8=2/>
 ; COMBINED-NEXT:  </GLOBALVAL_SUMMARY_BLOCK>
 
 ; ModuleID = 'thinlto-function-summary-callgraph.ll'

Modified: llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-profile-summary.ll Thu Nov 15 23:08:00 2018
@@ -48,7 +48,7 @@
 ; CHECK-NEXT:    <VERSION
 ; CHECK-NEXT:    <VALUE_GUID op0=25 op1=123/>
 ; op4=hot1 op6=cold op8=hot2 op10=hot4 op12=none1 op14=hot3 op16=none2 op18=none3 op20=123
-; CHECK-NEXT:    <PERMODULE_PROFILE {{.*}} op5=1 op6=3 op7=5 op8=1 op9=2 op10=3 op11=4 op12=1 op13=6 op14=2 op15=3 op16=3 op17=7 op18=2 op19=8 op20=2 op21=25 op22=4/>
+; CHECK-NEXT:    <PERMODULE_PROFILE {{.*}} op6=1 op7=3 op8=5 op9=1 op10=2 op11=3 op12=4 op13=1 op14=6 op15=2 op16=3 op17=3 op18=7 op19=2 op20=8 op21=2 op22=25 op23=4/>
 ; CHECK-NEXT:  </GLOBALVAL_SUMMARY_BLOCK>
 
 ; CHECK: <STRTAB_BLOCK
@@ -71,7 +71,7 @@
 ; COMBINED-NEXT:    <COMBINED abbrevid=
 ; COMBINED-NEXT:    <COMBINED abbrevid=
 ; COMBINED-NEXT:    <COMBINED abbrevid=
-; COMBINED-NEXT:    <COMBINED_PROFILE {{.*}} op6=[[HOT1:.*]] op7=3 op8=[[COLD:.*]] op9=1 op10=[[HOT2:.*]] op11=3 op12=[[NONE1:.*]] op13=2 op14=[[HOT3:.*]] op15=3 op16=[[NONE2:.*]] op17=2 op18=[[NONE3:.*]] op19=2/>
+; COMBINED-NEXT:    <COMBINED_PROFILE {{.*}} op7=[[HOT1:.*]] op8=3 op9=[[COLD:.*]] op10=1 op11=[[HOT2:.*]] op12=3 op13=[[NONE1:.*]] op14=2 op15=[[HOT3:.*]] op16=3 op17=[[NONE2:.*]] op18=2 op19=[[NONE3:.*]] op20=2/>
 ; COMBINED_NEXT:    <COMBINED abbrevid=
 ; COMBINED_NEXT:  </GLOBALVAL_SUMMARY_BLOCK>
 

Modified: llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-relbf.ll Thu Nov 15 23:08:00 2018
@@ -13,7 +13,7 @@
 ; CHECK:       <GLOBALVAL_SUMMARY_BLOCK
 ; CHECK-NEXT:    <VERSION
 ; See if the call to func is registered.
-; CHECK-NEXT:    <PERMODULE_RELBF {{.*}} op4=1 {{.*}} op7=256
+; CHECK-NEXT:    <PERMODULE_RELBF {{.*}} op4=1 {{.*}} op8=256
 ; CHECK-NEXT:  </GLOBALVAL_SUMMARY_BLOCK>
 ; CHECK: <STRTAB_BLOCK
 ; CHECK-NEXT: blob data = 'undefinedglobmainfunc{{.*}}'

Modified: llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph-sample-profile-summary.ll Thu Nov 15 23:08:00 2018
@@ -31,7 +31,7 @@
 ; CHECK-NEXT:    <VERSION
 ; CHECK-NEXT:    <VALUE_GUID op0=26 op1=123/>
 ; op4=none1 op6=hot1 op8=cold1 op10=none2 op12=hot2 op14=cold2 op16=none3 op18=hot3 op20=cold3 op22=123
-; CHECK-NEXT:    <PERMODULE_PROFILE {{.*}} op5=7 op6=0 op7=1 op8=3 op9=4 op10=1 op11=8 op12=0 op13=2 op14=3 op15=5 op16=1 op17=9 op18=0 op19=3 op20=3 op21=6 op22=1 op23=26 op24=4/>
+; CHECK-NEXT:    <PERMODULE_PROFILE {{.*}} op6=7 op7=0 op8=1 op9=3 op10=4 op11=1 op12=8 op13=0 op14=2 op15=3 op16=5 op17=1 op18=9 op19=0 op20=3 op21=3 op22=6 op23=1 op24=26 op25=4/>
 ; CHECK-NEXT:  </GLOBALVAL_SUMMARY_BLOCK>
 
 ; CHECK: <STRTAB_BLOCK
@@ -58,7 +58,7 @@
 ; COMBINED-NEXT:    <COMBINED abbrevid=
 ; COMBINED-NEXT:    <COMBINED abbrevid=
 ; COMBINED-NEXT:    <COMBINED abbrevid=
-; COMBINED-NEXT:    <COMBINED_PROFILE {{.*}} op6=[[NONE1:.*]] op7=0 op8=[[HOT1:.*]] op9=3 op10=[[COLD1:.*]] op11=1 op12=[[NONE2:.*]] op13=0 op14=[[HOT2:.*]] op15=3 op16=[[COLD2:.*]] op17=1 op18=[[NONE3:.*]] op19=0 op20=[[HOT3:.*]] op21=3 op22=[[COLD3:.*]] op23=1/>
+; COMBINED-NEXT:    <COMBINED_PROFILE {{.*}} op7=[[NONE1:.*]] op8=0 op9=[[HOT1:.*]] op10=3 op11=[[COLD1:.*]] op12=1 op13=[[NONE2:.*]] op14=0 op15=[[HOT2:.*]] op16=3 op17=[[COLD2:.*]] op18=1 op19=[[NONE3:.*]] op20=0 op21=[[HOT3:.*]] op22=3 op23=[[COLD3:.*]] op24=1/>
 ; COMBINED_NEXT:    <COMBINED abbrevid=
 ; COMBINED_NEXT:  </GLOBALVAL_SUMMARY_BLOCK>
 

Modified: llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph.ll?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-function-summary-callgraph.ll Thu Nov 15 23:08:00 2018
@@ -17,7 +17,7 @@
 ; CHECK-NEXT: <FUNCTION op0=17 op1=4
 ; CHECK:       <GLOBALVAL_SUMMARY_BLOCK
 ; CHECK-NEXT:    <VERSION
-; See if the call to func is registered.
+; See if the call to func is registered
 ; CHECK-NEXT:    <PERMODULE {{.*}} op4=1
 ; CHECK-NEXT:  </GLOBALVAL_SUMMARY_BLOCK>
 ; CHECK: <STRTAB_BLOCK
@@ -33,7 +33,7 @@
 ; COMBINED-NEXT:    <VALUE_GUID
 ; COMBINED-NEXT:    <COMBINED
 ; See if the call to func is registered.
-; COMBINED-NEXT:    <COMBINED {{.*}} op6=[[FUNCID]]/>
+; COMBINED-NEXT:    <COMBINED {{.*}} op7=[[FUNCID]]/>
 ; COMBINED-NEXT:  </GLOBALVAL_SUMMARY_BLOCK>
 
 ; ModuleID = 'thinlto-function-summary-callgraph.ll'

Modified: llvm/trunk/test/Bitcode/thinlto-function-summary-refgraph.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/thinlto-function-summary-refgraph.ll?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/test/Bitcode/thinlto-function-summary-refgraph.ll (original)
+++ llvm/trunk/test/Bitcode/thinlto-function-summary-refgraph.ll Thu Nov 15 23:08:00 2018
@@ -41,27 +41,27 @@
 ; CHECK:       <GLOBALVAL_SUMMARY_BLOCK
 ; Function main contains call to func, as well as address reference to func:
 ; op0=main op4=func op5=func
-; CHECK-DAG:    <PERMODULE {{.*}} op0=11 op1=0 {{.*}} op4=1 op5=2 op6=2/>
+; CHECK-DAG:    <PERMODULE {{.*}} op0=11 op1=0 {{.*}} op4=1 op5=0 op6=2 op7=2/>
 ; Function W contains a call to func3 as well as a reference to globalvar:
 ; op0=W op4=globalvar op5=func3
-; CHECK-DAG:    <PERMODULE {{.*}} op0=6 op1=5 {{.*}} op4=1 op5=1 op6=5/>
+; CHECK-DAG:    <PERMODULE {{.*}} op0=6 op1=5 {{.*}} op4=1 op5=0 op6=1 op7=5/>
 ; Function X contains call to foo, as well as address reference to foo
 ; which is in the same instruction as the call:
 ; op0=X op4=foo op5=foo
-; CHECK-DAG:    <PERMODULE {{.*}} op0=7 op1=1 {{.*}} op4=1 op5=4 op6=4/>
+; CHECK-DAG:    <PERMODULE {{.*}} op0=7 op1=1 {{.*}} op4=1 op5=0 op6=4 op7=4/>
 ; Function Y contains call to func2, and ensures we don't incorrectly add
 ; a reference to it when reached while earlier analyzing the phi using its
 ; return value:
 ; op0=Y op4=func2
-; CHECK-DAG:    <PERMODULE {{.*}} op0=8 op1=72 {{.*}} op4=0 op5=3/>
+; CHECK-DAG:    <PERMODULE {{.*}} op0=8 op1=72 {{.*}} op4=0 op5=0 op6=3/>
 ; Function Z contains call to func2, and ensures we don't incorrectly add
 ; a reference to it when reached while analyzing subsequent use of its return
 ; value:
 ; op0=Z op4=func2
-; CHECK-DAG:    <PERMODULE {{.*}} op0=9 op1=3 {{.*}} op4=0 op5=3/>
+; CHECK-DAG:    <PERMODULE {{.*}} op0=9 op1=3 {{.*}} op4=0 op5=0 op6=3/>
 ; Variable bar initialization contains address reference to func:
 ; op0=bar op2=func
-; CHECK-DAG:    <PERMODULE_GLOBALVAR_INIT_REFS {{.*}} op0=0 op1=0 op2=2/>
+; CHECK-DAG:    <PERMODULE_GLOBALVAR_INIT_REFS {{.*}} op0=0 op1=0 op2=1 op3=2/>
 ; CHECK:  </GLOBALVAL_SUMMARY_BLOCK>
 
 ; CHECK: <STRTAB_BLOCK

Added: llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-alias.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-alias.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-alias.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-alias.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,5 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g = global i32 42, align 4
+ at g.alias = weak alias i32, i32* @g

Added: llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-foo.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-foo.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-foo.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-foo.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,19 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at gFoo = internal unnamed_addr global i32 1, align 4
+
+; Function Attrs: norecurse nounwind readonly ssp uwtable
+define i32 @foo() local_unnamed_addr {
+  %1 = load i32, i32* @gFoo, align 4
+  ret i32 %1
+}
+
+; Function Attrs: nounwind ssp uwtable
+define void @bar() local_unnamed_addr {
+  %1 = tail call i32 @rand()
+  store i32 %1, i32* @gFoo, align 4
+  ret void
+}
+
+declare i32 @rand() local_unnamed_addr

Added: llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-test1.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-test1.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-test1.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-test1.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,10 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind ssp uwtable
+define i32 @test() local_unnamed_addr {
+  %1 = tail call i32 (...) @foo()
+  ret i32 %1
+}
+
+declare i32 @foo(...) local_unnamed_addr

Added: llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-test2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-test2.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-test2.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-cache-test2.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,14 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind ssp uwtable
+define i32 @test() local_unnamed_addr {
+  %1 = tail call i32 (...) @foo()
+  %2 = tail call i32 (...) @bar()
+  %3 = add nsw i32 %2, %1
+  ret i32 %3
+}
+
+declare i32 @foo(...) local_unnamed_addr
+
+declare i32 @bar(...) local_unnamed_addr

Added: llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-comdat.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-comdat.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-comdat.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-comdat.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,5 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+$comdat.any = comdat any
+ at g = global i32 42, comdat($comdat.any)

Added: llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-define-g.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-define-g.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-define-g.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-define-g.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,4 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g = global i32 42, align 4

Added: llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-full-lto.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-full-lto.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-full-lto.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-full-lto.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,12 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g = external global i32
+
+define i32 @foo() {
+  %v = load i32, i32* @g
+  ret i32 %v
+}
+
+!0 = !{i32 1, !"ThinLTO", i32 0}
+!llvm.module.flags = !{ !0 }

Added: llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-gvref.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-gvref.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-gvref.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-gvref.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,5 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at b = global i32* @a, align 8
+ at a = global i32 42, align 4

Added: llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-linkage.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-linkage.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-linkage.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop-linkage.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,15 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g1 = common global i32 0, align 4
+ at g2 = global i32 42, align 4
+ at g3 = available_externally global i32 42, align 4
+
+define i32 @foo() {
+  %v1 = load i32, i32* @g1
+  %v2 = load i32, i32* @g2
+  %v3 = load i32, i32* @g3
+  %s1 = add i32 %v1, %v2
+  %s2 = add i32 %s1, %v3
+  ret i32 %s2
+}

Added: llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/Inputs/index-const-prop.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,64 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-linux-gnu"
+
+ at gBar = local_unnamed_addr global i32 2, align 4, !dbg !0
+ at gFoo = internal unnamed_addr global i32 1, align 4, !dbg !6
+
+; Function Attrs: norecurse nounwind readonly
+define i32 @foo() local_unnamed_addr #0 !dbg !14 {
+  %1 = load i32, i32* @gFoo, align 4, !dbg !17
+  ret i32 %1, !dbg !18
+}
+
+; Function Attrs: norecurse nounwind readonly
+define i32 @bar() local_unnamed_addr #0 !dbg !19 {
+  %1 = load i32, i32* @gBar, align 4, !dbg !20
+  ret i32 %1, !dbg !21
+}
+
+define void @baz() local_unnamed_addr !dbg !22 {
+  %1 = tail call i32 @rand(), !dbg !25
+  store i32 %1, i32* @gFoo, align 4, !dbg !26
+  %2 = tail call i32 @rand(), !dbg !27
+  store i32 %2, i32* @gBar, align 4, !dbg !28
+  ret void, !dbg !29
+}
+
+declare i32 @rand() local_unnamed_addr
+
+attributes #0 = { norecurse nounwind readonly }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!9, !10, !11, !12}
+!llvm.ident = !{!13}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "gBar", scope: !2, file: !3, line: 4, type: !8, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 7.0.0 (trunk 332246)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5)
+!3 = !DIFile(filename: "foo.c", directory: "/data/work/lto/roref/test")
+!4 = !{}
+!5 = !{!0, !6}
+!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression())
+!7 = distinct !DIGlobalVariable(name: "gFoo", scope: !2, file: !3, line: 3, type: !8, isLocal: true, isDefinition: true)
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!9 = !{i32 2, !"Dwarf Version", i32 4}
+!10 = !{i32 2, !"Debug Info Version", i32 3}
+!11 = !{i32 1, !"wchar_size", i32 4}
+!12 = !{i32 7, !"PIC Level", i32 2}
+!13 = !{!"clang version 7.0.0 (trunk 332246)"}
+!14 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 6, type: !15, isLocal: false, isDefinition: true, scopeLine: 6, isOptimized: true, unit: !2, retainedNodes: !4)
+!15 = !DISubroutineType(types: !16)
+!16 = !{!8}
+!17 = !DILocation(line: 7, column: 10, scope: !14)
+!18 = !DILocation(line: 7, column: 3, scope: !14)
+!19 = distinct !DISubprogram(name: "bar", scope: !3, file: !3, line: 10, type: !15, isLocal: false, isDefinition: true, scopeLine: 10, isOptimized: true, unit: !2, retainedNodes: !4)
+!20 = !DILocation(line: 11, column: 10, scope: !19)
+!21 = !DILocation(line: 11, column: 3, scope: !19)
+!22 = distinct !DISubprogram(name: "baz", scope: !3, file: !3, line: 14, type: !23, isLocal: false, isDefinition: true, scopeLine: 14, isOptimized: true, unit: !2, retainedNodes: !4)
+!23 = !DISubroutineType(types: !24)
+!24 = !{null}
+!25 = !DILocation(line: 15, column: 10, scope: !22)
+!26 = !DILocation(line: 15, column: 8, scope: !22)
+!27 = !DILocation(line: 16, column: 10, scope: !22)
+!28 = !DILocation(line: 16, column: 8, scope: !22)
+!29 = !DILocation(line: 17, column: 1, scope: !22)

Modified: llvm/trunk/test/ThinLTO/X86/dot-dumper.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/dot-dumper.ll?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/dot-dumper.ll (original)
+++ llvm/trunk/test/ThinLTO/X86/dot-dumper.ll Thu Nov 15 23:08:00 2018
@@ -20,7 +20,7 @@
 ; STRUCTURE-DAG:      subgraph cluster_1
 ; STRUCTURE:          // Cross-module edges:
 ; STRUCTURE-DAG:      M0_{{[0-9]+}} -> M1_{{[0-9]+}} // call
-; STRUCTURE-DAG:      M0_{{[0-9]+}} -> M1_{{[0-9]+}} [{{.*}}]; // ref
+; STRUCTURE-DAG:      M0_{{[0-9]+}} -> M1_{{[0-9]+}} [{{.*}}]; // const-ref
 ; STRUCTURE-NEXT:   }
 
 ; CLUSTER0:         // Module: {{.*}}1.bc
@@ -33,13 +33,13 @@
 
 ; CLUSTER1:         // Module: {{.*}}2.bc
 ; CLUSTER1-NEXT:    subgraph cluster_1 {
-; CLUSTER1-DAG:       M1_[[A:[0-9]+]] [{{.*}}A|extern{{.*}}]; // variable
+; CLUSTER1-DAG:       M1_[[A:[0-9]+]] [{{.*}}A|extern{{.*}}]; // variable, immutable
 ; CLUSTER1-DAG:       M1_[[FOO:[0-9]+]] [{{.*}}foo|extern{{.*}} ffl: 00001{{.*}}]; // function
-; CLUSTER1-DAG:       M1_[[B:[0-9]+]] [{{.*}}B|extern{{.*}}]; // variable
+; CLUSTER1-DAG:       M1_[[B:[0-9]+]] [{{.*}}B|extern{{.*}}]; // variable, immutable
 ; CLUSTER1-DAG:       M1_[[BAR:[0-9]+]] [{{.*}}bar|extern{{.*}}]; // function, dead
 ; CLUSTER1-NEXT:      // Edges:
-; CLUSTER1-DAG:       M1_[[FOO]] -> M1_[[B]] [{{.*}}]; // ref
-; CLUSTER1-DAG:       M1_[[FOO]] -> M1_[[A]] [{{.*}}]; // ref
+; CLUSTER1-DAG:       M1_[[FOO]] -> M1_[[B]] [{{.*}}]; // const-ref
+; CLUSTER1-DAG:       M1_[[FOO]] -> M1_[[A]] [{{.*}}]; // const-ref
 ; CLUSTER1-DAG:     }
 
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"

Modified: llvm/trunk/test/ThinLTO/X86/globals-import-const-fold.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/globals-import-const-fold.ll?rev=347033&r1=347032&r2=347033&view=diff
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/globals-import-const-fold.ll (original)
+++ llvm/trunk/test/ThinLTO/X86/globals-import-const-fold.ll Thu Nov 15 23:08:00 2018
@@ -2,12 +2,12 @@
 ; RUN: opt -module-summary %p/Inputs/globals-import-cf-baz.ll -o %t2.bc
 ; RUN: llvm-lto -thinlto-action=thinlink %t1.bc %t2.bc -o %t3.index.bc
 
-; RUN: llvm-lto -thinlto-action=import %t1.bc %t2.bc -thinlto-index=%t3.index.bc
+; RUN: llvm-lto -thinlto-action=import -exported-symbol=main %t1.bc -thinlto-index=%t3.index.bc
 ; RUN: llvm-dis %t1.bc.thinlto.imported.bc -o - | FileCheck --check-prefix=IMPORT %s
 ; RUN: llvm-lto -thinlto-action=optimize %t1.bc.thinlto.imported.bc -o %t1.bc.thinlto.opt.bc
 ; RUN: llvm-dis %t1.bc.thinlto.opt.bc -o - | FileCheck --check-prefix=OPTIMIZE %s
 
-; IMPORT: @baz = available_externally local_unnamed_addr constant i32 10
+; IMPORT: @baz = internal local_unnamed_addr constant i32 10
 
 ; OPTIMIZE:       define i32 @main()
 ; OPTIMIZE-NEXT:    ret i32 10

Added: llvm/trunk/test/ThinLTO/X86/index-const-prop-O0.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/index-const-prop-O0.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/index-const-prop-O0.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/index-const-prop-O0.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,18 @@
+; RUN: opt -module-summary %s -o %t1.bc
+; RUN: opt -module-summary %p/Inputs/index-const-prop-define-g.ll -o %t2.bc
+; RUN: llvm-lto2 run -O0 -save-temps %t2.bc -r=%t2.bc,g,pl %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,g, -o %t3
+; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s
+
+; With -O0 import is disabled so we must not internalize
+; read-only globals
+; CHECK: @g = dso_local global i32 42
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g = external global i32
+
+define i32 @main() {
+  %v = load i32, i32* @g
+  ret i32 %v
+}

Added: llvm/trunk/test/ThinLTO/X86/index-const-prop-alias.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/index-const-prop-alias.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/index-const-prop-alias.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/index-const-prop-alias.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,42 @@
+; RUN: opt -module-summary %s -o %t1.bc
+; RUN: opt -module-summary %p/Inputs/index-const-prop-alias.ll -o %t2.bc
+; RUN: llvm-lto2 run %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,ret_ptr,pl -r=%t1.bc,g.alias,l -r=%t1.bc,g,l \
+; RUN:               %t2.bc -r=%t2.bc,g,pl -r=%t2.bc,g.alias,pl -save-temps -o %t3
+; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT
+; RUN: llvm-dis %t3.1.5.precodegen.bc -o - | FileCheck %s --check-prefix=CODEGEN
+
+; When ret_ptr is preserved we return pointer to alias, so we can't internalize aliasee
+; RUN: llvm-lto2 run %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,ret_ptr,plx -r=%t1.bc,g.alias,l -r=%t1.bc,g,l \
+; RUN:               %t2.bc -r=%t2.bc,g,pl -r=%t2.bc,g.alias,pl -save-temps -o %t4
+; RUN: llvm-dis %t4.1.3.import.bc -o - | FileCheck %s --check-prefix=PRESERVED
+
+; When g.alias is preserved we can't internalize aliasee either
+; RUN: llvm-lto2 run %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,ret_ptr,pl -r=%t1.bc,g.alias,l -r=%t1.bc,g,l \
+; RUN:               %t2.bc -r=%t2.bc,g,pl -r=%t2.bc,g.alias,plx -save-temps -o %t5
+; RUN: llvm-dis %t5.1.3.import.bc -o - | FileCheck %s --check-prefix=PRESERVED
+
+; We currently don't support importing aliases
+; IMPORT:       @g.alias = external dso_local global i32
+; IMPORT-NEXT:  @g = internal global i32 42, align 4 #0
+; IMPORT:  attributes #0 = { "thinlto-internalize" }
+
+; CODEGEN:      define dso_local i32 @main
+; CODEGEN-NEXT:    ret i32 42
+
+; PRESERVED:      @g.alias = external dso_local global i32
+; PRESERVED-NEXT: @g = available_externally dso_local global i32 42, align 4
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g.alias = external global i32
+ at g = external global i32
+
+define i32 @main() {
+  %v = load i32, i32* @g
+  ret i32 %v
+}
+
+define i32* @ret_ptr() {
+  ret i32* @g.alias
+}

Added: llvm/trunk/test/ThinLTO/X86/index-const-prop-cache.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/index-const-prop-cache.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/index-const-prop-cache.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/index-const-prop-cache.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,41 @@
+; Check that we correctly handle 'ReadOnly' attribute when computing cache key
+; RUN: opt -module-summary -module-hash %s -o %t1.bc
+; RUN: opt -module-summary -module-hash %p/Inputs/index-const-prop-cache-foo.ll -o %t2.bc
+; RUN: opt -module-summary -module-hash %p/Inputs/index-const-prop-cache-test1.ll -o %t3.bc
+; RUN: opt -module-summary -module-hash %p/Inputs/index-const-prop-cache-test2.ll -o %t4.bc
+; RUN: rm -Rf %t.cache && mkdir %t.cache
+
+; Here @gFoo variable is writeable
+; RUN: llvm-lto -thinlto-action=run %t1.bc %t4.bc %t2.bc \
+; RUN:    -exported-symbol=main -exported-symbol=test -thinlto-cache-dir=%t.cache
+; RUN: ls %t.cache/llvmcache-* | count 3
+
+; Now gFoo is read-only and all modules should get different cache keys.
+; RUN: llvm-lto -thinlto-action=run %t1.bc %t3.bc %t2.bc \
+; RUN:    -exported-symbol=main -exported-symbol=test -thinlto-cache-dir=%t.cache
+; RUN: ls %t.cache/llvmcache-* | count 6
+
+; Do the same but with llvm-lto2
+; RUN: rm -Rf %t.cache && mkdir %t.cache
+; RUN: llvm-lto2 run  %t1.bc %t4.bc %t2.bc -cache-dir=%t.cache -o %t5 \
+; RUN:  -r=%t1.bc,main,plx -r=%t1.bc,foo,l \
+; RUN:  -r=%t4.bc,test,plx -r=%t4.bc,foo,l -r=%t4.bc,bar,l \
+; RUN:  -r=%t2.bc,foo,pl -r=%t2.bc,bar,pl -r=%t2.bc,rand,
+; RUN: ls %t.cache/llvmcache-* | count 3
+
+; RUN: llvm-lto2 run %t1.bc %t3.bc %t2.bc -cache-dir %t.cache -o %t6 \
+; RUN:  -r=%t1.bc,main,plx -r=%t1.bc,foo,l \
+; RUN:  -r=%t3.bc,test,plx -r=%t3.bc,foo,l \
+; RUN:  -r=%t2.bc,foo,pl -r=%t2.bc,bar,pl -r=%t2.bc,rand,
+; RUN: ls %t.cache/llvmcache-* | count 6
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: nounwind ssp uwtable
+define i32 @main() local_unnamed_addr {
+  %1 = tail call i32 (...) @foo()
+  ret i32 %1
+}
+
+declare i32 @foo(...) local_unnamed_addr

Added: llvm/trunk/test/ThinLTO/X86/index-const-prop-comdat.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/index-const-prop-comdat.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/index-const-prop-comdat.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/index-const-prop-comdat.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,17 @@
+; RUN: opt -module-summary %s -o %t1.bc
+; RUN: opt -module-summary %p/Inputs/index-const-prop-comdat.ll -o %t2.bc
+; RUN: llvm-lto2 run -save-temps %t2.bc -r=%t2.bc,g,pl %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,g, -o %t3
+; RUN: llvm-dis %t3.2.3.import.bc -o - | FileCheck %s
+
+; Comdats are not internalized even if they are read only.
+; CHECK: @g = available_externally dso_local global i32 42 
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g = external global i32
+
+define i32 @main() {
+  %v = load i32, i32* @g
+  ret i32 %v
+}

Added: llvm/trunk/test/ThinLTO/X86/index-const-prop-dead.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/index-const-prop-dead.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/index-const-prop-dead.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/index-const-prop-dead.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,26 @@
+; RUN: opt -module-summary %s -o %t1.bc
+; RUN: opt -module-summary %p/Inputs/index-const-prop-define-g.ll -o %t2.bc
+; RUN: llvm-lto2 run -save-temps %t2.bc -r=%t2.bc,g,pl \
+; RUN:               %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,foo,pl -r=%t1.bc,g, -o %t3
+; RUN: llvm-dis %t3.2.3.import.bc -o - | FileCheck %s
+
+; Dead globals are converted to declarations by ThinLTO in dropDeadSymbols
+; If we try to internalize such we'll get a broken module. 
+; CHECK: @g = external dso_local global i32
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g = external global i32
+
+; We need at least one live symbol to enable dead stripping
+; Otherwise ModuleSummaryIndex::isGlobalValueLive will always
+; return true.
+define i32 @main() {
+  ret i32 42
+}
+
+define i32 @foo() {
+  %v = load i32, i32* @g
+  ret i32 %v
+}

Added: llvm/trunk/test/ThinLTO/X86/index-const-prop-full-lto.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/index-const-prop-full-lto.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/index-const-prop-full-lto.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/index-const-prop-full-lto.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,24 @@
+; RUN: opt -module-summary %s -o %t1.bc
+; RUN: opt -module-summary %p/Inputs/index-const-prop-define-g.ll -o %t2.bc
+; RUN: opt -module-summary %p/Inputs/index-const-prop-full-lto.ll -o %t3.bc
+; RUN: llvm-lto2 run -save-temps %t2.bc -r=%t2.bc,g,pl \
+; RUN:                 %t1.bc -r=%t1.bc,foo,l -r=%t1.bc,main,plx -r=%t1.bc,g, \
+; RUN:                 %t3.bc -r=%t3.bc,foo,pl -r=%t3.bc,g, -o %t4
+; RUN: llvm-dis %t4.2.3.import.bc -o - | FileCheck %s
+
+; All references from functions in full LTO module are not constant.
+; We cannot internalize @g
+; CHECK: @g = available_externally dso_local global i32 42
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare i32 @foo()
+ at g = external global i32
+
+define i32 @main() {
+  %v = call i32 @foo()
+  %v2 = load i32, i32* @g
+  %v3 = add i32 %v, %v2
+  ret i32 %v3
+}

Added: llvm/trunk/test/ThinLTO/X86/index-const-prop-gvref.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/index-const-prop-gvref.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/index-const-prop-gvref.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/index-const-prop-gvref.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,27 @@
+; RUN: opt -module-summary %s -o %t1.bc
+; RUN: opt -module-summary %p/Inputs/index-const-prop-gvref.ll -o %t2.bc
+; RUN: llvm-lto2 run -save-temps %t2.bc -r=%t2.bc,b,pl -r=%t2.bc,a,pl \
+; RUN:               %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,a, -r=%t1.bc,b, -o %t3
+; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=SRC
+; RUN: llvm-dis %t3.2.3.import.bc -o - | FileCheck %s --check-prefix=DEST
+
+; No variable in the source module should have been internalized
+; SRC:      @b = dso_local global i32* @a
+; SRC-NEXT: @a = dso_local global i32 42
+
+; We can't internalize globals referenced by other live globals
+; DEST:      @b = external dso_local global i32*
+; DEST-NEXT: @a = available_externally dso_local global i32 42, align 4
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at a = external global i32
+ at b = external global i32*
+
+define i32 @main() {
+  %p = load i32*, i32** @b, align 8  
+  store i32 33, i32* %p, align 4
+  %v = load i32, i32* @a, align 4
+  ret i32 %v
+}

Added: llvm/trunk/test/ThinLTO/X86/index-const-prop-ldst.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/index-const-prop-ldst.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/index-const-prop-ldst.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/index-const-prop-ldst.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,21 @@
+; RUN: opt -module-summary %s -o %t1.bc
+; RUN: opt -module-summary %p/Inputs/index-const-prop-define-g.ll -o %t2.bc
+; RUN: llvm-lto2 run -save-temps %t2.bc -r=%t2.bc,g,pl %t1.bc -r=%t1.bc,main,plx -r=%t1.bc,g, -o %t3
+; RUN: llvm-dis %t3.2.3.import.bc -o - | FileCheck %s
+
+; The 'store' instruction in @main should prevent internalization
+; even when there is 'load' instruction before it.
+; CHECK: @g = available_externally dso_local global i32 42
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+ at g = external global i32
+
+define i32 @main() {
+  %v = load i32, i32* @g
+  %q = add i32 %v, 1
+  store i32 %q, i32* @g
+  
+  ret i32 %v
+}

Added: llvm/trunk/test/ThinLTO/X86/index-const-prop-linkage.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/index-const-prop-linkage.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/index-const-prop-linkage.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/index-const-prop-linkage.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,27 @@
+; RUN: opt -module-summary %s -o %t1.bc
+; RUN: opt -module-summary %p/Inputs/index-const-prop-linkage.ll -o %t2.bc
+; RUN: llvm-lto2 run -save-temps %t2.bc -r=%t2.bc,foo,pl -r=%t2.bc,g1,pl -r=%t2.bc,g2,pl -r=%t2.bc,g3, \
+; RUN:                           %t1.bc -r=%t1.bc,foo, -r=%t1.bc,main,plx -r=%t1.bc,g2,  -o %t3
+; RUN: llvm-dis %t3.2.3.import.bc -o - | FileCheck %s
+
+; Check that we never internalize anything with:
+; - appending linkage
+; - common linkage
+; - available_externally linkage
+; - reference from @llvm.used
+; CHECK:      @llvm.used = appending global [1 x i32*] [i32* @g2]
+; CHECK-NEXT: @g1 = external dso_local global i32, align 4
+; CHECK-NEXT: @g2 = available_externally dso_local global i32 42, align 4
+; CHECK-NEXT: @g3 = available_externally global i32 42, align 4
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare i32 @foo()
+ at g2 = external global i32
+ at llvm.used = appending global [1 x i32*] [i32* @g2]
+
+define i32 @main() {
+  %v = call i32 @foo()
+  ret i32 %v
+}

Added: llvm/trunk/test/ThinLTO/X86/index-const-prop.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/index-const-prop.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/index-const-prop.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/index-const-prop.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,40 @@
+; Check constant propagation in thinlto combined summary. This allows us to do 2 things:
+;  1. Internalize global definition which is not used externally if all accesses to it are read-only
+;  2. Make a local copy of internal definition if all accesses to it are readonly. This allows constant
+;     folding it during optimziation phase.
+
+; RUN: opt -module-summary %s -o %t1.bc
+; RUN: opt -module-summary %p/Inputs/index-const-prop.ll -o %t2.bc
+; RUN: llvm-lto -thinlto-action=thinlink -o %t3.index.bc %t1.bc %t2.bc
+; RUN: llvm-lto -thinlto-action=import -exported-symbol=main  %t1.bc -thinlto-index=%t3.index.bc -o %t1.imported.bc
+; RUN: llvm-dis %t1.imported.bc -o - | FileCheck %s --check-prefix=IMPORT
+; RUN: llvm-lto -thinlto-action=optimize %t1.imported.bc -o - | llvm-dis - -o - | FileCheck %s --check-prefix=OPTIMIZE
+
+; Check that we don't internalize gBar when it is exported
+; RUN: llvm-lto -thinlto-action=import -exported-symbol main -exported-symbol gBar  %t1.bc -thinlto-index=%t3.index.bc -o %t1.imported2.bc
+; RUN: llvm-dis %t1.imported2.bc -o - | FileCheck %s --check-prefix=IMPORT2
+
+; IMPORT: @gFoo.llvm.0 = internal unnamed_addr global i32 1, align 4, !dbg !0
+; IMPORT-NEXT: @gBar = internal local_unnamed_addr global i32 2, align 4, !dbg !5
+; IMPORT: !DICompileUnit({{.*}}, globals: !{{[0-9]+}})
+
+; OPTIMIZE:        define i32 @main
+; OPTIMIZE-NEXT:     ret i32 3
+
+; IMPORT2: @gBar = available_externally local_unnamed_addr global i32 2, align 4, !dbg !5
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-linux-gnu"
+
+ at gBar = external global i32
+
+define i32 @main() local_unnamed_addr {
+  %call = tail call i32 bitcast (i32 (...)* @foo to i32 ()*)()
+  %call1 = tail call i32 bitcast (i32 (...)* @bar to i32 ()*)()
+  %add = add nsw i32 %call1, %call
+  ret i32 %add
+}
+
+declare i32 @foo(...) local_unnamed_addr
+
+declare i32 @bar(...) local_unnamed_addr

Added: llvm/trunk/test/ThinLTO/X86/index-const-prop2.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/index-const-prop2.ll?rev=347033&view=auto
==============================================================================
--- llvm/trunk/test/ThinLTO/X86/index-const-prop2.ll (added)
+++ llvm/trunk/test/ThinLTO/X86/index-const-prop2.ll Thu Nov 15 23:08:00 2018
@@ -0,0 +1,59 @@
+; Check constant propagation in thinlto combined summary. This allows us to do 2 things:
+;  1. Internalize global definition which is not used externally if all accesses to it are read-only
+;  2. Make a local copy of internal definition if all accesses to it are readonly. This allows constant
+;     folding it during optimziation phase.
+; RUN: opt -module-summary %s -o %t1.bc
+; RUN: opt -module-summary %p/Inputs/index-const-prop.ll -o %t2.bc
+; RUN: llvm-lto2 run %t1.bc %t2.bc -save-temps \
+; RUN:  -r=%t2.bc,foo,pl \
+; RUN:  -r=%t2.bc,bar,pl \
+; RUN:  -r=%t2.bc,baz,pl \
+; RUN:  -r=%t2.bc,rand, \
+; RUN:  -r=%t2.bc,gBar,pl \
+; RUN:  -r=%t1.bc,main,plx \
+; RUN:  -r=%t1.bc,foo, \
+; RUN:  -r=%t1.bc,bar, \
+; RUN:  -r=%t1.bc,gBar, \
+; RUN:  -o %t3
+; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT
+; RUN: llvm-dis %t3.1.5.precodegen.bc -o - | FileCheck %s --check-prefix=CODEGEN
+
+; Now check that we won't internalize global (gBar) if it's externally referenced
+; RUN: llvm-lto2 run %t1.bc %t2.bc -save-temps \
+; RUN:  -r=%t2.bc,foo,pl \
+; RUN:  -r=%t2.bc,bar,pl \
+; RUN:  -r=%t2.bc,baz,pl \
+; RUN:  -r=%t2.bc,rand, \
+; RUN:  -r=%t2.bc,gBar,plx \
+; RUN:  -r=%t1.bc,main,plx \
+; RUN:  -r=%t1.bc,foo, \
+; RUN:  -r=%t1.bc,bar, \
+; RUN:  -r=%t1.bc,gBar, \
+; RUN:  -o %t3
+; RUN: llvm-dis %t3.1.3.import.bc -o - | FileCheck %s --check-prefix=IMPORT2
+
+; IMPORT:       @gFoo.llvm.0 = internal unnamed_addr global i32 1, align 4
+; IMPORT-NEXT:  @gBar = internal local_unnamed_addr global i32 2, align 4
+; IMPORT:       !DICompileUnit({{.*}}, globals: !{{[0-9]+}})
+
+; CODEGEN:        i32 @main()
+; CODEGEN-NEXT:     ret i32 3
+
+; IMPORT2: @gBar = available_externally dso_local local_unnamed_addr global i32 2, align 4
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-linux-gnu"
+
+; We should be able to link external definition of gBar to its declaration
+ at gBar = external global i32
+
+define i32 @main() local_unnamed_addr {
+  %call = tail call i32 bitcast (i32 (...)* @foo to i32 ()*)()
+  %call1 = tail call i32 bitcast (i32 (...)* @bar to i32 ()*)()
+  %add = add nsw i32 %call1, %call
+  ret i32 %add
+}
+
+declare i32 @foo(...) local_unnamed_addr
+
+declare i32 @bar(...) local_unnamed_addr




More information about the llvm-commits mailing list