Index: include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- include/llvm/IR/ModuleSummaryIndex.h +++ include/llvm/IR/ModuleSummaryIndex.h @@ -73,6 +73,9 @@ /// per-module summaries. const GlobalValue *GV = nullptr; + /// Summary string representation. Valid for combined summaries + StringRef Name; + /// List of global value summary structures for a particular value held /// in the GlobalValueMap. Requires a vector in the case of multiple /// COMDAT values of the same name. @@ -104,6 +107,10 @@ ArrayRef> getSummaryList() const { return Ref->second.SummaryList; } + + StringRef name() const { + return Ref->second.GV ? Ref->second.GV->getName() : Ref->second.Name; + } }; template <> struct DenseMapInfo { @@ -660,6 +667,13 @@ return ValueInfo(getOrInsertValuePtr(GUID)); } + /// Return a ValueInfo for \p GUID setting value \p Name. + ValueInfo getOrInsertValueInfo(GlobalValue::GUID GUID, StringRef Name) { + auto VP = getOrInsertValuePtr(GUID); + VP->second.Name = Name; + return ValueInfo(VP); + } + /// Return a ValueInfo for \p GV and mark it as belonging to GV. ValueInfo getOrInsertValueInfo(const GlobalValue *GV) { auto VP = getOrInsertValuePtr(GV->getGUID()); @@ -823,6 +837,9 @@ /// Summary). void collectDefinedGVSummariesPerModule( StringMap &ModuleToDefinedGVSummaries) const; + + /// Export summary to dot file for GraphViz. + void exportToDot(raw_ostream& OS) const; }; } // end namespace llvm Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -4810,8 +4810,8 @@ if (PrintSummaryGUIDs) dbgs() << "GUID " << ValueGUID << "(" << OriginalNameID << ") is " << ValueName << "\n"; - ValueIdToValueInfoMap[ValueID] = - std::make_pair(TheIndex.getOrInsertValueInfo(ValueGUID), OriginalNameID); + ValueIdToValueInfoMap[ValueID] = std::make_pair( + TheIndex.getOrInsertValueInfo(ValueGUID, ValueName), OriginalNameID); } // Specialized value symbol table parser used when reading module index Index: lib/IR/ModuleSummaryIndex.cpp =================================================================== --- lib/IR/ModuleSummaryIndex.cpp +++ lib/IR/ModuleSummaryIndex.cpp @@ -69,3 +69,219 @@ return true; return false; } + +namespace { +struct Attributes { + void add(const Twine &Name, const Twine &Value); + std::string getAsString() const; + + std::vector Attrs; +}; + +struct Edge { + int SrcMod; + int Hotness; + GlobalValue::GUID Src; + GlobalValue::GUID Dst; +}; +} + +void Attributes::add(const Twine& Name, const Twine& Value) { + std::string A = Name.str(); + A += "=\""; + A += Value.str(); + A += "\""; + Attrs.push_back(A); +} + +std::string Attributes::getAsString() const { + if (Attrs.empty()) + return ""; + + std::string Ret = "["; + for (auto &A : Attrs) + Ret += A + ","; + Ret.pop_back(); + Ret += "]"; + return Ret; +} + +static std::string linkageToString(GlobalValue::LinkageTypes LT) { + switch (LT) { + case GlobalValue::ExternalLinkage: + return "extern"; + case GlobalValue::AvailableExternallyLinkage: + return "av_ext"; + case GlobalValue::LinkOnceAnyLinkage: + return "linkonce"; + case GlobalValue::LinkOnceODRLinkage: + return "linkonce_odr"; + case GlobalValue::WeakAnyLinkage: + return "weak"; + case GlobalValue::WeakODRLinkage: + return "weak_odr"; + case GlobalValue::AppendingLinkage: + return "appending"; + case GlobalValue::InternalLinkage: + return "internal"; + case GlobalValue::PrivateLinkage: + return "private"; + case GlobalValue::ExternalWeakLinkage: + return "extern_weak"; + case GlobalValue::CommonLinkage: + return "common"; + } + + return ""; +} + +static std::string fflagsToString(FunctionSummary::FFlags F) { + auto FlagValue = [](unsigned V) { return V ? '1' : '0'; }; + char FlagRep[] = {FlagValue(F.ReadNone), FlagValue(F.ReadOnly), + FlagValue(F.NoRecurse), FlagValue(F.ReturnDoesNotAlias), 0}; + + return FlagRep; +} + +// Get string representation of function instruction count and flags. +static std::string getSummaryAttributes(GlobalValueSummary* GVS) { + auto *FS = dyn_cast_or_null(GVS); + if (!FS) + return ""; + + return std::string("inst: ") + std::to_string(FS->instCount()) + + ", ffl: " + fflagsToString(FS->fflags()); +} + +static std::string getNodeVisualName(const ValueInfo &VI) { + return VI.name().empty() ? std::string("@") + std::to_string(VI.getGUID()) + : VI.name().str(); +} + +// Get node label in form MXXX_. The MXXX prefix is required, +// because we may have multiple linkonce functions summaries. +static std::string getNodeLabel(const ValueInfo &VI, GlobalValueSummary *GVS) { + if (isa(GVS)) + return getNodeVisualName(VI); + + std::string Attrs = getSummaryAttributes(GVS); + std::string Label = + getNodeVisualName(VI) + "|" + linkageToString(GVS->linkage()); + if (!Attrs.empty()) + Label += std::string(" (") + Attrs + ")"; + Label += "}"; + + return Label; +} + +// Write definition of node without ValueInfo. This is typically +// an external function or variable +static void defineExternalNode(raw_ostream &OS, const char *Pfx, + const ValueInfo &VI) { + auto StrId = std::to_string(VI.getGUID()); + OS << " " << StrId << " [label=\"" << getNodeVisualName(VI) << "\"];\n"; +} + +void ModuleSummaryIndex::exportToDot(raw_ostream& OS) const { + std::vector CrossModuleEdges; + DenseMap> NodeMap; + StringMap ModuleToDefinedGVS; + collectDefinedGVSummariesPerModule(ModuleToDefinedGVS); + + auto NodeId = [](int ModNum, GlobalValue::GUID Id) { + return ModNum < 0 ? std::to_string(Id) + : std::string("M") + std::to_string(ModNum) + "_" + + std::to_string(Id); + }; + + auto DrawEdge = [&](const char *Pfx, int SrcMod, GlobalValue::GUID SrcId, + int DstMod, GlobalValue::GUID DstId, int Hotness) { + ++Hotness; // 0 corresponds to ref edge, 1 to call with unknown hotness, ... + static const char *EdgeAttrs[] = { + " [style=dashed]", "", " [color=blue]", "", " [color=brown]", + " [style=bold,color=read]"}; + + assert(static_cast(Hotness) < + sizeof(EdgeAttrs) / sizeof(EdgeAttrs[0])); + OS << Pfx << NodeId(SrcMod, SrcId) << " -> " << NodeId(DstMod, DstId) + << EdgeAttrs[Hotness] << "; // " << std::to_string(SrcId) << " -> " + << std::to_string(DstId) << "\n"; + }; + + int ModNum = 0; + OS << "digraph Summary {\n"; + for (auto &ModIt : ModuleToDefinedGVS) { + OS << " subgraph cluster_" << std::to_string(ModNum) << " {\n"; + OS << " style = filled;\n"; + OS << " color = lightgrey;\n"; + OS << " label = \"" << ModIt.first() << "\";\n"; + OS << " node [style=filled,fillcolor=lightblue];\n"; + + auto &GVSMap = ModIt.second; + auto Draw = [&](GlobalValue::GUID IdFrom, GlobalValue::GUID IdTo, int Hotness) { + if (!GVSMap.count(IdTo)) { + CrossModuleEdges.push_back({ModNum, Hotness, IdFrom, IdTo}); + return; + } + DrawEdge(" ", ModNum, IdFrom, ModNum, IdTo, Hotness); + }; + + for (auto &SummaryIt : GVSMap) { + NodeMap[SummaryIt.first].push_back(ModNum); + auto Flags = SummaryIt.second->flags(); + Attributes A; + if (isa(SummaryIt.second)) { + A.add("shape", "record"); + } else if (isa(SummaryIt.second)) { + A.add("style", "dotted,filled"); + A.add("shape", "box"); + } else { + A.add("shape", "Mrecord"); + } + + auto VI = getValueInfo(SummaryIt.first); + A.add("label", getNodeLabel(VI, SummaryIt.second)); + if (!Flags.Live) + A.add("fillcolor", "red"); + else if (Flags.NotEligibleToImport) + A.add("fillcolor", "yellow"); + + OS << " " << NodeId(ModNum, SummaryIt.first) << " " << A.getAsString() + << ";\n"; + } + + for (auto &SummaryIt : GVSMap) { + auto *GVS = SummaryIt.second; + for (auto &R : GVS->refs()) + Draw(SummaryIt.first, R.getGUID(), -1); + + if (auto *AS = dyn_cast_or_null(SummaryIt.second)) { + auto AliaseeOrigId = AS->getAliasee().getOriginalName(); + auto AliaseeId = getGUIDFromOriginalID(AliaseeOrigId); + + Draw(SummaryIt.first, AliaseeId ? AliaseeId : AliaseeOrigId, -1); + continue; + } + + if (auto *FS = dyn_cast_or_null(SummaryIt.second)) + for (auto &CGEdge : FS->calls()) + Draw(SummaryIt.first, CGEdge.first.getGUID(), + static_cast(CGEdge.second.Hotness)); + } + OS << " }\n"; + ++ModNum; + } + + for (auto &E : CrossModuleEdges) { + auto &ModList = NodeMap[E.Dst]; + if (ModList.empty()) { + defineExternalNode(OS, " ", getValueInfo(E.Dst)); + ModList.push_back(-1); + } + for (int DstMod : ModList) + if (DstMod != E.SrcMod) + DrawEdge(" ", E.SrcMod, E.Src, DstMod, E.Dst, E.Hotness); + } + + OS << "}"; +} Index: lib/LTO/LTOBackend.cpp =================================================================== --- lib/LTO/LTOBackend.cpp +++ lib/LTO/LTOBackend.cpp @@ -103,6 +103,12 @@ if (EC) reportOpenError(Path, EC.message()); WriteIndexToFile(Index, OS); + + Path = OutputFileName + "index.dot"; + raw_fd_ostream OSDot(Path, EC, sys::fs::OpenFlags::F_None); + if (EC) + reportOpenError(Path, EC.message()); + Index.exportToDot(OSDot); return true; };