[llvm] r351453 - [ThinLTO] Add summary entries for index-based WPD
Teresa Johnson via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 17 08:10:02 PST 2019
Mistaken commit, reverted in r351455.
On Thu, Jan 17, 2019 at 7:53 AM Teresa Johnson via llvm-commits <
llvm-commits at lists.llvm.org> wrote:
> Author: tejohnson
> Date: Thu Jan 17 07:49:03 2019
> New Revision: 351453
>
> URL: http://llvm.org/viewvc/llvm-project?rev=351453&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 index-based WPD will be sent as a follow-on.
>
> 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=351453&r1=351452&r2=351453&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h (original)
> +++ llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h Thu Jan 17 07:49:03 2019
> @@ -264,10 +264,25 @@ 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,
> + // 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=351453&r1=351452&r2=351453&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h (original)
> +++ llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h Thu Jan 17 07:49:03
> 2019
> @@ -666,6 +666,12 @@ template <> struct DenseMapInfo<Function
> }
> };
>
> +/// Pair of function ValueInfo and offset within a vtable definition
> +/// initializer array.
> +using VirtFuncOffsetPair = std::pair<ValueInfo, uint64_t>;
> +/// List of functions referenced by a particular vtable definition.
> +using VTableFuncList = std::vector<VirtFuncOffsetPair>;
> +
> /// Global variable summary information to aid decisions and
> /// implementation of importing.
> ///
> @@ -673,6 +679,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) {}
> @@ -693,6 +704,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<VirtFuncOffsetPair> vTableFuncs() const {
> + if (VTableFuncs)
> + return *VTableFuncs;
> + return {};
> + }
> };
>
> struct TypeTestResolution {
> @@ -791,6 +813,14 @@ using GVSummaryMapTy = DenseMap<GlobalVa
> using TypeIdSummaryMapTy =
> std::multimap<GlobalValue::GUID, std::pair<std::string,
> TypeIdSummary>>;
>
> +/// Holds information about vtable definitions decorated with type
> metadata:
> +/// the vtable definition value and its offset in the corresponding type
> +/// metadata.
> +using TypeIdOffsetGVPair = std::pair<uint64_t, ValueInfo>;
> +/// List of vtable definitions decorated by the same type id metadata,
> +/// and their corresponding offsets in the type id metadata.
> +using TypeIdGVInfo = std::vector<TypeIdOffsetGVPair>;
> +
> /// Class to hold module path string table and global value map,
> /// and encapsulate methods for operating on them.
> class ModuleSummaryIndex {
> @@ -803,9 +833,14 @@ 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.
> + std::map<std::string, TypeIdGVInfo> TypeIdMetadataMap;
> +
> /// 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;
> @@ -1163,6 +1198,27 @@ public:
> return nullptr;
> }
>
> + const std::map<std::string, TypeIdGVInfo> &typeIdMetadataMap() const {
> + return TypeIdMetadataMap;
> + }
> +
> + /// Return an existing or new TypeIdMetadataMap entry for \p TypeId.
> + /// This accessor can mutate the map and therefore should not be used in
> + /// the ThinLTO backends.
> + TypeIdGVInfo &getOrInsertTypeIdMetadataSummary(StringRef TypeId) {
> + return TypeIdMetadataMap[TypeId];
> + }
> +
> + /// For the given \p TypeId, this returns either a pointer to the
> + /// TypeIdMetadataMap entry (if present in the summary map) or null
> + /// (if not present). This may be used when importing.
> + const TypeIdGVInfo *getTypeIdMetadataSummary(StringRef TypeId) const {
> + auto I = TypeIdMetadataMap.find(TypeId);
> + if (I == TypeIdMetadataMap.end())
> + return nullptr;
> + 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=351453&r1=351452&r2=351453&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp (original)
> +++ llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp Thu Jan 17 07:49:03
> 2019
> @@ -406,9 +406,98 @@ static void computeFunctionSummary(Modul
> Index.addGlobalValueSummary(F, std::move(FuncSummary));
> }
>
> -static void
> -computeVariableSummary(ModuleSummaryIndex &Index, const GlobalVariable &V,
> - DenseSet<GlobalValue::GUID> &CantBePromoted) {
> +/// 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(
> + std::make_pair(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.second >= PrevOffset);
> + PrevOffset = P.second;
> + }
> +#endif
> +}
> +
> +/// Record vtable definition \p V for each type metadata it references.
> +static void recordTypeIdMetadataReferences(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.getOrInsertTypeIdMetadataSummary(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);
> @@ -416,6 +505,21 @@ computeVariableSummary(ModuleSummaryInde
> GlobalValueSummary::GVFlags Flags(V.getLinkage(), NonRenamableLocal,
> /* Live = */ false, V.isDSOLocal());
>
> + 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.
> + recordTypeIdMetadataReferences(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() &&
> @@ -426,6 +530,8 @@ computeVariableSummary(ModuleSummaryInde
> CantBePromoted.insert(V.getGUID());
> if (HasBlockAddress)
> GVarSummary->setNotEligibleToImport();
> + if (!VTableFuncs.empty())
> + GVarSummary->setVTableFuncs(VTableFuncs);
> Index.addGlobalValueSummary(V, std::move(GVarSummary));
> }
>
> @@ -568,10 +674,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=351453&r1=351452&r2=351453&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/AsmParser/LLLexer.cpp (original)
> +++ llvm/trunk/lib/AsmParser/LLLexer.cpp Thu Jan 17 07:49:03 2019
> @@ -749,6 +749,8 @@ lltok::Kind LLLexer::LexIdentifier() {
> KEYWORD(critical);
> KEYWORD(relbf);
> KEYWORD(variable);
> + KEYWORD(vTableFuncs);
> + KEYWORD(virtFunc);
> KEYWORD(aliasee);
> KEYWORD(refs);
> KEYWORD(typeIdInfo);
> @@ -761,6 +763,7 @@ lltok::Kind LLLexer::LexIdentifier() {
> KEYWORD(offset);
> KEYWORD(args);
> KEYWORD(typeid);
> + KEYWORD(typeidMetadata);
> 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=351453&r1=351452&r2=351453&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/AsmParser/LLParser.cpp (original)
> +++ llvm/trunk/lib/AsmParser/LLParser.cpp Thu Jan 17 07:49:03 2019
> @@ -822,6 +822,9 @@ bool LLParser::ParseSummaryEntry() {
> case lltok::kw_typeid:
> return ParseTypeIdEntry(SummaryID);
> break;
> + case lltok::kw_typeidMetadata:
> + return ParseTypeIdMetadataEntry(SummaryID);
> + break;
> default:
> return Error(Lex.getLoc(), "unexpected summary kind");
> }
> @@ -7257,6 +7260,90 @@ bool LLParser::ParseTypeIdSummary(TypeId
> return false;
> }
>
> +static ValueInfo EmptyVI =
> + ValueInfo(false, (GlobalValueSummaryMapTy::value_type *)-8);
> +
> +/// TypeIdMetadataEntry
> +/// ::= 'typeidMetadata' ':' '(' 'name' ':' STRINGCONSTANT ','
> TypeIdGVInfo
> +/// ')'
> +bool LLParser::ParseTypeIdMetadataEntry(unsigned ID) {
> + assert(Lex.getKind() == lltok::kw_typeidMetadata);
> + 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;
> +
> + TypeIdGVInfo &TI = Index->getOrInsertTypeIdMetadataSummary(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 TypeIdGVInfo 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].second == 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].second, 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' )
> ','
> @@ -7764,6 +7851,7 @@ bool LLParser::ParseVariableSummary(std:
> /*Live=*/false, /*IsLocal=*/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) ||
> @@ -7772,10 +7860,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"))
> @@ -7785,6 +7883,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));
> @@ -8002,6 +8101,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(std::make_pair(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].first == 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].first, 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=351453&r1=351452&r2=351453&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/AsmParser/LLParser.h (original)
> +++ llvm/trunk/lib/AsmParser/LLParser.h Thu Jan 17 07:49:03 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 ParseTypeIdMetadataEntry(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=351453&r1=351452&r2=351453&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/AsmParser/LLToken.h (original)
> +++ llvm/trunk/lib/AsmParser/LLToken.h Thu Jan 17 07:49:03 2019
> @@ -379,6 +379,8 @@ enum Kind {
> kw_critical,
> kw_relbf,
> kw_variable,
> + kw_vTableFuncs,
> + kw_virtFunc,
> kw_aliasee,
> kw_refs,
> kw_typeIdInfo,
> @@ -391,6 +393,7 @@ enum Kind {
> kw_offset,
> kw_args,
> kw_typeid,
> + kw_typeidMetadata,
> 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=351453&r1=351452&r2=351453&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)
> +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Thu Jan 17 07:49:03
> 2019
> @@ -748,6 +748,9 @@ private:
> bool HasRelBF);
> Error parseEntireSummary(unsigned ID);
> Error parseModuleStringTable();
> + void parseTypeIdMetadataSummaryRecord(ArrayRef<uint64_t> Record);
> + void parseTypeIdGVInfo(ArrayRef<uint64_t> Record, size_t &Slot,
> + TypeIdGVInfo &TypeId);
>
> std::pair<ValueInfo, GlobalValue::GUID>
> getValueInfoFromValueId(unsigned ValueId);
> @@ -5224,6 +5227,24 @@ static void parseTypeIdSummaryRecord(Arr
> parseWholeProgramDevirtResolution(Record, Strtab, Slot, TypeId);
> }
>
> +void ModuleSummaryIndexBitcodeReader::parseTypeIdGVInfo(
> + ArrayRef<uint64_t> Record, size_t &Slot, TypeIdGVInfo &TypeId) {
> + uint64_t Offset = Record[Slot++];
> + ValueInfo Callee = getValueInfoFromValueId(Record[Slot++]).first;
> + TypeId.push_back({Offset, Callee});
> +}
> +
> +void ModuleSummaryIndexBitcodeReader::parseTypeIdMetadataSummaryRecord(
> + ArrayRef<uint64_t> Record) {
> + size_t Slot = 0;
> + TypeIdGVInfo &TypeId = TheIndex.getOrInsertTypeIdMetadataSummary(
> + {Strtab.data() + Record[Slot], static_cast<size_t>(Record[Slot +
> 1])});
> + Slot += 2;
> +
> + while (Slot < Record.size())
> + parseTypeIdGVInfo(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)
> @@ -5441,6 +5462,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,
> @@ -5610,6 +5659,10 @@ Error ModuleSummaryIndexBitcodeReader::p
> case bitc::FS_TYPE_ID:
> parseTypeIdSummaryRecord(Record, Strtab, TheIndex);
> break;
> +
> + case bitc::FS_TYPE_ID_METADATA:
> + parseTypeIdMetadataSummaryRecord(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=351453&r1=351452&r2=351453&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original)
> +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Thu Jan 17 07:49:03
> 2019
> @@ -215,7 +215,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;
> @@ -3528,6 +3529,18 @@ static void writeTypeIdSummaryRecord(Sma
> W.second);
> }
>
> +static void writeTypeIdMetadataSummaryRecord(
> + SmallVector<uint64_t, 64> &NameVals, StringTableBuilder
> &StrtabBuilder,
> + const std::string &Id, const TypeIdGVInfo &Summary, ValueEnumerator
> &VE) {
> + NameVals.push_back(StrtabBuilder.add(Id));
> + NameVals.push_back(Id.size());
> +
> + for (auto &P : Summary) {
> + NameVals.push_back(P.first);
> + NameVals.push_back(VE.getValueID(P.second.getValue()));
> + }
> +}
> +
> // Helper to emit a single function summary record.
> void ModuleBitcodeWriterBase::writePerModuleFunctionSummaryRecord(
> SmallVector<uint64_t, 64> &NameVals, GlobalValueSummary *Summary,
> @@ -3572,7 +3585,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
> @@ -3586,6 +3599,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()));
> @@ -3593,8 +3610,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.first.getValue()));
> + NameVals.push_back(P.second);
> + }
> + }
> +
> + 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();
> }
>
> @@ -3675,6 +3704,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));
> @@ -3707,7 +3747,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();
> @@ -3725,6 +3766,16 @@ void ModuleBitcodeWriterBase::writePerMo
> NameVals.clear();
> }
>
> + if (!Index->typeIdMetadataMap().empty()) {
> + SmallVector<uint64_t, 64> NameVals;
> + for (auto &S : Index->typeIdMetadataMap()) {
> + writeTypeIdMetadataSummaryRecord(NameVals, StrtabBuilder, S.first,
> + S.second, VE);
> + Stream.EmitRecord(bitc::FS_TYPE_ID_METADATA, NameVals);
> + 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=351453&r1=351452&r2=351453&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/IR/AsmWriter.cpp (original)
> +++ llvm/trunk/lib/IR/AsmWriter.cpp Thu Jan 17 07:49:03 2019
> @@ -1038,6 +1038,9 @@ void SlotTracker::processIndex() {
> TidIter != TheIndex->typeIds().end(); TidIter++)
> CreateTypeIdSlot(TidIter->second.first);
>
> + for (auto &TId : TheIndex->typeIdMetadataMap())
> + CreateGUIDSlot(GlobalValue::getGUID(TId.first));
> +
> ST_DEBUG("end processIndex!\n");
> }
>
> @@ -2393,6 +2396,7 @@ public:
> void printGlobalVarSummary(const GlobalVarSummary *GS);
> void printFunctionSummary(const FunctionSummary *FS);
> void printTypeIdSummary(const TypeIdSummary &TIS);
> + void printTypeIdMetadataSummary(const TypeIdGVInfo &TI);
> void printTypeTestResolution(const TypeTestResolution &TTRes);
> void printArgs(const std::vector<uint64_t> &Args);
> void printWPDRes(const WholeProgramDevirtResolution &WPDRes);
> @@ -2695,6 +2699,15 @@ void AssemblyWriter::printModuleSummaryI
> printTypeIdSummary(TidIter->second.second);
> Out << ") ; guid = " << TidIter->first << "\n";
> }
> +
> + // Print the TypeIdMetadataMap entries.
> + for (auto &TId : TheIndex->typeIdMetadataMap()) {
> + auto GUID = GlobalValue::getGUID(TId.first);
> + Out << "^" << Machine.getGUIDSlot(GUID) << " = typeidMetadata: (name:
> \""
> + << TId.first << "\"";
> + printTypeIdMetadataSummary(TId.second);
> + Out << ") ; guid = " << GUID << "\n";
> + }
> }
>
> static const char *
> @@ -2777,6 +2790,18 @@ void AssemblyWriter::printTypeIdSummary(
> Out << ")";
> }
>
> +void AssemblyWriter::printTypeIdMetadataSummary(const TypeIdGVInfo &TI) {
> + Out << ", summary: (";
> + FieldSeparator FS;
> + for (auto &P : TI) {
> + Out << FS;
> + Out << "(offset: " << P.first << ", ";
> + Out << "^" << Machine.getGUIDSlot(P.second.getGUID());
> + Out << ")";
> + }
> + Out << ")";
> +}
> +
> void AssemblyWriter::printArgs(const std::vector<uint64_t> &Args) {
> Out << "args: (";
> FieldSeparator FS;
> @@ -2846,6 +2871,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.first.getGUID())
> + << ", offset: " << P.second;
> + 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=351453&r1=351452&r2=351453&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp Thu Jan 17
> 07:49:03 2019
> @@ -418,34 +418,55 @@ 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);
> + else {
> + // 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=351453&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/Assembler/thinlto-vtable-summary.ll (added)
> +++ llvm/trunk/test/Assembler/thinlto-vtable-summary.ll Thu Jan 17
> 07:49:03 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),
> 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),
> varFlags: (readonly: 0), vTableFuncs: ((virtFunc: ^5, offset: 16),
> (virtFunc: ^1, offset: 24)), refs: (^1, ^5)))) ; guid = 13624023785555846296
> +^5 = gv: (name: "_ZN1C1fEi") ; guid = 14876272565662207556
> +^6 = typeidMetadata: (name: "_ZTS1A", summary: ((offset: 16, ^2),
> (offset: 16, ^4))) ; guid = 7004155349499253778
> +^7 = typeidMetadata: (name: "_ZTS1B", summary: ((offset: 16, ^2))) ; guid
> = 6203814149063363976
> +^8 = typeidMetadata: (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=351453&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/ThinLTO/X86/devirt.ll (added)
> +++ llvm/trunk/test/ThinLTO/X86/devirt.ll Thu Jan 17 07:49:03 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=typeidMetadata
> +; 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=typeidMetadata
> +; 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: typeidMetadata: (name: "_ZTS1A", summary:
> ((offset: 16, [[B]]), (offset: 16, [[C]])))
> +; NOENABLESPLITFLAG-DAG: typeidMetadata: (name: "_ZTS1B", summary:
> ((offset: 16, [[B]])))
> +; NOENABLESPLITFLAG-DAG: typeidMetadata: (name: "_ZTS1C", summary:
> ((offset: 16, [[C]])))
> +; Type Id on _ZTV1D should have been promoted
> +; NOENABLESPLITFLAG-DAG: typeidMetadata: (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=351453&r1=351452&r2=351453&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp (original)
> +++ llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp Thu Jan 17
> 07:49:03 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
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
--
Teresa Johnson | Software Engineer | tejohnson at google.com |
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20190117/0e5d9c03/attachment-0001.html>
More information about the llvm-commits
mailing list