[llvm] r364960 - [ThinLTO] Add summary entries for index-based WPD

Mikael Holmén via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 3 07:02:29 PDT 2019


Hi,

On 2019-07-03 15:36, Teresa Johnson wrote:
> Hi Mikael,
> 
> Thanks for looking into this! Not sure why I had const in the return 
> type to start with, let me go ahead and remove it once I sanity check 
> that everything builds/runs with the change (including a follow-on patch 
> that makes use of this interface).
> 

Sounds good!

Thanks,
Mikael

> Teresa
> 
> On Wed, Jul 3, 2019 at 12:39 AM Mikael Holmén 
> <mikael.holmen at ericsson.com <mailto:mikael.holmen at ericsson.com>> wrote:
> 
> 
> 
>     On 2019-07-03 08:39, Mikael Holmén via llvm-commits wrote:
>      > Hi Teresa,
>      >
>      > With this commit I start seeing warnings from gcc 7.4.0:
>      >
>      > In file included from ../include/llvm/ADT/STLExtras.h:19:0,
>      >                    from ../include/llvm/ADT/StringRef.h:12,
>      >                    from ../include/llvm/ADT/StringMap.h:16,
>      >                    from ../include/llvm/Support/Host.h:16,
>      >                    from ../include/llvm/ADT/Hashing.h:48,
>      >                    from ../include/llvm/ADT/ArrayRef.h:12,
>      >                    from ../include/llvm/ADT/APFloat.h:20,
>      >                    from ../lib/IR/AsmWriter.cpp:18:
>      > ../include/llvm/ADT/Optional.h: In instantiation of 'void
>      > llvm::optional_detail::OptionalStorage<T, <anonymous>
>      >::emplace(Args&&
>      > ...) [with Args = {const std::vector<llvm::TypeIdOffsetVtableInfo,
>      > std::allocator<llvm::TypeIdOffsetVtableInfo> >}; T = const
>      > std::vector<llvm::TypeIdOffsetVtableInfo>; bool <anonymous> =
>     false]':
>      > ../include/llvm/ADT/Optional.h:55:14:   required from
>      > 'llvm::optional_detail::OptionalStorage<T, <anonymous>
>      >   >::OptionalStorage(llvm::optional_detail::OptionalStorage<T,
>      > <anonymous> >&&) [with T = const
>      > std::vector<llvm::TypeIdOffsetVtableInfo>; bool <anonymous> = false]'
>      > ../include/llvm/ADT/Optional.h:228:3:   required from here
>      > ../include/llvm/ADT/Optional.h:89:12: error: cast from type 'const
>      > std::vector<llvm::TypeIdOffsetVtableInfo>*' to type 'void*' casts
>     away
>      > qualifiers [-Werror=cast-qual]
>      >        ::new ((void *)std::addressof(value))
>     T(std::forward<Args>(args)...);
>      >               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>      >
>      > Can you make any sense out of that with respect to your commit?
>      >
> 
>     It seems like it's the const in the return type in
> 
>         Optional<const TypeIdCompatibleVtableInfo>
>         getTypeIdCompatibleVtableSummary(StringRef TypeId) const {
>           auto I = TypeIdCompatibleVtableMap.find(TypeId);
>           if (I == TypeIdCompatibleVtableMap.end())
>             return None;
>           return I->second;
>         }
> 
>     that it complains that it casts away in
> 
>         template <class... Args> void emplace(Args &&... args) {
>           reset();
>           ::new ((void *)std::addressof(value))
>     T(std::forward<Args>(args)...);
>           hasVal = true;
>         }
> 
>     The warning goes away if I remove that const, but I've no idea what the
>     proper solution is.
> 
>     /Mikael
> 
> 
>      > Thanks,
>      > Mikael
>      >
>      > On 2019-07-02 21:38, Teresa Johnson via llvm-commits wrote:
>      >> Author: tejohnson
>      >> Date: Tue Jul  2 12:38:02 2019
>      >> New Revision: 364960
>      >>
>      >> URL: http://llvm.org/viewvc/llvm-project?rev=364960&view=rev
>      >> Log:
>      >> [ThinLTO] Add summary entries for index-based WPD
>      >>
>      >> Summary:
>      >> If LTOUnit splitting is disabled, the module summary analysis
>     computes
>      >> the summary information necessary to perform single implementation
>      >> devirtualization during the thin link with the index and no IR. The
>      >> information collected from the regular LTO IR in the current
>     hybrid WPD
>      >> algorithm is summarized, including:
>      >> 1) For vtable definitions, record the function pointers and
>     their offset
>      >> within the vtable initializer (subsumes the information
>     collected from
>      >> IR by tryFindVirtualCallTargets).
>      >> 2) A record for each type metadata summarizing the vtable
>     definitions
>      >> decorated with that metadata (subsumes the TypeIdentiferMap
>     collected
>      >> from IR).
>      >>
>      >> Also added are the necessary bitcode records, and the corresponding
>      >> assembly support.
>      >>
>      >> The follow-on index-based WPD patch is D55153.
>      >>
>      >> Depends on D53890.
>      >>
>      >> Reviewers: pcc
>      >>
>      >> Subscribers: mehdi_amini, Prazek, inglorion, eraman, steven_wu,
>     dexonsmith, arphaman, llvm-commits
>      >>
>      >> Differential Revision: https://reviews.llvm.org/D54815
>      >>
>      >> Added:
>      >>       llvm/trunk/test/Assembler/thinlto-vtable-summary.ll
>      >>       llvm/trunk/test/ThinLTO/X86/devirt.ll
>      >> Modified:
>      >>       llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h
>      >>       llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h
>      >>       llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp
>      >>       llvm/trunk/lib/AsmParser/LLLexer.cpp
>      >>       llvm/trunk/lib/AsmParser/LLParser.cpp
>      >>       llvm/trunk/lib/AsmParser/LLParser.h
>      >>       llvm/trunk/lib/AsmParser/LLToken.h
>      >>       llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
>      >>       llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
>      >>       llvm/trunk/lib/IR/AsmWriter.cpp
>      >>       llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
>      >>       llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
>      >>
>      >> Modified: llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h
>      >> URL:
>     http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h?rev=364960&r1=364959&r2=364960&view=diff
>      >>
>     ==============================================================================
>      >> --- llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h (original)
>      >> +++ llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h Tue Jul  2
>     12:38:02 2019
>      >> @@ -263,10 +263,31 @@ enum GlobalValueSummarySymtabCodes {
>      >>      // Index-wide flags
>      >>      FS_FLAGS = 20,
>      >>      // Maps type identifier to summary information for that
>     type identifier.
>      >> +  // Produced by the thin link (only lives in combined index).
>      >>      // TYPE_ID: [typeid, kind, bitwidth, align, size, bitmask,
>     inlinebits,
>      >>      //           n x (typeid, kind, name, numrba,
>      >>      //                numrba x (numarg, numarg x arg, kind,
>     info, byte, bit))]
>      >>      FS_TYPE_ID = 21,
>      >> +  // For background see overview at
>     https://llvm.org/docs/TypeMetadata.html.
>      >> +  // The type metadata includes both the type identifier and
>     the offset of
>      >> +  // the address point of the type (the address held by objects
>     of that type
>      >> +  // which may not be the beginning of the virtual table).
>     Vtable definitions
>      >> +  // are decorated with type metadata for the types they are
>     compatible with.
>      >> +  //
>      >> +  // Maps type identifier to summary information for that type
>     identifier
>      >> +  // computed from type metadata: the valueid of each vtable
>     definition
>      >> +  // decorated with a type metadata for that identifier, and
>     the offset from
>      >> +  // the corresponding type metadata.
>      >> +  // Exists in the per-module summary to provide information to
>     thin link
>      >> +  // for index-based whole program devirtualization.
>      >> +  // TYPE_ID_METADATA: [typeid, n x (valueid, offset)]
>      >> +  FS_TYPE_ID_METADATA = 22,
>      >> +  // Summarizes vtable definition for use in index-based whole
>     program
>      >> +  // devirtualization during the thin link.
>      >> +  // PERMODULE_VTABLE_GLOBALVAR_INIT_REFS: [valueid, flags,
>     varflags,
>      >> +  //                                        numrefs, numrefs x
>     valueid,
>      >> +  //                                        n x (valueid, offset)]
>      >> +  FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS = 23,
>      >>    };
>      >>
>      >>    enum MetadataCodes {
>      >>
>      >> Modified: llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h
>      >> URL:
>     http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h?rev=364960&r1=364959&r2=364960&view=diff
>      >>
>     ==============================================================================
>      >> --- llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h (original)
>      >> +++ llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h Tue Jul  2
>     12:38:02 2019
>      >> @@ -698,6 +698,18 @@ template <> struct DenseMapInfo<Function
>      >>      }
>      >>    };
>      >>
>      >> +/// The ValueInfo and offset for a function within a vtable
>     definition
>      >> +/// initializer array.
>      >> +struct VirtFuncOffset {
>      >> +  VirtFuncOffset(ValueInfo VI, uint64_t Offset)
>      >> +      : FuncVI(VI), VTableOffset(Offset) {}
>      >> +
>      >> +  ValueInfo FuncVI;
>      >> +  uint64_t VTableOffset;
>      >> +};
>      >> +/// List of functions referenced by a particular vtable definition.
>      >> +using VTableFuncList = std::vector<VirtFuncOffset>;
>      >> +
>      >>    /// Global variable summary information to aid decisions and
>      >>    /// implementation of importing.
>      >>    ///
>      >> @@ -705,6 +717,11 @@ template <> struct DenseMapInfo<Function
>      >>    /// modified during the program run or not. This affects ThinLTO
>      >>    /// internalization
>      >>    class GlobalVarSummary : public GlobalValueSummary {
>      >> +private:
>      >> +  /// For vtable definitions this holds the list of functions and
>      >> +  /// their corresponding offsets within the initializer array.
>      >> +  std::unique_ptr<VTableFuncList> VTableFuncs;
>      >> +
>      >>    public:
>      >>      struct GVarFlags {
>      >>        GVarFlags(bool ReadOnly = false) : ReadOnly(ReadOnly) {}
>      >> @@ -725,6 +742,17 @@ public:
>      >>      GVarFlags varflags() const { return VarFlags; }
>      >>      void setReadOnly(bool RO) { VarFlags.ReadOnly = RO; }
>      >>      bool isReadOnly() const { return VarFlags.ReadOnly; }
>      >> +
>      >> +  void setVTableFuncs(VTableFuncList Funcs) {
>      >> +    assert(!VTableFuncs);
>      >> +    VTableFuncs =
>     llvm::make_unique<VTableFuncList>(std::move(Funcs));
>      >> +  }
>      >> +
>      >> +  ArrayRef<VirtFuncOffset> vTableFuncs() const {
>      >> +    if (VTableFuncs)
>      >> +      return *VTableFuncs;
>      >> +    return {};
>      >> +  }
>      >>    };
>      >>
>      >>    struct TypeTestResolution {
>      >> @@ -823,6 +851,29 @@ using GVSummaryMapTy = DenseMap<GlobalVa
>      >>    using TypeIdSummaryMapTy =
>      >>        std::multimap<GlobalValue::GUID, std::pair<std::string,
>     TypeIdSummary>>;
>      >>
>      >> +/// The following data structures summarize type metadata
>     information.
>      >> +/// For type metadata overview see
>     https://llvm.org/docs/TypeMetadata.html.
>      >> +/// Each type metadata includes both the type identifier and
>     the offset of
>      >> +/// the address point of the type (the address held by objects
>     of that type
>      >> +/// which may not be the beginning of the virtual table).
>     Vtable definitions
>      >> +/// are decorated with type metadata for the types they are
>     compatible with.
>      >> +///
>      >> +/// Holds information about vtable definitions decorated with
>     type metadata:
>      >> +/// the vtable definition value and its address point offset in
>     a type
>      >> +/// identifier metadata it is decorated (compatible) with.
>      >> +struct TypeIdOffsetVtableInfo {
>      >> +  TypeIdOffsetVtableInfo(uint64_t Offset, ValueInfo VI)
>      >> +      : AddressPointOffset(Offset), VTableVI(VI) {}
>      >> +
>      >> +  uint64_t AddressPointOffset;
>      >> +  ValueInfo VTableVI;
>      >> +};
>      >> +/// List of vtable definitions decorated by a particular type
>     identifier,
>      >> +/// and their corresponding offsets in that type identifier's
>     metadata.
>      >> +/// Note that each type identifier may be compatible with
>     multiple vtables, due
>      >> +/// to inheritance, which is why this is a vector.
>      >> +using TypeIdCompatibleVtableInfo =
>     std::vector<TypeIdOffsetVtableInfo>;
>      >> +
>      >>    /// Class to hold module path string table and global value map,
>      >>    /// and encapsulate methods for operating on them.
>      >>    class ModuleSummaryIndex {
>      >> @@ -835,9 +886,15 @@ private:
>      >>      ModulePathStringTableTy ModulePathStringTable;
>      >>
>      >>      /// Mapping from type identifier GUIDs to type identifier
>     and its summary
>      >> -  /// information.
>      >> +  /// information. Produced by thin link.
>      >>      TypeIdSummaryMapTy TypeIdMap;
>      >>
>      >> +  /// Mapping from type identifier to information about vtables
>     decorated
>      >> +  /// with that type identifier's metadata. Produced by per
>     module summary
>      >> +  /// analysis and consumed by thin link. For more information,
>     see description
>      >> +  /// above where TypeIdCompatibleVtableInfo is defined.
>      >> +  std::map<std::string, TypeIdCompatibleVtableInfo>
>     TypeIdCompatibleVtableMap;
>      >> +
>      >>      /// Mapping from original ID to GUID. If original ID can
>     map to multiple
>      >>      /// GUIDs, it will be mapped to 0.
>      >>      std::map<GlobalValue::GUID, GlobalValue::GUID> OidGuidMap;
>      >> @@ -1201,6 +1258,29 @@ public:
>      >>        return nullptr;
>      >>      }
>      >>
>      >> +  const std::map<std::string, TypeIdCompatibleVtableInfo> &
>      >> +  typeIdCompatibleVtableMap() const {
>      >> +    return TypeIdCompatibleVtableMap;
>      >> +  }
>      >> +
>      >> +  /// Return an existing or new TypeIdCompatibleVtableMap entry
>     for \p TypeId.
>      >> +  /// This accessor can mutate the map and therefore should not
>     be used in
>      >> +  /// the ThinLTO backends.
>      >> +  TypeIdCompatibleVtableInfo &
>      >> +  getOrInsertTypeIdCompatibleVtableSummary(StringRef TypeId) {
>      >> +    return TypeIdCompatibleVtableMap[TypeId];
>      >> +  }
>      >> +
>      >> +  /// For the given \p TypeId, this returns the
>     TypeIdCompatibleVtableMap
>      >> +  /// entry if present in the summary map. This may be used
>     when importing.
>      >> +  Optional<const TypeIdCompatibleVtableInfo>
>      >> +  getTypeIdCompatibleVtableSummary(StringRef TypeId) const {
>      >> +    auto I = TypeIdCompatibleVtableMap.find(TypeId);
>      >> +    if (I == TypeIdCompatibleVtableMap.end())
>      >> +      return None;
>      >> +    return I->second;
>      >> +  }
>      >> +
>      >>      /// Collect for the given module the list of functions it
>     defines
>      >>      /// (GUID -> Summary).
>      >>      void collectDefinedFunctionsForModule(StringRef ModulePath,
>      >>
>      >> Modified: llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp
>      >> URL:
>     http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp?rev=364960&r1=364959&r2=364960&view=diff
>      >>
>     ==============================================================================
>      >> --- llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp (original)
>      >> +++ llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp Tue Jul  2
>     12:38:02 2019
>      >> @@ -411,9 +411,98 @@ static void computeFunctionSummary(Modul
>      >>      Index.addGlobalValueSummary(F, std::move(FuncSummary));
>      >>    }
>      >>
>      >> +/// Find function pointers referenced within the given vtable
>     initializer
>      >> +/// (or subset of an initializer) \p I. The starting offset of
>     \p I within
>      >> +/// the vtable initializer is \p StartingOffset. Any discovered
>     function
>      >> +/// pointers are added to \p VTableFuncs along with their
>     cumulative offset
>      >> +/// within the initializer.
>      >> +static void findFuncPointers(const Constant *I, uint64_t
>     StartingOffset,
>      >> +                             const Module &M,
>     ModuleSummaryIndex &Index,
>      >> +                             VTableFuncList &VTableFuncs) {
>      >> +  // First check if this is a function pointer.
>      >> +  if (I->getType()->isPointerTy()) {
>      >> +    auto Fn = dyn_cast<Function>(I->stripPointerCasts());
>      >> +    // We can disregard __cxa_pure_virtual as a possible call
>     target, as
>      >> +    // calls to pure virtuals are UB.
>      >> +    if (Fn && Fn->getName() != "__cxa_pure_virtual")
>      >> +      VTableFuncs.push_back({Index.getOrInsertValueInfo(Fn),
>     StartingOffset});
>      >> +    return;
>      >> +  }
>      >> +
>      >> +  // Walk through the elements in the constant struct or array
>     and recursively
>      >> +  // look for virtual function pointers.
>      >> +  const DataLayout &DL = M.getDataLayout();
>      >> +  if (auto *C = dyn_cast<ConstantStruct>(I)) {
>      >> +    StructType *STy = dyn_cast<StructType>(C->getType());
>      >> +    assert(STy);
>      >> +    const StructLayout *SL = DL.getStructLayout(C->getType());
>      >> +
>      >> +    for (StructType::element_iterator EB =
>     STy->element_begin(), EI = EB,
>      >> +                                      EE = STy->element_end();
>      >> +         EI != EE; ++EI) {
>      >> +      auto Offset = SL->getElementOffset(EI - EB);
>      >> +      unsigned Op = SL->getElementContainingOffset(Offset);
>      >> +      findFuncPointers(cast<Constant>(I->getOperand(Op)),
>      >> +                       StartingOffset + Offset, M, Index,
>     VTableFuncs);
>      >> +    }
>      >> +  } else if (auto *C = dyn_cast<ConstantArray>(I)) {
>      >> +    ArrayType *ATy = C->getType();
>      >> +    Type *EltTy = ATy->getElementType();
>      >> +    uint64_t EltSize = DL.getTypeAllocSize(EltTy);
>      >> +    for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {
>      >> +      findFuncPointers(cast<Constant>(I->getOperand(i)),
>      >> +                       StartingOffset + i * EltSize, M, Index,
>     VTableFuncs);
>      >> +    }
>      >> +  }
>      >> +}
>      >> +
>      >> +// Identify the function pointers referenced by vtable
>     definition \p V.
>      >> +static void computeVTableFuncs(ModuleSummaryIndex &Index,
>      >> +                               const GlobalVariable &V, const
>     Module &M,
>      >> +                               VTableFuncList &VTableFuncs) {
>      >> +  if (!V.isConstant())
>      >> +    return;
>      >> +
>      >> +  findFuncPointers(V.getInitializer(), /*StartingOffset=*/0, M,
>     Index,
>      >> +                   VTableFuncs);
>      >> +
>      >> +#ifndef NDEBUG
>      >> +  // Validate that the VTableFuncs list is ordered by offset.
>      >> +  uint64_t PrevOffset = 0;
>      >> +  for (auto &P : VTableFuncs) {
>      >> +    // The findVFuncPointers traversal should have encountered the
>      >> +    // functions in offset order. We need to use ">=" since
>     PrevOffset
>      >> +    // starts at 0.
>      >> +    assert(P.VTableOffset >= PrevOffset);
>      >> +    PrevOffset = P.VTableOffset;
>      >> +  }
>      >> +#endif
>      >> +}
>      >> +
>      >> +/// Record vtable definition \p V for each type metadata it
>     references.
>      >>    static void
>      >> -computeVariableSummary(ModuleSummaryIndex &Index, const
>     GlobalVariable &V,
>      >> -                       DenseSet<GlobalValue::GUID>
>     &CantBePromoted) {
>      >> +recordTypeIdCompatibleVtableReferences(ModuleSummaryIndex &Index,
>      >> +                                       const GlobalVariable &V,
>      >> +                                       SmallVectorImpl<MDNode
>     *> &Types) {
>      >> +  for (MDNode *Type : Types) {
>      >> +    auto TypeID = Type->getOperand(1).get();
>      >> +
>      >> +    uint64_t Offset =
>      >> +        cast<ConstantInt>(
>      >> +           
>     cast<ConstantAsMetadata>(Type->getOperand(0))->getValue())
>      >> +            ->getZExtValue();
>      >> +
>      >> +    if (auto *TypeId = dyn_cast<MDString>(TypeID))
>      >> +     
>     Index.getOrInsertTypeIdCompatibleVtableSummary(TypeId->getString())
>      >> +          .push_back({Offset, Index.getOrInsertValueInfo(&V)});
>      >> +  }
>      >> +}
>      >> +
>      >> +static void computeVariableSummary(ModuleSummaryIndex &Index,
>      >> +                                   const GlobalVariable &V,
>      >> +                                   DenseSet<GlobalValue::GUID>
>     &CantBePromoted,
>      >> +                                   const Module &M,
>      >> +                                   SmallVectorImpl<MDNode *>
>     &Types) {
>      >>      SetVector<ValueInfo> RefEdges;
>      >>      SmallPtrSet<const User *, 8> Visited;
>      >>      bool HasBlockAddress = findRefEdges(Index, &V, RefEdges,
>     Visited);
>      >> @@ -422,6 +511,21 @@ computeVariableSummary(ModuleSummaryInde
>      >>                                        /* Live = */ false,
>     V.isDSOLocal(),
>      >>                                        V.hasLinkOnceODRLinkage()
>     && V.hasGlobalUnnamedAddr());
>      >>
>      >> +  VTableFuncList VTableFuncs;
>      >> +  // If splitting is not enabled, then we compute the summary
>     information
>      >> +  // necessary for index-based whole program devirtualization.
>      >> +  if (!Index.enableSplitLTOUnit()) {
>      >> +    Types.clear();
>      >> +    V.getMetadata(LLVMContext::MD_type, Types);
>      >> +    if (!Types.empty()) {
>      >> +      // Identify the function pointers referenced by this
>     vtable definition.
>      >> +      computeVTableFuncs(Index, V, M, VTableFuncs);
>      >> +
>      >> +      // Record this vtable definition for each type metadata
>     it references.
>      >> +      recordTypeIdCompatibleVtableReferences(Index, V, Types);
>      >> +    }
>      >> +  }
>      >> +
>      >>      // Don't mark variables we won't be able to internalize as
>     read-only.
>      >>      GlobalVarSummary::GVarFlags VarFlags(
>      >>          !V.hasComdat() && !V.hasAppendingLinkage() &&
>     !V.isInterposable() &&
>      >> @@ -432,6 +536,8 @@ computeVariableSummary(ModuleSummaryInde
>      >>        CantBePromoted.insert(V.getGUID());
>      >>      if (HasBlockAddress)
>      >>        GVarSummary->setNotEligibleToImport();
>      >> +  if (!VTableFuncs.empty())
>      >> +    GVarSummary->setVTableFuncs(VTableFuncs);
>      >>      Index.addGlobalValueSummary(V, std::move(GVarSummary));
>      >>    }
>      >>
>      >> @@ -578,10 +684,11 @@ ModuleSummaryIndex llvm::buildModuleSumm
>      >>
>      >>      // Compute summaries for all variables defined in module,
>     and save in the
>      >>      // index.
>      >> +  SmallVector<MDNode *, 2> Types;
>      >>      for (const GlobalVariable &G : M.globals()) {
>      >>        if (G.isDeclaration())
>      >>          continue;
>      >> -    computeVariableSummary(Index, G, CantBePromoted);
>      >> +    computeVariableSummary(Index, G, CantBePromoted, M, Types);
>      >>      }
>      >>
>      >>      // Compute summaries for all aliases defined in module, and
>     save in the
>      >>
>      >> Modified: llvm/trunk/lib/AsmParser/LLLexer.cpp
>      >> URL:
>     http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLLexer.cpp?rev=364960&r1=364959&r2=364960&view=diff
>      >>
>     ==============================================================================
>      >> --- llvm/trunk/lib/AsmParser/LLLexer.cpp (original)
>      >> +++ llvm/trunk/lib/AsmParser/LLLexer.cpp Tue Jul  2 12:38:02 2019
>      >> @@ -752,6 +752,8 @@ lltok::Kind LLLexer::LexIdentifier() {
>      >>      KEYWORD(critical);
>      >>      KEYWORD(relbf);
>      >>      KEYWORD(variable);
>      >> +  KEYWORD(vTableFuncs);
>      >> +  KEYWORD(virtFunc);
>      >>      KEYWORD(aliasee);
>      >>      KEYWORD(refs);
>      >>      KEYWORD(typeIdInfo);
>      >> @@ -764,6 +766,7 @@ lltok::Kind LLLexer::LexIdentifier() {
>      >>      KEYWORD(offset);
>      >>      KEYWORD(args);
>      >>      KEYWORD(typeid);
>      >> +  KEYWORD(typeidCompatibleVTable);
>      >>      KEYWORD(summary);
>      >>      KEYWORD(typeTestRes);
>      >>      KEYWORD(kind);
>      >>
>      >> Modified: llvm/trunk/lib/AsmParser/LLParser.cpp
>      >> URL:
>     http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.cpp?rev=364960&r1=364959&r2=364960&view=diff
>      >>
>     ==============================================================================
>      >> --- llvm/trunk/lib/AsmParser/LLParser.cpp (original)
>      >> +++ llvm/trunk/lib/AsmParser/LLParser.cpp Tue Jul  2 12:38:02 2019
>      >> @@ -832,6 +832,9 @@ bool LLParser::ParseSummaryEntry() {
>      >>      case lltok::kw_typeid:
>      >>        result = ParseTypeIdEntry(SummaryID);
>      >>        break;
>      >> +  case lltok::kw_typeidCompatibleVTable:
>      >> +    result = ParseTypeIdCompatibleVtableEntry(SummaryID);
>      >> +    break;
>      >>      default:
>      >>        result = Error(Lex.getLoc(), "unexpected summary kind");
>      >>        break;
>      >> @@ -7486,6 +7489,92 @@ bool LLParser::ParseTypeIdSummary(TypeId
>      >>      return false;
>      >>    }
>      >>
>      >> +static ValueInfo EmptyVI =
>      >> +    ValueInfo(false, (GlobalValueSummaryMapTy::value_type *)-8);
>      >> +
>      >> +/// TypeIdCompatibleVtableEntry
>      >> +///   ::= 'typeidCompatibleVTable' ':' '(' 'name' ':'
>     STRINGCONSTANT ','
>      >> +///   TypeIdCompatibleVtableInfo
>      >> +///   ')'
>      >> +bool LLParser::ParseTypeIdCompatibleVtableEntry(unsigned ID) {
>      >> +  assert(Lex.getKind() == lltok::kw_typeidCompatibleVTable);
>      >> +  Lex.Lex();
>      >> +
>      >> +  std::string Name;
>      >> +  if (ParseToken(lltok::colon, "expected ':' here") ||
>      >> +      ParseToken(lltok::lparen, "expected '(' here") ||
>      >> +      ParseToken(lltok::kw_name, "expected 'name' here") ||
>      >> +      ParseToken(lltok::colon, "expected ':' here") ||
>      >> +      ParseStringConstant(Name))
>      >> +    return true;
>      >> +
>      >> +  TypeIdCompatibleVtableInfo &TI =
>      >> +      Index->getOrInsertTypeIdCompatibleVtableSummary(Name);
>      >> +  if (ParseToken(lltok::comma, "expected ',' here") ||
>      >> +      ParseToken(lltok::kw_summary, "expected 'summary' here") ||
>      >> +      ParseToken(lltok::colon, "expected ':' here") ||
>      >> +      ParseToken(lltok::lparen, "expected '(' here"))
>      >> +    return true;
>      >> +
>      >> +  IdToIndexMapType IdToIndexMap;
>      >> +  // Parse each call edge
>      >> +  do {
>      >> +    uint64_t Offset;
>      >> +    if (ParseToken(lltok::lparen, "expected '(' here") ||
>      >> +        ParseToken(lltok::kw_offset, "expected 'offset' here") ||
>      >> +        ParseToken(lltok::colon, "expected ':' here") ||
>     ParseUInt64(Offset) ||
>      >> +        ParseToken(lltok::comma, "expected ',' here"))
>      >> +      return true;
>      >> +
>      >> +    LocTy Loc = Lex.getLoc();
>      >> +    unsigned GVId;
>      >> +    ValueInfo VI;
>      >> +    if (ParseGVReference(VI, GVId))
>      >> +      return true;
>      >> +
>      >> +    // Keep track of the TypeIdCompatibleVtableInfo array index
>     needing a
>      >> +    // forward reference. We will save the location of the
>     ValueInfo needing an
>      >> +    // update, but can only do so once the std::vector is
>     finalized.
>      >> +    if (VI == EmptyVI)
>      >> +      IdToIndexMap[GVId].push_back(std::make_pair(TI.size(), Loc));
>      >> +    TI.push_back({Offset, VI});
>      >> +
>      >> +    if (ParseToken(lltok::rparen, "expected ')' in call"))
>      >> +      return true;
>      >> +  } while (EatIfPresent(lltok::comma));
>      >> +
>      >> +  // Now that the TI vector is finalized, it is safe to save
>     the locations
>      >> +  // of any forward GV references that need updating later.
>      >> +  for (auto I : IdToIndexMap) {
>      >> +    for (auto P : I.second) {
>      >> +      assert(TI[P.first].VTableVI == EmptyVI &&
>      >> +             "Forward referenced ValueInfo expected to be empty");
>      >> +      auto FwdRef = ForwardRefValueInfos.insert(std::make_pair(
>      >> +          I.first, std::vector<std::pair<ValueInfo *, LocTy>>()));
>      >> +      FwdRef.first->second.push_back(
>      >> +          std::make_pair(&TI[P.first].VTableVI, P.second));
>      >> +    }
>      >> +  }
>      >> +
>      >> +  if (ParseToken(lltok::rparen, "expected ')' here") ||
>      >> +      ParseToken(lltok::rparen, "expected ')' here"))
>      >> +    return true;
>      >> +
>      >> +  // Check if this ID was forward referenced, and if so, update the
>      >> +  // corresponding GUIDs.
>      >> +  auto FwdRefTIDs = ForwardRefTypeIds.find(ID);
>      >> +  if (FwdRefTIDs != ForwardRefTypeIds.end()) {
>      >> +    for (auto TIDRef : FwdRefTIDs->second) {
>      >> +      assert(!*TIDRef.first &&
>      >> +             "Forward referenced type id GUID expected to be 0");
>      >> +      *TIDRef.first = GlobalValue::getGUID(Name);
>      >> +    }
>      >> +    ForwardRefTypeIds.erase(FwdRefTIDs);
>      >> +  }
>      >> +
>      >> +  return false;
>      >> +}
>      >> +
>      >>    /// TypeTestResolution
>      >>    ///   ::= 'typeTestRes' ':' '(' 'kind' ':'
>      >>    ///         ( 'unsat' | 'byteArray' | 'inline' | 'single' |
>     'allOnes' ) ','
>      >> @@ -7994,6 +8083,7 @@ bool LLParser::ParseVariableSummary(std:
>      >>          /*Live=*/false, /*IsLocal=*/false, /*CanAutoHide=*/false);
>      >>      GlobalVarSummary::GVarFlags GVarFlags(/*ReadOnly*/ false);
>      >>      std::vector<ValueInfo> Refs;
>      >> +  VTableFuncList VTableFuncs;
>      >>      if (ParseToken(lltok::colon, "expected ':' here") ||
>      >>          ParseToken(lltok::lparen, "expected '(' here") ||
>      >>          ParseModuleReference(ModulePath) ||
>      >> @@ -8002,10 +8092,20 @@ bool LLParser::ParseVariableSummary(std:
>      >>          ParseGVarFlags(GVarFlags))
>      >>        return true;
>      >>
>      >> -  // Parse optional refs field
>      >> -  if (EatIfPresent(lltok::comma)) {
>      >> -    if (ParseOptionalRefs(Refs))
>      >> -      return true;
>      >> +  // Parse optional fields
>      >> +  while (EatIfPresent(lltok::comma)) {
>      >> +    switch (Lex.getKind()) {
>      >> +    case lltok::kw_vTableFuncs:
>      >> +      if (ParseOptionalVTableFuncs(VTableFuncs))
>      >> +        return true;
>      >> +      break;
>      >> +    case lltok::kw_refs:
>      >> +      if (ParseOptionalRefs(Refs))
>      >> +        return true;
>      >> +      break;
>      >> +    default:
>      >> +      return Error(Lex.getLoc(), "expected optional variable
>     summary field");
>      >> +    }
>      >>      }
>      >>
>      >>      if (ParseToken(lltok::rparen, "expected ')' here"))
>      >> @@ -8015,6 +8115,7 @@ bool LLParser::ParseVariableSummary(std:
>      >>          llvm::make_unique<GlobalVarSummary>(GVFlags, GVarFlags,
>     std::move(Refs));
>      >>
>      >>      GS->setModulePath(ModulePath);
>      >> +  GS->setVTableFuncs(std::move(VTableFuncs));
>      >>
>      >>      AddGlobalValueToIndex(Name, GUID,
>     (GlobalValue::LinkageTypes)GVFlags.Linkage,
>      >>                            ID, std::move(GS));
>      >> @@ -8235,6 +8336,67 @@ bool LLParser::ParseHotness(CalleeInfo::
>      >>      return false;
>      >>    }
>      >>
>      >> +/// OptionalVTableFuncs
>      >> +///   := 'vTableFuncs' ':' '(' VTableFunc [',' VTableFunc]* ')'
>      >> +/// VTableFunc ::= '(' 'virtFunc' ':' GVReference ',' 'offset'
>     ':' UInt64 ')'
>      >> +bool LLParser::ParseOptionalVTableFuncs(VTableFuncList
>     &VTableFuncs) {
>      >> +  assert(Lex.getKind() == lltok::kw_vTableFuncs);
>      >> +  Lex.Lex();
>      >> +
>      >> +  if (ParseToken(lltok::colon, "expected ':' in vTableFuncs") |
>      >> +      ParseToken(lltok::lparen, "expected '(' in vTableFuncs"))
>      >> +    return true;
>      >> +
>      >> +  IdToIndexMapType IdToIndexMap;
>      >> +  // Parse each virtual function pair
>      >> +  do {
>      >> +    ValueInfo VI;
>      >> +    if (ParseToken(lltok::lparen, "expected '(' in vTableFunc") ||
>      >> +        ParseToken(lltok::kw_virtFunc, "expected 'callee' in
>     vTableFunc") ||
>      >> +        ParseToken(lltok::colon, "expected ':'"))
>      >> +      return true;
>      >> +
>      >> +    LocTy Loc = Lex.getLoc();
>      >> +    unsigned GVId;
>      >> +    if (ParseGVReference(VI, GVId))
>      >> +      return true;
>      >> +
>      >> +    uint64_t Offset;
>      >> +    if (ParseToken(lltok::comma, "expected comma") ||
>      >> +        ParseToken(lltok::kw_offset, "expected offset") ||
>      >> +        ParseToken(lltok::colon, "expected ':'") ||
>     ParseUInt64(Offset))
>      >> +      return true;
>      >> +
>      >> +    // Keep track of the VTableFuncs array index needing a
>     forward reference.
>      >> +    // We will save the location of the ValueInfo needing an
>     update, but
>      >> +    // can only do so once the std::vector is finalized.
>      >> +    if (VI == EmptyVI)
>      >> +     
>     IdToIndexMap[GVId].push_back(std::make_pair(VTableFuncs.size(), Loc));
>      >> +    VTableFuncs.push_back({VI, Offset});
>      >> +
>      >> +    if (ParseToken(lltok::rparen, "expected ')' in vTableFunc"))
>      >> +      return true;
>      >> +  } while (EatIfPresent(lltok::comma));
>      >> +
>      >> +  // Now that the VTableFuncs vector is finalized, it is safe
>     to save the
>      >> +  // locations of any forward GV references that need updating
>     later.
>      >> +  for (auto I : IdToIndexMap) {
>      >> +    for (auto P : I.second) {
>      >> +      assert(VTableFuncs[P.first].FuncVI == EmptyVI &&
>      >> +             "Forward referenced ValueInfo expected to be empty");
>      >> +      auto FwdRef = ForwardRefValueInfos.insert(std::make_pair(
>      >> +          I.first, std::vector<std::pair<ValueInfo *, LocTy>>()));
>      >> +      FwdRef.first->second.push_back(
>      >> +          std::make_pair(&VTableFuncs[P.first].FuncVI, P.second));
>      >> +    }
>      >> +  }
>      >> +
>      >> +  if (ParseToken(lltok::rparen, "expected ')' in vTableFuncs"))
>      >> +    return true;
>      >> +
>      >> +  return false;
>      >> +}
>      >> +
>      >>    /// OptionalRefs
>      >>    ///   := 'refs' ':' '(' GVReference [',' GVReference]* ')'
>      >>    bool LLParser::ParseOptionalRefs(std::vector<ValueInfo> &Refs) {
>      >>
>      >> Modified: llvm/trunk/lib/AsmParser/LLParser.h
>      >> URL:
>     http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.h?rev=364960&r1=364959&r2=364960&view=diff
>      >>
>     ==============================================================================
>      >> --- llvm/trunk/lib/AsmParser/LLParser.h (original)
>      >> +++ llvm/trunk/lib/AsmParser/LLParser.h Tue Jul  2 12:38:02 2019
>      >> @@ -369,9 +369,11 @@ namespace llvm {
>      >>                             IdToIndexMapType &IdToIndexMap,
>     unsigned Index);
>      >>        bool ParseVFuncId(FunctionSummary::VFuncId &VFuncId,
>      >>                          IdToIndexMapType &IdToIndexMap,
>     unsigned Index);
>      >> +    bool ParseOptionalVTableFuncs(VTableFuncList &VTableFuncs);
>      >>        bool ParseOptionalRefs(std::vector<ValueInfo> &Refs);
>      >>        bool ParseTypeIdEntry(unsigned ID);
>      >>        bool ParseTypeIdSummary(TypeIdSummary &TIS);
>      >> +    bool ParseTypeIdCompatibleVtableEntry(unsigned ID);
>      >>        bool ParseTypeTestResolution(TypeTestResolution &TTRes);
>      >>        bool ParseOptionalWpdResolutions(
>      >>            std::map<uint64_t, WholeProgramDevirtResolution>
>     &WPDResMap);
>      >>
>      >> Modified: llvm/trunk/lib/AsmParser/LLToken.h
>      >> URL:
>     http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLToken.h?rev=364960&r1=364959&r2=364960&view=diff
>      >>
>     ==============================================================================
>      >> --- llvm/trunk/lib/AsmParser/LLToken.h (original)
>      >> +++ llvm/trunk/lib/AsmParser/LLToken.h Tue Jul  2 12:38:02 2019
>      >> @@ -383,6 +383,8 @@ enum Kind {
>      >>      kw_critical,
>      >>      kw_relbf,
>      >>      kw_variable,
>      >> +  kw_vTableFuncs,
>      >> +  kw_virtFunc,
>      >>      kw_aliasee,
>      >>      kw_refs,
>      >>      kw_typeIdInfo,
>      >> @@ -395,6 +397,7 @@ enum Kind {
>      >>      kw_offset,
>      >>      kw_args,
>      >>      kw_typeid,
>      >> +  kw_typeidCompatibleVTable,
>      >>      kw_summary,
>      >>      kw_typeTestRes,
>      >>      kw_kind,
>      >>
>      >> Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
>      >> URL:
>     http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=364960&r1=364959&r2=364960&view=diff
>      >>
>     ==============================================================================
>      >> --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)
>      >> +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Tue Jul  2
>     12:38:02 2019
>      >> @@ -828,6 +828,9 @@ private:
>      >>                                                        bool
>     HasRelBF);
>      >>      Error parseEntireSummary(unsigned ID);
>      >>      Error parseModuleStringTable();
>      >> +  void
>     parseTypeIdCompatibleVtableSummaryRecord(ArrayRef<uint64_t> Record);
>      >> +  void parseTypeIdCompatibleVtableInfo(ArrayRef<uint64_t>
>     Record, size_t &Slot,
>      >> +                                     
>       TypeIdCompatibleVtableInfo &TypeId);
>      >>
>      >>      std::pair<ValueInfo, GlobalValue::GUID>
>      >>      getValueInfoFromValueId(unsigned ValueId);
>      >> @@ -5657,6 +5660,27 @@ static void parseTypeIdSummaryRecord(Arr
>      >>        parseWholeProgramDevirtResolution(Record, Strtab, Slot,
>     TypeId);
>      >>    }
>      >>
>      >> +void
>     ModuleSummaryIndexBitcodeReader::parseTypeIdCompatibleVtableInfo(
>      >> +    ArrayRef<uint64_t> Record, size_t &Slot,
>      >> +    TypeIdCompatibleVtableInfo &TypeId) {
>      >> +  uint64_t Offset = Record[Slot++];
>      >> +  ValueInfo Callee = getValueInfoFromValueId(Record[Slot++]).first;
>      >> +  TypeId.push_back({Offset, Callee});
>      >> +}
>      >> +
>      >> +void
>     ModuleSummaryIndexBitcodeReader::parseTypeIdCompatibleVtableSummaryRecord(
>      >> +    ArrayRef<uint64_t> Record) {
>      >> +  size_t Slot = 0;
>      >> +  TypeIdCompatibleVtableInfo &TypeId =
>      >> +      TheIndex.getOrInsertTypeIdCompatibleVtableSummary(
>      >> +          {Strtab.data() + Record[Slot],
>      >> +           static_cast<size_t>(Record[Slot + 1])});
>      >> +  Slot += 2;
>      >> +
>      >> +  while (Slot < Record.size())
>      >> +    parseTypeIdCompatibleVtableInfo(Record, 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)
>      >> @@ -5883,6 +5907,34 @@ Error ModuleSummaryIndexBitcodeReader::p
>      >>          TheIndex.addGlobalValueSummary(GUID.first, std::move(FS));
>      >>          break;
>      >>        }
>      >> +    // FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS: [valueid,
>     flags, varflags,
>      >> +    //                        numrefs, numrefs x valueid,
>      >> +    //                        n x (valueid, offset)]
>      >> +    case bitc::FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS: {
>      >> +      unsigned ValueID = Record[0];
>      >> +      uint64_t RawFlags = Record[1];
>      >> +      GlobalVarSummary::GVarFlags GVF =
>     getDecodedGVarFlags(Record[2]);
>      >> +      unsigned NumRefs = Record[3];
>      >> +      unsigned RefListStartIndex = 4;
>      >> +      unsigned VTableListStartIndex = RefListStartIndex + NumRefs;
>      >> +      auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);
>      >> +      std::vector<ValueInfo> Refs = makeRefList(
>      >> +          ArrayRef<uint64_t>(Record).slice(RefListStartIndex,
>     NumRefs));
>      >> +      VTableFuncList VTableFuncs;
>      >> +      for (unsigned I = VTableListStartIndex, E =
>     Record.size(); I != E; ++I) {
>      >> +        ValueInfo Callee =
>     getValueInfoFromValueId(Record[I]).first;
>      >> +        uint64_t Offset = Record[++I];
>      >> +        VTableFuncs.push_back({Callee, Offset});
>      >> +      }
>      >> +      auto VS =
>      >> +          llvm::make_unique<GlobalVarSummary>(Flags, GVF,
>     std::move(Refs));
>      >> +      VS->setModulePath(getThisModule()->first());
>      >> +      VS->setVTableFuncs(VTableFuncs);
>      >> +      auto GUID = getValueInfoFromValueId(ValueID);
>      >> +      VS->setOriginalName(GUID.second);
>      >> +      TheIndex.addGlobalValueSummary(GUID.first, std::move(VS));
>      >> +      break;
>      >> +    }
>      >>        // FS_COMBINED: [valueid, modid, flags, instcount,
>     fflags, numrefs,
>      >>        //               numrefs x valueid, n x (valueid)]
>      >>        // FS_COMBINED_PROFILE: [valueid, modid, flags,
>     instcount, fflags, numrefs,
>      >> @@ -6049,6 +6101,10 @@ Error ModuleSummaryIndexBitcodeReader::p
>      >>        case bitc::FS_TYPE_ID:
>      >>          parseTypeIdSummaryRecord(Record, Strtab, TheIndex);
>      >>          break;
>      >> +
>      >> +    case bitc::FS_TYPE_ID_METADATA:
>      >> +      parseTypeIdCompatibleVtableSummaryRecord(Record);
>      >> +      break;
>      >>        }
>      >>      }
>      >>      llvm_unreachable("Exit infinite loop");
>      >>
>      >> Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
>      >> URL:
>     http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=364960&r1=364959&r2=364960&view=diff
>      >>
>     ==============================================================================
>      >> --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original)
>      >> +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Tue Jul  2
>     12:38:02 2019
>      >> @@ -214,7 +214,8 @@ private:
>      >>                                               const Function &F);
>      >>      void writeModuleLevelReferences(const GlobalVariable &V,
>      >>                                      SmallVector<uint64_t, 64>
>     &NameVals,
>      >> -                                  unsigned FSModRefsAbbrev);
>      >> +                                  unsigned FSModRefsAbbrev,
>      >> +                                  unsigned FSModVTableRefsAbbrev);
>      >>
>      >>      void assignValueId(GlobalValue::GUID ValGUID) {
>      >>        GUIDToValueIdMap[ValGUID] = ++GlobalValueId;
>      >> @@ -3605,6 +3606,19 @@ static void writeTypeIdSummaryRecord(Sma
>      >>                                          W.second);
>      >>    }
>      >>
>      >> +static void writeTypeIdCompatibleVtableSummaryRecord(
>      >> +    SmallVector<uint64_t, 64> &NameVals, StringTableBuilder
>     &StrtabBuilder,
>      >> +    const std::string &Id, const TypeIdCompatibleVtableInfo
>     &Summary,
>      >> +    ValueEnumerator &VE) {
>      >> +  NameVals.push_back(StrtabBuilder.add(Id));
>      >> +  NameVals.push_back(Id.size());
>      >> +
>      >> +  for (auto &P : Summary) {
>      >> +    NameVals.push_back(P.AddressPointOffset);
>      >> +    NameVals.push_back(VE.getValueID(P.VTableVI.getValue()));
>      >> +  }
>      >> +}
>      >> +
>      >>    // Helper to emit a single function summary record.
>      >>    void
>     ModuleBitcodeWriterBase::writePerModuleFunctionSummaryRecord(
>      >>        SmallVector<uint64_t, 64> &NameVals, GlobalValueSummary
>     *Summary,
>      >> @@ -3649,7 +3663,7 @@ void ModuleBitcodeWriterBase::writePerMo
>      >>    // and emit them in a summary record.
>      >>    void ModuleBitcodeWriterBase::writeModuleLevelReferences(
>      >>        const GlobalVariable &V, SmallVector<uint64_t, 64> &NameVals,
>      >> -    unsigned FSModRefsAbbrev) {
>      >> +    unsigned FSModRefsAbbrev, unsigned FSModVTableRefsAbbrev) {
>      >>      auto VI = Index->getValueInfo(V.getGUID());
>      >>      if (!VI || VI.getSummaryList().empty()) {
>      >>        // Only declarations should not have a summary (a
>     declaration might however
>      >> @@ -3663,6 +3677,10 @@ void ModuleBitcodeWriterBase::writeModul
>      >>      NameVals.push_back(getEncodedGVSummaryFlags(VS->flags()));
>      >>      NameVals.push_back(getEncodedGVarFlags(VS->varflags()));
>      >>
>      >> +  auto VTableFuncs = VS->vTableFuncs();
>      >> +  if (!VTableFuncs.empty())
>      >> +    NameVals.push_back(VS->refs().size());
>      >> +
>      >>      unsigned SizeBeforeRefs = NameVals.size();
>      >>      for (auto &RI : VS->refs())
>      >>        NameVals.push_back(VE.getValueID(RI.getValue()));
>      >> @@ -3670,8 +3688,20 @@ void ModuleBitcodeWriterBase::writeModul
>      >>      // been initialized from a DenseSet.
>      >>      llvm::sort(NameVals.begin() + SizeBeforeRefs, NameVals.end());
>      >>
>      >> -  Stream.EmitRecord(bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS,
>     NameVals,
>      >> -                    FSModRefsAbbrev);
>      >> +  if (!VTableFuncs.empty()) {
>      >> +    // VTableFuncs pairs should already be sorted by offset.
>      >> +    for (auto &P : VTableFuncs) {
>      >> +      NameVals.push_back(VE.getValueID(P.FuncVI.getValue()));
>      >> +      NameVals.push_back(P.VTableOffset);
>      >> +    }
>      >> +  }
>      >> +
>      >> +  if (VTableFuncs.empty())
>      >> +    Stream.EmitRecord(bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS,
>     NameVals,
>      >> +                      FSModRefsAbbrev);
>      >> +  else
>      >> +   
>     Stream.EmitRecord(bitc::FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS,
>     NameVals,
>      >> +                      FSModVTableRefsAbbrev);
>      >>      NameVals.clear();
>      >>    }
>      >>
>      >> @@ -3752,6 +3782,17 @@ void ModuleBitcodeWriterBase::writePerMo
>      >>      Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
>      >>      unsigned FSModRefsAbbrev = Stream.EmitAbbrev(std::move(Abbv));
>      >>
>      >> +  // Abbrev for FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS.
>      >> +  Abbv = std::make_shared<BitCodeAbbrev>();
>      >> + 
>     Abbv->Add(BitCodeAbbrevOp(bitc::FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS));
>      >> +  Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // valueid
>      >> +  Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // flags
>      >> +  Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs
>      >> +  // numrefs x valueid, n x (valueid , offset)
>      >> +  Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
>      >> +  Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
>      >> +  unsigned FSModVTableRefsAbbrev =
>     Stream.EmitAbbrev(std::move(Abbv));
>      >> +
>      >>      // Abbrev for FS_ALIAS.
>      >>      Abbv = std::make_shared<BitCodeAbbrev>();
>      >>      Abbv->Add(BitCodeAbbrevOp(bitc::FS_ALIAS));
>      >> @@ -3760,6 +3801,16 @@ void ModuleBitcodeWriterBase::writePerMo
>      >>      Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));   //
>     valueid
>      >>      unsigned FSAliasAbbrev = Stream.EmitAbbrev(std::move(Abbv));
>      >>
>      >> +  // Abbrev for FS_TYPE_ID_METADATA
>      >> +  Abbv = std::make_shared<BitCodeAbbrev>();
>      >> +  Abbv->Add(BitCodeAbbrevOp(bitc::FS_TYPE_ID_METADATA));
>      >> +  Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); //
>     typeid strtab index
>      >> +  Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); //
>     typeid length
>      >> +  // n x (valueid , offset)
>      >> +  Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
>      >> +  Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));
>      >> +  unsigned TypeIdCompatibleVtableAbbrev =
>     Stream.EmitAbbrev(std::move(Abbv));
>      >> +
>      >>      SmallVector<uint64_t, 64> NameVals;
>      >>      // Iterate over the list of functions instead of the Index to
>      >>      // ensure the ordering is stable.
>      >> @@ -3784,7 +3835,8 @@ void ModuleBitcodeWriterBase::writePerMo
>      >>      // Capture references from GlobalVariable initializers,
>     which are outside
>      >>      // of a function scope.
>      >>      for (const GlobalVariable &G : M.globals())
>      >> -    writeModuleLevelReferences(G, NameVals, FSModRefsAbbrev);
>      >> +    writeModuleLevelReferences(G, NameVals, FSModRefsAbbrev,
>      >> +                               FSModVTableRefsAbbrev);
>      >>
>      >>      for (const GlobalAlias &A : M.aliases()) {
>      >>        auto *Aliasee = A.getBaseObject();
>      >> @@ -3802,6 +3854,16 @@ void ModuleBitcodeWriterBase::writePerMo
>      >>        NameVals.clear();
>      >>      }
>      >>
>      >> +  if (!Index->typeIdCompatibleVtableMap().empty()) {
>      >> +    for (auto &S : Index->typeIdCompatibleVtableMap()) {
>      >> +      writeTypeIdCompatibleVtableSummaryRecord(NameVals,
>     StrtabBuilder, S.first,
>      >> +                                               S.second, VE);
>      >> +      Stream.EmitRecord(bitc::FS_TYPE_ID_METADATA, NameVals,
>      >> +                        TypeIdCompatibleVtableAbbrev);
>      >> +      NameVals.clear();
>      >> +    }
>      >> +  }
>      >> +
>      >>      Stream.ExitBlock();
>      >>    }
>      >>
>      >>
>      >> Modified: llvm/trunk/lib/IR/AsmWriter.cpp
>      >> URL:
>     http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/AsmWriter.cpp?rev=364960&r1=364959&r2=364960&view=diff
>      >>
>     ==============================================================================
>      >> --- llvm/trunk/lib/IR/AsmWriter.cpp (original)
>      >> +++ llvm/trunk/lib/IR/AsmWriter.cpp Tue Jul  2 12:38:02 2019
>      >> @@ -1037,6 +1037,9 @@ void SlotTracker::processIndex() {
>      >>           TidIter != TheIndex->typeIds().end(); TidIter++)
>      >>        CreateTypeIdSlot(TidIter->second.first);
>      >>
>      >> +  for (auto &TId : TheIndex->typeIdCompatibleVtableMap())
>      >> +    CreateGUIDSlot(GlobalValue::getGUID(TId.first));
>      >> +
>      >>      ST_DEBUG("end processIndex!\n");
>      >>    }
>      >>
>      >> @@ -2410,6 +2413,7 @@ public:
>      >>      void printGlobalVarSummary(const GlobalVarSummary *GS);
>      >>      void printFunctionSummary(const FunctionSummary *FS);
>      >>      void printTypeIdSummary(const TypeIdSummary &TIS);
>      >> +  void printTypeIdCompatibleVtableSummary(const
>     TypeIdCompatibleVtableInfo &TI);
>      >>      void printTypeTestResolution(const TypeTestResolution &TTRes);
>      >>      void printArgs(const std::vector<uint64_t> &Args);
>      >>      void printWPDRes(const WholeProgramDevirtResolution &WPDRes);
>      >> @@ -2712,6 +2716,15 @@ void AssemblyWriter::printModuleSummaryI
>      >>        printTypeIdSummary(TidIter->second.second);
>      >>        Out << ") ; guid = " << TidIter->first << "\n";
>      >>      }
>      >> +
>      >> +  // Print the TypeIdCompatibleVtableMap entries.
>      >> +  for (auto &TId : TheIndex->typeIdCompatibleVtableMap()) {
>      >> +    auto GUID = GlobalValue::getGUID(TId.first);
>      >> +    Out << "^" << Machine.getGUIDSlot(GUID)
>      >> +        << " = typeidCompatibleVTable: (name: \"" << TId.first
>     << "\"";
>      >> +    printTypeIdCompatibleVtableSummary(TId.second);
>      >> +    Out << ") ; guid = " << GUID << "\n";
>      >> +  }
>      >>    }
>      >>
>      >>    static const char *
>      >> @@ -2794,6 +2807,19 @@ void AssemblyWriter::printTypeIdSummary(
>      >>      Out << ")";
>      >>    }
>      >>
>      >> +void AssemblyWriter::printTypeIdCompatibleVtableSummary(
>      >> +    const TypeIdCompatibleVtableInfo &TI) {
>      >> +  Out << ", summary: (";
>      >> +  FieldSeparator FS;
>      >> +  for (auto &P : TI) {
>      >> +    Out << FS;
>      >> +    Out << "(offset: " << P.AddressPointOffset << ", ";
>      >> +    Out << "^" << Machine.getGUIDSlot(P.VTableVI.getGUID());
>      >> +    Out << ")";
>      >> +  }
>      >> +  Out << ")";
>      >> +}
>      >> +
>      >>    void AssemblyWriter::printArgs(const std::vector<uint64_t>
>     &Args) {
>      >>      Out << "args: (";
>      >>      FieldSeparator FS;
>      >> @@ -2863,6 +2889,19 @@ void AssemblyWriter::printAliasSummary(c
>      >>
>      >>    void AssemblyWriter::printGlobalVarSummary(const
>     GlobalVarSummary *GS) {
>      >>      Out << ", varFlags: (readonly: " << GS->VarFlags.ReadOnly
>     << ")";
>      >> +
>      >> +  auto VTableFuncs = GS->vTableFuncs();
>      >> +  if (!VTableFuncs.empty()) {
>      >> +    Out << ", vTableFuncs: (";
>      >> +    FieldSeparator FS;
>      >> +    for (auto &P : VTableFuncs) {
>      >> +      Out << FS;
>      >> +      Out << "(virtFunc: ^" <<
>     Machine.getGUIDSlot(P.FuncVI.getGUID())
>      >> +          << ", offset: " << P.VTableOffset;
>      >> +      Out << ")";
>      >> +    }
>      >> +    Out << ")";
>      >> +  }
>      >>    }
>      >>
>      >>    static std::string getLinkageName(GlobalValue::LinkageTypes LT) {
>      >>
>      >> Modified: llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
>      >> URL:
>     http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp?rev=364960&r1=364959&r2=364960&view=diff
>      >>
>     ==============================================================================
>      >> --- llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp
>     (original)
>      >> +++ llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp Tue
>     Jul  2 12:38:02 2019
>      >> @@ -417,34 +417,53 @@ void splitAndWriteThinLTOBitcode(
>      >>      }
>      >>    }
>      >>
>      >> -// Returns whether this module needs to be split because
>     splitting is
>      >> -// enabled and it uses type metadata.
>      >> -bool requiresSplit(Module &M) {
>      >> -  // First check if the LTO Unit splitting has been enabled.
>      >> +// Check if the LTO Unit splitting has been enabled.
>      >> +bool enableSplitLTOUnit(Module &M) {
>      >>      bool EnableSplitLTOUnit = false;
>      >>      if (auto *MD = mdconst::extract_or_null<ConstantInt>(
>      >>              M.getModuleFlag("EnableSplitLTOUnit")))
>      >>        EnableSplitLTOUnit = MD->getZExtValue();
>      >> -  if (!EnableSplitLTOUnit)
>      >> -    return false;
>      >> +  return EnableSplitLTOUnit;
>      >> +}
>      >>
>      >> -  // Module only needs to be split if it contains type metadata.
>      >> +// Returns whether this module needs to be split because it
>     uses type metadata.
>      >> +bool hasTypeMetadata(Module &M) {
>      >>      for (auto &GO : M.global_objects()) {
>      >>        if (GO.hasMetadata(LLVMContext::MD_type))
>      >>          return true;
>      >>      }
>      >> -
>      >>      return false;
>      >>    }
>      >>
>      >>    void writeThinLTOBitcode(raw_ostream &OS, raw_ostream
>     *ThinLinkOS,
>      >>                             function_ref<AAResults &(Function
>     &)> AARGetter,
>      >>                             Module &M, const ModuleSummaryIndex
>     *Index) {
>      >> -  // Split module if splitting is enabled and it contains any
>     type metadata.
>      >> -  if (requiresSplit(M))
>      >> -    return splitAndWriteThinLTOBitcode(OS, ThinLinkOS,
>     AARGetter, M);
>      >> +  std::unique_ptr<ModuleSummaryIndex> NewIndex = nullptr;
>      >> +  // See if this module has any type metadata. If so, we try to
>     split it
>      >> +  // or at least promote type ids to enable WPD.
>      >> +  if (hasTypeMetadata(M)) {
>      >> +    if (enableSplitLTOUnit(M))
>      >> +      return splitAndWriteThinLTOBitcode(OS, ThinLinkOS,
>     AARGetter, M);
>      >> +    // Promote type ids as needed for index-based WPD.
>      >> +    std::string ModuleId = getUniqueModuleId(&M);
>      >> +    if (!ModuleId.empty()) {
>      >> +      promoteTypeIds(M, ModuleId);
>      >> +      // Need to rebuild the index so that it contains type
>     metadata
>      >> +      // for the newly promoted type ids.
>      >> +      // FIXME: Probably should not bother building the index
>     at all
>      >> +      // in the caller of writeThinLTOBitcode (which does so
>     via the
>      >> +      // ModuleSummaryIndexAnalysis pass), since we have to
>     rebuild it
>      >> +      // anyway whenever there is type metadata (here or in
>      >> +      // splitAndWriteThinLTOBitcode). Just always build it
>     once via the
>      >> +      // buildModuleSummaryIndex when Module(s) are ready.
>      >> +      ProfileSummaryInfo PSI(M);
>      >> +      NewIndex = llvm::make_unique<ModuleSummaryIndex>(
>      >> +          buildModuleSummaryIndex(M, nullptr, &PSI));
>      >> +      Index = NewIndex.get();
>      >> +    }
>      >> +  }
>      >>
>      >> -  // Otherwise we can just write it out as a regular module.
>      >> +  // Write it out as an unsplit ThinLTO module.
>      >>
>      >>      // Save the module hash produced for the full bitcode,
>     which will
>      >>      // be used in the backends, and use that in the minimized
>     bitcode
>      >>
>      >> Added: llvm/trunk/test/Assembler/thinlto-vtable-summary.ll
>      >> URL:
>     http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/thinlto-vtable-summary.ll?rev=364960&view=auto
>      >>
>     ==============================================================================
>      >> --- llvm/trunk/test/Assembler/thinlto-vtable-summary.ll (added)
>      >> +++ llvm/trunk/test/Assembler/thinlto-vtable-summary.ll Tue Jul 
>     2 12:38:02 2019
>      >> @@ -0,0 +1,38 @@
>      >> +; Test summary parsing of index-based WPD related summary fields
>      >> +; RUN: llvm-as %s -o - | llvm-dis -o %t.ll
>      >> +; RUN: grep "^\^" %s >%t2
>      >> +; RUN: grep "^\^" %t.ll >%t3
>      >> +; Expect that the summary information is the same after
>     round-trip through
>      >> +; llvm-as and llvm-dis.
>      >> +; RUN: diff %t2 %t3
>      >> +
>      >> +source_filename = "thinlto-vtable-summary.ll"
>      >> +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
>      >> +target triple = "x86_64-grtev4-linux-gnu"
>      >> +
>      >> +%struct.A = type { i32 (...)** }
>      >> +%struct.B = type { %struct.A }
>      >> +%struct.C = type { %struct.A }
>      >> +
>      >> + at _ZTV1B = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8*
>     undef, i8* bitcast (i32 (%struct.B*, i32)* @_ZN1B1fEi to i8*), i8*
>     bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0,
>     !type !1
>      >> + at _ZTV1C = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8*
>     undef, i8* bitcast (i32 (%struct.C*, i32)* @_ZN1C1fEi to i8*), i8*
>     bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0,
>     !type !2
>      >> +
>      >> +declare i32 @_ZN1B1fEi(%struct.B*, i32)
>      >> +
>      >> +declare i32 @_ZN1A1nEi(%struct.A*, i32)
>      >> +
>      >> +declare i32 @_ZN1C1fEi(%struct.C*, i32)
>      >> +
>      >> +!0 = !{i64 16, !"_ZTS1A"}
>      >> +!1 = !{i64 16, !"_ZTS1B"}
>      >> +!2 = !{i64 16, !"_ZTS1C"}
>      >> +
>      >> +^0 = module: (path: "<stdin>", hash: (0, 0, 0, 0, 0))
>      >> +^1 = gv: (name: "_ZN1A1nEi") ; guid = 1621563287929432257
>      >> +^2 = gv: (name: "_ZTV1B", summaries: (variable: (module: ^0,
>     flags: (linkage: external, notEligibleToImport: 0, live: 0,
>     dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0), vTableFuncs:
>     ((virtFunc: ^3, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^3,
>     ^1)))) ; guid = 5283576821522790367
>      >> +^3 = gv: (name: "_ZN1B1fEi") ; guid = 7162046368816414394
>      >> +^4 = gv: (name: "_ZTV1C", summaries: (variable: (module: ^0,
>     flags: (linkage: external, notEligibleToImport: 0, live: 0,
>     dsoLocal: 0, canAutoHide: 0), varFlags: (readonly: 0), vTableFuncs:
>     ((virtFunc: ^5, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^1,
>     ^5)))) ; guid = 13624023785555846296
>      >> +^5 = gv: (name: "_ZN1C1fEi") ; guid = 14876272565662207556
>      >> +^6 = typeidCompatibleVTable: (name: "_ZTS1A", summary:
>     ((offset: 16, ^2), (offset: 16, ^4))) ; guid = 7004155349499253778
>      >> +^7 = typeidCompatibleVTable: (name: "_ZTS1B", summary:
>     ((offset: 16, ^2))) ; guid = 6203814149063363976
>      >> +^8 = typeidCompatibleVTable: (name: "_ZTS1C", summary:
>     ((offset: 16, ^4))) ; guid = 1884921850105019584
>      >>
>      >> Added: llvm/trunk/test/ThinLTO/X86/devirt.ll
>      >> URL:
>     http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/devirt.ll?rev=364960&view=auto
>      >>
>     ==============================================================================
>      >> --- llvm/trunk/test/ThinLTO/X86/devirt.ll (added)
>      >> +++ llvm/trunk/test/ThinLTO/X86/devirt.ll Tue Jul  2 12:38:02 2019
>      >> @@ -0,0 +1,146 @@
>      >> +; REQUIRES: x86-registered-target
>      >> +
>      >> +; Test devirtualization through the thin link and backend.
>      >> +
>      >> +; Generate split module with summary for hybrid Thin/Regular
>     LTO WPD.
>      >> +; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t.o %s
>      >> +
>      >> +; Check that we have module flag showing splitting enabled, and
>     that we don't
>      >> +; generate summary information needed for index-based WPD.
>      >> +; RUN: llvm-modextract -b -n=0 %t.o -o %t.o.0
>      >> +; RUN: llvm-dis -o - %t.o.0 | FileCheck %s
>     --check-prefix=ENABLESPLITFLAG --implicit-check-not=vTableFuncs
>     --implicit-check-not=typeidCompatibleVTable
>      >> +; RUN: llvm-modextract -b -n=1 %t.o -o %t.o.1
>      >> +; RUN: llvm-dis -o - %t.o.1 | FileCheck %s
>     --check-prefix=ENABLESPLITFLAG --implicit-check-not=vTableFuncs
>     --implicit-check-not=typeidCompatibleVTable
>      >> +; ENABLESPLITFLAG: !{i32 1, !"EnableSplitLTOUnit", i32 1}
>      >> +
>      >> +; Generate unsplit module with summary for ThinLTO index-based WPD.
>      >> +; RUN: opt -thinlto-bc -o %t2.o %s
>      >> +
>      >> +; Check that we don't have module flag when splitting not
>     enabled for ThinLTO,
>      >> +; and that we generate summary information needed for
>     index-based WPD.
>      >> +; RUN: llvm-dis -o - %t2.o | FileCheck %s
>     --check-prefix=NOENABLESPLITFLAG
>      >> +; NOENABLESPLITFLAG-DAG: !{i32 1, !"EnableSplitLTOUnit", i32 0}
>      >> +; NOENABLESPLITFLAG-DAG: [[An:\^[0-9]+]] = gv: (name: "_ZN1A1nEi")
>      >> +; NOENABLESPLITFLAG-DAG: [[Bf:\^[0-9]+]] = gv: (name: "_ZN1B1fEi")
>      >> +; NOENABLESPLITFLAG-DAG: [[Cf:\^[0-9]+]] = gv: (name: "_ZN1C1fEi")
>      >> +; NOENABLESPLITFLAG-DAG: [[Dm:\^[0-9]+]] = gv: (name: "_ZN1D1mEi")
>      >> +; NOENABLESPLITFLAG-DAG: [[B:\^[0-9]+]] = gv: (name: "_ZTV1B",
>     {{.*}} vTableFuncs: ((virtFunc: [[Bf]], offset: 16), (virtFunc:
>     [[An]], offset: 24)), refs: ([[Bf]], [[An]])
>      >> +; NOENABLESPLITFLAG-DAG: [[C:\^[0-9]+]] = gv: (name: "_ZTV1C",
>     {{.*}} vTableFuncs: ((virtFunc: [[Cf]], offset: 16), (virtFunc:
>     [[An]], offset: 24)), refs: ([[An]], [[Cf]])
>      >> +; NOENABLESPLITFLAG-DAG: [[D:\^[0-9]+]] = gv: (name: "_ZTV1D",
>     {{.*}} vTableFuncs: ((virtFunc: [[Dm]], offset: 16)), refs: ([[Dm]])
>      >> +; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name:
>     "_ZTS1A", summary: ((offset: 16, [[B]]), (offset: 16, [[C]])))
>      >> +; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name:
>     "_ZTS1B", summary: ((offset: 16, [[B]])))
>      >> +; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name:
>     "_ZTS1C", summary: ((offset: 16, [[C]])))
>      >> +; Type Id on _ZTV1D should have been promoted
>      >> +; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name:
>     "1${{.*}}", summary: ((offset: 16, [[D]])))
>      >> +
>      >> +; TODO: Test index-based WPD one %t2.o once implemented.
>      >> +
>      >> +; Legacy PM
>      >> +; RUN: llvm-lto2 run %t.o -save-temps -pass-remarks=. \
>      >> +; RUN:   -o %t3 \
>      >> +; RUN:   -r=%t.o,test,px \
>      >> +; RUN:   -r=%t.o,_ZN1A1nEi,p \
>      >> +; RUN:   -r=%t.o,_ZN1B1fEi,p \
>      >> +; RUN:   -r=%t.o,_ZN1C1fEi,p \
>      >> +; RUN:   -r=%t.o,_ZN1D1mEi,p \
>      >> +; RUN:   -r=%t.o,_ZTV1B, \
>      >> +; RUN:   -r=%t.o,_ZTV1C, \
>      >> +; RUN:   -r=%t.o,_ZTV1D, \
>      >> +; RUN:   -r=%t.o,_ZN1A1nEi, \
>      >> +; RUN:   -r=%t.o,_ZN1B1fEi, \
>      >> +; RUN:   -r=%t.o,_ZN1C1fEi, \
>      >> +; RUN:   -r=%t.o,_ZN1D1mEi, \
>      >> +; RUN:   -r=%t.o,_ZTV1B,px \
>      >> +; RUN:   -r=%t.o,_ZTV1C,px \
>      >> +; RUN:   -r=%t.o,_ZTV1D,px 2>&1 | FileCheck %s
>     --check-prefix=REMARK
>      >> +; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s
>     --check-prefix=CHECK-IR
>      >> +
>      >> +; New PM
>      >> +; RUN: llvm-lto2 run %t.o -save-temps -use-new-pm -pass-remarks=. \
>      >> +; RUN:   -o %t3 \
>      >> +; RUN:   -r=%t.o,test,px \
>      >> +; RUN:   -r=%t.o,_ZN1A1nEi,p \
>      >> +; RUN:   -r=%t.o,_ZN1B1fEi,p \
>      >> +; RUN:   -r=%t.o,_ZN1C1fEi,p \
>      >> +; RUN:   -r=%t.o,_ZN1D1mEi,p \
>      >> +; RUN:   -r=%t.o,_ZTV1B, \
>      >> +; RUN:   -r=%t.o,_ZTV1C, \
>      >> +; RUN:   -r=%t.o,_ZTV1D, \
>      >> +; RUN:   -r=%t.o,_ZN1A1nEi, \
>      >> +; RUN:   -r=%t.o,_ZN1B1fEi, \
>      >> +; RUN:   -r=%t.o,_ZN1C1fEi, \
>      >> +; RUN:   -r=%t.o,_ZN1D1mEi, \
>      >> +; RUN:   -r=%t.o,_ZTV1B,px \
>      >> +; RUN:   -r=%t.o,_ZTV1C,px \
>      >> +; RUN:   -r=%t.o,_ZTV1D,px 2>&1 | FileCheck %s
>     --check-prefix=REMARK
>      >> +; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s
>     --check-prefix=CHECK-IR
>      >> +
>      >> +; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi
>      >> +; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi
>      >> +
>      >> +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
>      >> +target triple = "x86_64-grtev4-linux-gnu"
>      >> +
>      >> +%struct.A = type { i32 (...)** }
>      >> +%struct.B = type { %struct.A }
>      >> +%struct.C = type { %struct.A }
>      >> +%struct.D = type { i32 (...)** }
>      >> +
>      >> + at _ZTV1B = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8*
>     undef, i8* bitcast (i32 (%struct.B*, i32)* @_ZN1B1fEi to i8*), i8*
>     bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0,
>     !type !1
>      >> + at _ZTV1C = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8*
>     undef, i8* bitcast (i32 (%struct.C*, i32)* @_ZN1C1fEi to i8*), i8*
>     bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0,
>     !type !2
>      >> + at _ZTV1D = constant { [3 x i8*] } { [3 x i8*] [i8* null, i8*
>     undef, i8* bitcast (i32 (%struct.D*, i32)* @_ZN1D1mEi to i8*)] },
>     !type !3
>      >> +
>      >> +
>      >> +; CHECK-IR-LABEL: define i32 @test
>      >> +define i32 @test(%struct.A* %obj, %struct.D* %obj2, i32 %a) {
>      >> +entry:
>      >> +  %0 = bitcast %struct.A* %obj to i8***
>      >> +  %vtable = load i8**, i8*** %0
>      >> +  %1 = bitcast i8** %vtable to i8*
>      >> +  %p = call i1 @llvm.type.test(i8* %1, metadata !"_ZTS1A")
>      >> +  call void @llvm.assume(i1 %p)
>      >> +  %fptrptr = getelementptr i8*, i8** %vtable, i32 1
>      >> +  %2 = bitcast i8** %fptrptr to i32 (%struct.A*, i32)**
>      >> +  %fptr1 = load i32 (%struct.A*, i32)*, i32 (%struct.A*, i32)**
>     %2, align 8
>      >> +
>      >> +  ; Check that the call was devirtualized.
>      >> +  ; CHECK-IR: %call = tail call i32 @_ZN1A1nEi
>      >> +  %call = tail call i32 %fptr1(%struct.A* nonnull %obj, i32 %a)
>      >> +
>      >> +  %3 = bitcast i8** %vtable to i32 (%struct.A*, i32)**
>      >> +  %fptr22 = load i32 (%struct.A*, i32)*, i32 (%struct.A*,
>     i32)** %3, align 8
>      >> +
>      >> +  ; We still have to call it as virtual.
>      >> +  ; CHECK-IR: %call3 = tail call i32 %fptr22
>      >> +  %call3 = tail call i32 %fptr22(%struct.A* nonnull %obj, i32
>     %call)
>      >> +
>      >> +  %4 = bitcast %struct.D* %obj2 to i8***
>      >> +  %vtable2 = load i8**, i8*** %4
>      >> +  %5 = bitcast i8** %vtable2 to i8*
>      >> +  %p2 = call i1 @llvm.type.test(i8* %5, metadata !4)
>      >> +  call void @llvm.assume(i1 %p2)
>      >> +
>      >> +  %6 = bitcast i8** %vtable2 to i32 (%struct.D*, i32)**
>      >> +  %fptr33 = load i32 (%struct.D*, i32)*, i32 (%struct.D*,
>     i32)** %6, align 8
>      >> +
>      >> +  ; Check that the call was devirtualized.
>      >> +  ; CHECK-IR: %call4 = tail call i32 @_ZN1D1mEi
>      >> +  %call4 = tail call i32 %fptr33(%struct.D* nonnull %obj2, i32
>     %call3)
>      >> +  ret i32 %call4
>      >> +}
>      >> +; CHECK-IR-LABEL: ret i32
>      >> +; CHECK-IR-LABEL: }
>      >> +
>      >> +declare i1 @llvm.type.test(i8*, metadata)
>      >> +declare void @llvm.assume(i1)
>      >> +
>      >> +declare i32 @_ZN1B1fEi(%struct.B* %this, i32 %a)
>      >> +declare i32 @_ZN1A1nEi(%struct.A* %this, i32 %a)
>      >> +declare i32 @_ZN1C1fEi(%struct.C* %this, i32 %a)
>      >> +declare i32 @_ZN1D1mEi(%struct.D* %this, i32 %a)
>      >> +
>      >> +!0 = !{i64 16, !"_ZTS1A"}
>      >> +!1 = !{i64 16, !"_ZTS1B"}
>      >> +!2 = !{i64 16, !"_ZTS1C"}
>      >> +!3 = !{i64 16, !4}
>      >> +!4 = distinct !{}
>      >>
>      >> Modified: llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
>      >> URL:
>     http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp?rev=364960&r1=364959&r2=364960&view=diff
>      >>
>     ==============================================================================
>      >> --- llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp (original)
>      >> +++ llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp Tue
>     Jul  2 12:38:02 2019
>      >> @@ -317,6 +317,7 @@ static const char *GetCodeName(unsigned
>      >>          STRINGIFY_CODE(FS, PERMODULE_PROFILE)
>      >>          STRINGIFY_CODE(FS, PERMODULE_RELBF)
>      >>          STRINGIFY_CODE(FS, PERMODULE_GLOBALVAR_INIT_REFS)
>      >> +      STRINGIFY_CODE(FS, PERMODULE_VTABLE_GLOBALVAR_INIT_REFS)
>      >>          STRINGIFY_CODE(FS, COMBINED)
>      >>          STRINGIFY_CODE(FS, COMBINED_PROFILE)
>      >>          STRINGIFY_CODE(FS, COMBINED_GLOBALVAR_INIT_REFS)
>      >> @@ -334,6 +335,7 @@ static const char *GetCodeName(unsigned
>      >>          STRINGIFY_CODE(FS, CFI_FUNCTION_DEFS)
>      >>          STRINGIFY_CODE(FS, CFI_FUNCTION_DECLS)
>      >>          STRINGIFY_CODE(FS, TYPE_ID)
>      >> +      STRINGIFY_CODE(FS, TYPE_ID_METADATA)
>      >>        }
>      >>      case bitc::METADATA_ATTACHMENT_ID:
>      >>        switch(CodeID) {
>      >>
>      >>
>      >> _______________________________________________
>      >> llvm-commits mailing list
>      >> llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>
>      >> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>      >>
>      > _______________________________________________
>      > llvm-commits mailing list
>      > llvm-commits at lists.llvm.org <mailto:llvm-commits at lists.llvm.org>
>      > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>      >
> 
> 
> 
> -- 
> Teresa Johnson |	 Software Engineer |	tejohnson at google.com 
> <mailto:tejohnson at google.com> |	
> 



More information about the llvm-commits mailing list