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