Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -210,6 +210,10 @@ FS_COMBINED_PROFILE = 5, // COMBINED_GLOBALVAR_INIT_REFS: [modid, linkage, n x valueid] FS_COMBINED_GLOBALVAR_INIT_REFS = 6, + // ALIAS: [valueid, linkage, valueid] + FS_ALIAS = 7, + // ALIAS: [modid, linkage, offset] + FS_COMBINED_ALIAS = 8, }; enum MetadataCodes { Index: include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- include/llvm/IR/ModuleSummaryIndex.h +++ include/llvm/IR/ModuleSummaryIndex.h @@ -92,7 +92,7 @@ class GlobalValueSummary { public: /// \brief Sububclass discriminator (for dyn_cast<> et al.) - enum SummaryKind { FunctionKind, GlobalVarKind }; + enum SummaryKind { AliasKind, FunctionKind, GlobalVarKind }; private: /// Kind of summary for use in dyn_cast<> et al. @@ -168,6 +168,32 @@ const std::vector &refs() const { return RefEdgeList; } }; +/// \brief Alias summary information. +class AliasSummary : public GlobalValueSummary { + GlobalValueSummary *AliaseeSummary; + +public: + /// Summary constructors. + AliasSummary(GlobalValue::LinkageTypes Linkage) + : GlobalValueSummary(AliasKind, Linkage) {} + + /// Check if this is an alias summary. + static bool classof(const GlobalValueSummary *GVS) { + return GVS->getSummaryKind() == AliasKind; + } + + void setAliasee(GlobalValueSummary *Aliasee) { AliaseeSummary = Aliasee; } + + const GlobalValueSummary &getAliasee() const { + return const_cast(this)->getAliasee(); + } + + GlobalValueSummary &getAliasee() { + assert(AliaseeSummary && "Unexpected missing aliasee summary"); + return *AliaseeSummary; + } +}; + /// \brief Function summary information to aid decisions and implementation of /// importing. class FunctionSummary : public GlobalValueSummary { Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -5836,6 +5836,33 @@ Info->setSummary(std::move(FS)); break; } + // FS_ALIAS: [valueid, linkage, valueid] + case bitc::FS_ALIAS: { + unsigned ValueID = Record[0]; + uint64_t RawLinkage = Record[1]; + unsigned AliaseeID = Record[2]; + std::unique_ptr AS = + llvm::make_unique(getDecodedLinkage(RawLinkage)); + // The module path string ref set in the summary must be owned by the + // index's module string table. Since we don't have a module path + // string table section in the per-module index, we create a single + // module path string table entry with an empty (0) ID to take + // ownership. + AS->setModulePath( + TheIndex->addModulePath(Buffer->getBufferIdentifier(), 0)->first()); + + GlobalValue::GUID AliaseeGUID = getGUIDFromValueId(AliaseeID); + auto *AliaseeInfo = TheIndex->getGlobalValueInfo(AliaseeGUID); + if (!AliaseeInfo->summary()) + return error("Alias expects aliasee summary to be parsed"); + AS->setAliasee(AliaseeInfo->summary()); + + GlobalValue::GUID GUID = getGUIDFromValueId(ValueID); + auto *Info = TheIndex->getGlobalValueInfo(GUID); + assert(!Info->summary() && "Expected a single summary per VST entry"); + Info->setSummary(std::move(AS)); + break; + } // FS_PERMODULE_GLOBALVAR_INIT_REFS: [valueid, linkage, n x valueid] case bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS: { unsigned ValueID = Record[0]; @@ -5894,6 +5921,26 @@ Combined = true; break; } + // FS_COMBINED_ALIAS: [modid, linkage, offset] + case bitc::FS_COMBINED_ALIAS: { + uint64_t ModuleId = Record[0]; + uint64_t RawLinkage = Record[1]; + uint64_t AliaseeSummaryOffset = Record[2]; + std::unique_ptr AS = + llvm::make_unique(getDecodedLinkage(RawLinkage)); + AS->setModulePath(ModuleIdMap[ModuleId]); + + auto *AliaseeInfo = getInfoFromSummaryOffset(AliaseeSummaryOffset); + if (!AliaseeInfo->summary()) + return error("Alias expects aliasee summary to be parsed"); + AS->setAliasee(AliaseeInfo->summary()); + + auto *Info = getInfoFromSummaryOffset(CurRecordBit); + assert(!Info->summary() && "Expected a single summary per VST entry"); + Info->setSummary(std::move(AS)); + Combined = true; + break; + } // FS_COMBINED_GLOBALVAR_INIT_REFS: [modid, linkage, n x valueid] case bitc::FS_COMBINED_GLOBALVAR_INIT_REFS: { uint64_t ModuleId = Record[0]; Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2910,6 +2910,14 @@ Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); unsigned FSModRefsAbbrev = Stream.EmitAbbrev(Abbv); + // Abbrev for FS_ALIAS. + Abbv = new BitCodeAbbrev(); + Abbv->Add(BitCodeAbbrevOp(bitc::FS_ALIAS)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // valueid + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 5)); // linkage + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // valueid + unsigned FSAliasAbbrev = Stream.EmitAbbrev(Abbv); + SmallVector NameVals; // Iterate over the list of functions instead of the Index to // ensure the ordering is stable. @@ -2928,20 +2936,6 @@ FSCallsAbbrev, FSCallsProfileAbbrev, Stream, F); } - for (const GlobalAlias &A : M->aliases()) { - if (!A.getBaseObject()) - continue; - const Function *F = dyn_cast(A.getBaseObject()); - if (!F || F->isDeclaration()) - continue; - - auto *Info = Index.getGlobalValueInfo(A); - WritePerModuleFunctionSummaryRecord( - NameVals, Info, - VE.getValueID(M->getValueSymbolTable().lookup(A.getName())), VE, - FSCallsAbbrev, FSCallsProfileAbbrev, Stream, *F); - } - // Capture references from GlobalVariable initializers, which are outside // of a function scope. for (const GlobalVariable &G : M->globals()) @@ -2951,12 +2945,23 @@ WriteModuleLevelReferences(*GV, Index, VE, NameVals, FSModRefsAbbrev, Stream); + for (const GlobalAlias &A : M->aliases()) { + auto *Aliasee = A.getBaseObject(); + auto AliasId = VE.getValueID(&A); + auto AliaseeId = VE.getValueID(Aliasee); + NameVals.push_back(AliasId); + NameVals.push_back(getEncodedLinkage(A.getLinkage())); + NameVals.push_back(AliaseeId); + Stream.EmitRecord(bitc::FS_ALIAS, NameVals, FSAliasAbbrev); + NameVals.clear(); + } + Stream.ExitBlock(); } /// Emit the combined summary section into the combined index file. static void WriteCombinedGlobalValueSummary( - const ModuleSummaryIndex &I, BitstreamWriter &Stream, + const ModuleSummaryIndex &Index, BitstreamWriter &Stream, std::map &GUIDToValueIdMap, unsigned GlobalValueId) { Stream.EnterSubblock(bitc::GLOBALVAL_SUMMARY_BLOCK_ID, 3); @@ -2994,14 +2999,34 @@ Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); unsigned FSModRefsAbbrev = Stream.EmitAbbrev(Abbv); + // Abbrev for FS_COMBINED_ALIAS. + Abbv = new BitCodeAbbrev(); + Abbv->Add(BitCodeAbbrevOp(bitc::FS_COMBINED_ALIAS)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // modid + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 5)); // linkage + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // valueid + unsigned FSAliasAbbrev = Stream.EmitAbbrev(Abbv); + + // The aliases are emitted as a post-pass, and will point to the summary + // offset id of the aliasee. For this purpose we need to be able to get back + // from the summary to the offset + SmallVector Aliases; + DenseMap SummaryToOffsetMap; + SmallVector NameVals; - for (const auto &FII : I) { + for (const auto &FII : Index) { for (auto &FI : FII.second) { GlobalValueSummary *S = FI->summary(); assert(S); + if (isa(S)) { + // Will process aliases as a post-pass because the reader wants all + // global to be loaded first. + Aliases.push_back(FI.get()); + continue; + } if (auto *VS = dyn_cast(S)) { - NameVals.push_back(I.getModuleId(VS->modulePath())); + NameVals.push_back(Index.getModuleId(VS->modulePath())); NameVals.push_back(getEncodedLinkage(VS->linkage())); for (auto &RI : VS->refs()) { const auto &VMI = GUIDToValueIdMap.find(RI.getId()); @@ -3021,6 +3046,8 @@ // reader will invoke readRecord after the abbrev id read. FI->setBitcodeIndex(Stream.GetCurrentBitNo() + Stream.GetAbbrevIDWidth()); + // Store temporarily the offset in the map for a possible alias. + SummaryToOffsetMap[S] = FI->bitcodeIndex(); // Emit the finished record. Stream.EmitRecord(bitc::FS_COMBINED_GLOBALVAR_INIT_REFS, NameVals, @@ -3030,7 +3057,7 @@ } auto *FS = cast(S); - NameVals.push_back(I.getModuleId(FS->modulePath())); + NameVals.push_back(Index.getModuleId(FS->modulePath())); NameVals.push_back(getEncodedLinkage(FS->linkage())); NameVals.push_back(FS->instCount()); NameVals.push_back(FS->refs().size()); @@ -3072,6 +3099,8 @@ // in the VST entry. Add the current code size since the // reader will invoke readRecord after the abbrev id read. FI->setBitcodeIndex(Stream.GetCurrentBitNo() + Stream.GetAbbrevIDWidth()); + // Store temporarily the offset in the map for a possible alias. + SummaryToOffsetMap[S] = FI->bitcodeIndex(); unsigned FSAbbrev = (HasProfileData ? FSCallsProfileAbbrev : FSCallsAbbrev); @@ -3084,6 +3113,25 @@ } } + for (auto GVI : Aliases) { + AliasSummary *AS = cast(GVI->summary()); + NameVals.push_back(Index.getModuleId(AS->modulePath())); + NameVals.push_back(getEncodedLinkage(AS->linkage())); + auto AliaseeID = SummaryToOffsetMap[&AS->getAliasee()]; + assert(AliaseeID); + NameVals.push_back(AliaseeID); + + // Record the starting offset of this summary entry for use + // in the VST entry. Add the current code size since the + // reader will invoke readRecord after the abbrev id read. + GVI->setBitcodeIndex(Stream.GetCurrentBitNo() + Stream.GetAbbrevIDWidth()); + + // Emit the finished record. + Stream.EmitRecord(bitc::FS_COMBINED_ALIAS, NameVals, FSAliasAbbrev); + NameVals.clear(); + continue; + } + Stream.ExitBlock(); } Index: lib/Transforms/IPO/FunctionImport.cpp =================================================================== --- lib/Transforms/IPO/FunctionImport.cpp +++ lib/Transforms/IPO/FunctionImport.cpp @@ -79,13 +79,16 @@ /// number of source modules parsed/linked. /// - One that has PGO data attached. /// - [insert you fancy metric here] -static const FunctionSummary * +static const GlobalValueSummary * selectCallee(const GlobalValueInfoList &CalleeInfoList, unsigned Threshold) { auto It = llvm::find_if( CalleeInfoList, [&](const std::unique_ptr &GlobInfo) { assert(GlobInfo->summary() && "We should not have a Global Info without summary"); - auto *Summary = cast(GlobInfo->summary()); + auto *GVSummary = GlobInfo->summary(); + if (auto *AS = dyn_cast(GVSummary)) + GVSummary = &AS->getAliasee(); + auto *Summary = cast(GVSummary); if (GlobalValue::isWeakAnyLinkage(Summary->linkage())) return false; @@ -98,14 +101,14 @@ if (It == CalleeInfoList.end()) return nullptr; - return cast((*It)->summary()); + return cast((*It)->summary()); } /// Return the summary for the function \p GUID that fits the \p Threshold, or /// null if there's no match. -static const FunctionSummary *selectCallee(GlobalValue::GUID GUID, - unsigned Threshold, - const ModuleSummaryIndex &Index) { +static const GlobalValueSummary *selectCallee(GlobalValue::GUID GUID, + unsigned Threshold, + const ModuleSummaryIndex &Index) { auto CalleeInfoList = Index.findGlobalValueInfoList(GUID); if (CalleeInfoList == Index.end()) { return nullptr; // This function does not have a summary @@ -158,11 +161,19 @@ DEBUG(dbgs() << "ignored! No qualifying callee with summary found.\n"); continue; } - assert(CalleeSummary->instCount() <= Threshold && + // "Resolve" the summary, traversing alias, + const FunctionSummary *ResolvedCalleeSummary; + if (isa(CalleeSummary)) + ResolvedCalleeSummary = cast( + &cast(CalleeSummary)->getAliasee()); + else + ResolvedCalleeSummary = cast(CalleeSummary); + + assert(ResolvedCalleeSummary->instCount() <= Threshold && "selectCallee() didn't honor the threshold"); auto &ProcessedThreshold = - ImportsForModule[CalleeSummary->modulePath()][GUID]; + ImportsForModule[ResolvedCalleeSummary->modulePath()][GUID]; /// Since the traversal of the call graph is DFS, we can revisit a function /// a second time with a higher threshold. In this case, it is added back to /// the worklist with the new threshold. @@ -175,24 +186,24 @@ ProcessedThreshold = Threshold; // Make exports in the source module. - auto ExportModulePath = CalleeSummary->modulePath(); + auto ExportModulePath = ResolvedCalleeSummary->modulePath(); auto ExportList = ExportLists[ExportModulePath]; ExportList.insert(GUID); // Mark all functions and globals referenced by this function as exported to // the outside if they are defined in the same source module. - for (auto &Edge : CalleeSummary->calls()) { + for (auto &Edge : ResolvedCalleeSummary->calls()) { auto CalleeGUID = Edge.first.getId(); if (isGlobalExported(Index, ExportModulePath, CalleeGUID)) ExportList.insert(CalleeGUID); } - for (auto &Ref : CalleeSummary->refs()) { + for (auto &Ref : ResolvedCalleeSummary->refs()) { auto GUID = Ref.getId(); if (isGlobalExported(Index, ExportModulePath, GUID)) ExportList.insert(GUID); } // Insert the newly imported function to the worklist. - Worklist.push_back(std::make_pair(CalleeSummary, Threshold)); + Worklist.push_back(std::make_pair(ResolvedCalleeSummary, Threshold)); } } Index: test/Bitcode/thinlto-function-summary.ll =================================================================== --- test/Bitcode/thinlto-function-summary.ll +++ test/Bitcode/thinlto-function-summary.ll @@ -7,7 +7,7 @@ ; BC: record string = 'foo' Index: tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp =================================================================== --- tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -308,6 +308,8 @@ STRINGIFY_CODE(FS, COMBINED) STRINGIFY_CODE(FS, COMBINED_PROFILE) STRINGIFY_CODE(FS, COMBINED_GLOBALVAR_INIT_REFS) + STRINGIFY_CODE(FS, ALIAS) + STRINGIFY_CODE(FS, COMBINED_ALIAS) } case bitc::METADATA_ATTACHMENT_ID: switch(CodeID) {