13ca95b02SDimitry Andric //===-- ModuleSummaryIndex.cpp - Module Summary Index ---------------------===//
23ca95b02SDimitry Andric //
33ca95b02SDimitry Andric // The LLVM Compiler Infrastructure
43ca95b02SDimitry Andric //
53ca95b02SDimitry Andric // This file is distributed under the University of Illinois Open Source
63ca95b02SDimitry Andric // License. See LICENSE.TXT for details.
73ca95b02SDimitry Andric //
83ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
93ca95b02SDimitry Andric //
103ca95b02SDimitry Andric // This file implements the module index and summary classes for the
113ca95b02SDimitry Andric // IR library.
123ca95b02SDimitry Andric //
133ca95b02SDimitry Andric //===----------------------------------------------------------------------===//
143ca95b02SDimitry Andric
153ca95b02SDimitry Andric #include "llvm/IR/ModuleSummaryIndex.h"
164ba319b5SDimitry Andric #include "llvm/ADT/SCCIterator.h"
17*b5893f02SDimitry Andric #include "llvm/ADT/Statistic.h"
183ca95b02SDimitry Andric #include "llvm/ADT/StringMap.h"
194ba319b5SDimitry Andric #include "llvm/Support/Path.h"
204ba319b5SDimitry Andric #include "llvm/Support/raw_ostream.h"
213ca95b02SDimitry Andric using namespace llvm;
223ca95b02SDimitry Andric
23*b5893f02SDimitry Andric #define DEBUG_TYPE "module-summary-index"
24*b5893f02SDimitry Andric
25*b5893f02SDimitry Andric STATISTIC(ReadOnlyLiveGVars,
26*b5893f02SDimitry Andric "Number of live global variables marked read only");
27*b5893f02SDimitry Andric
284ba319b5SDimitry Andric FunctionSummary FunctionSummary::ExternalNode =
294ba319b5SDimitry Andric FunctionSummary::makeDummyFunctionSummary({});
isDSOLocal() const304ba319b5SDimitry Andric bool ValueInfo::isDSOLocal() const {
314ba319b5SDimitry Andric // Need to check all summaries are local in case of hash collisions.
324ba319b5SDimitry Andric return getSummaryList().size() &&
334ba319b5SDimitry Andric llvm::all_of(getSummaryList(),
344ba319b5SDimitry Andric [](const std::unique_ptr<GlobalValueSummary> &Summary) {
354ba319b5SDimitry Andric return Summary->isDSOLocal();
364ba319b5SDimitry Andric });
374ba319b5SDimitry Andric }
384ba319b5SDimitry Andric
39*b5893f02SDimitry Andric // Gets the number of immutable refs in RefEdgeList
immutableRefCount() const40*b5893f02SDimitry Andric unsigned FunctionSummary::immutableRefCount() const {
41*b5893f02SDimitry Andric // Here we take advantage of having all readonly references
42*b5893f02SDimitry Andric // located in the end of the RefEdgeList.
43*b5893f02SDimitry Andric auto Refs = refs();
44*b5893f02SDimitry Andric unsigned ImmutableRefCnt = 0;
45*b5893f02SDimitry Andric for (int I = Refs.size() - 1; I >= 0 && Refs[I].isReadOnly(); --I)
46*b5893f02SDimitry Andric ImmutableRefCnt++;
47*b5893f02SDimitry Andric return ImmutableRefCnt;
48*b5893f02SDimitry Andric }
49*b5893f02SDimitry Andric
503ca95b02SDimitry Andric // Collect for the given module the list of function it defines
513ca95b02SDimitry Andric // (GUID -> Summary).
collectDefinedFunctionsForModule(StringRef ModulePath,GVSummaryMapTy & GVSummaryMap) const523ca95b02SDimitry Andric void ModuleSummaryIndex::collectDefinedFunctionsForModule(
533ca95b02SDimitry Andric StringRef ModulePath, GVSummaryMapTy &GVSummaryMap) const {
543ca95b02SDimitry Andric for (auto &GlobalList : *this) {
553ca95b02SDimitry Andric auto GUID = GlobalList.first;
560f5676f4SDimitry Andric for (auto &GlobSummary : GlobalList.second.SummaryList) {
573ca95b02SDimitry Andric auto *Summary = dyn_cast_or_null<FunctionSummary>(GlobSummary.get());
583ca95b02SDimitry Andric if (!Summary)
593ca95b02SDimitry Andric // Ignore global variable, focus on functions
603ca95b02SDimitry Andric continue;
613ca95b02SDimitry Andric // Ignore summaries from other modules.
623ca95b02SDimitry Andric if (Summary->modulePath() != ModulePath)
633ca95b02SDimitry Andric continue;
643ca95b02SDimitry Andric GVSummaryMap[GUID] = Summary;
653ca95b02SDimitry Andric }
663ca95b02SDimitry Andric }
673ca95b02SDimitry Andric }
683ca95b02SDimitry Andric
693ca95b02SDimitry Andric // Collect for each module the list of function it defines (GUID -> Summary).
collectDefinedGVSummariesPerModule(StringMap<GVSummaryMapTy> & ModuleToDefinedGVSummaries) const703ca95b02SDimitry Andric void ModuleSummaryIndex::collectDefinedGVSummariesPerModule(
713ca95b02SDimitry Andric StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries) const {
723ca95b02SDimitry Andric for (auto &GlobalList : *this) {
733ca95b02SDimitry Andric auto GUID = GlobalList.first;
740f5676f4SDimitry Andric for (auto &Summary : GlobalList.second.SummaryList) {
753ca95b02SDimitry Andric ModuleToDefinedGVSummaries[Summary->modulePath()][GUID] = Summary.get();
763ca95b02SDimitry Andric }
773ca95b02SDimitry Andric }
783ca95b02SDimitry Andric }
793ca95b02SDimitry Andric
803ca95b02SDimitry Andric GlobalValueSummary *
getGlobalValueSummary(uint64_t ValueGUID,bool PerModuleIndex) const813ca95b02SDimitry Andric ModuleSummaryIndex::getGlobalValueSummary(uint64_t ValueGUID,
823ca95b02SDimitry Andric bool PerModuleIndex) const {
830f5676f4SDimitry Andric auto VI = getValueInfo(ValueGUID);
840f5676f4SDimitry Andric assert(VI && "GlobalValue not found in index");
850f5676f4SDimitry Andric assert((!PerModuleIndex || VI.getSummaryList().size() == 1) &&
863ca95b02SDimitry Andric "Expected a single entry per global value in per-module index");
870f5676f4SDimitry Andric auto &Summary = VI.getSummaryList()[0];
883ca95b02SDimitry Andric return Summary.get();
893ca95b02SDimitry Andric }
9024d58133SDimitry Andric
isGUIDLive(GlobalValue::GUID GUID) const9124d58133SDimitry Andric bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID) const {
9224d58133SDimitry Andric auto VI = getValueInfo(GUID);
9324d58133SDimitry Andric if (!VI)
9424d58133SDimitry Andric return true;
9524d58133SDimitry Andric const auto &SummaryList = VI.getSummaryList();
9624d58133SDimitry Andric if (SummaryList.empty())
9724d58133SDimitry Andric return true;
9824d58133SDimitry Andric for (auto &I : SummaryList)
9924d58133SDimitry Andric if (isGlobalValueLive(I.get()))
10024d58133SDimitry Andric return true;
10124d58133SDimitry Andric return false;
10224d58133SDimitry Andric }
1034ba319b5SDimitry Andric
propagateConstantsToRefs(GlobalValueSummary * S)104*b5893f02SDimitry Andric static void propagateConstantsToRefs(GlobalValueSummary *S) {
105*b5893f02SDimitry Andric // If reference is not readonly then referenced summary is not
106*b5893f02SDimitry Andric // readonly either. Note that:
107*b5893f02SDimitry Andric // - All references from GlobalVarSummary are conservatively considered as
108*b5893f02SDimitry Andric // not readonly. Tracking them properly requires more complex analysis
109*b5893f02SDimitry Andric // then we have now.
110*b5893f02SDimitry Andric //
111*b5893f02SDimitry Andric // - AliasSummary objects have no refs at all so this function is a no-op
112*b5893f02SDimitry Andric // for them.
113*b5893f02SDimitry Andric for (auto &VI : S->refs()) {
114*b5893f02SDimitry Andric if (VI.isReadOnly()) {
115*b5893f02SDimitry Andric // We only mark refs as readonly when computing function summaries on
116*b5893f02SDimitry Andric // analysis phase.
117*b5893f02SDimitry Andric assert(isa<FunctionSummary>(S));
118*b5893f02SDimitry Andric continue;
119*b5893f02SDimitry Andric }
120*b5893f02SDimitry Andric for (auto &Ref : VI.getSummaryList())
121*b5893f02SDimitry Andric // If references to alias is not readonly then aliasee is not readonly
122*b5893f02SDimitry Andric if (auto *GVS = dyn_cast<GlobalVarSummary>(Ref->getBaseObject()))
123*b5893f02SDimitry Andric GVS->setReadOnly(false);
124*b5893f02SDimitry Andric }
125*b5893f02SDimitry Andric }
126*b5893f02SDimitry Andric
127*b5893f02SDimitry Andric // Do the constant propagation in combined index.
128*b5893f02SDimitry Andric // The goal of constant propagation is internalization of readonly
129*b5893f02SDimitry Andric // variables. To determine which variables are readonly and which
130*b5893f02SDimitry Andric // are not we take following steps:
131*b5893f02SDimitry Andric // - During analysis we speculatively assign readonly attribute to
132*b5893f02SDimitry Andric // all variables which can be internalized. When computing function
133*b5893f02SDimitry Andric // summary we also assign readonly attribute to a reference if
134*b5893f02SDimitry Andric // function doesn't modify referenced variable.
135*b5893f02SDimitry Andric //
136*b5893f02SDimitry Andric // - After computing dead symbols in combined index we do the constant
137*b5893f02SDimitry Andric // propagation. During this step we clear readonly attribute from
138*b5893f02SDimitry Andric // all variables which:
139*b5893f02SDimitry Andric // a. are preserved or can't be imported
140*b5893f02SDimitry Andric // b. referenced by any global variable initializer
141*b5893f02SDimitry Andric // c. referenced by a function and reference is not readonly
142*b5893f02SDimitry Andric //
143*b5893f02SDimitry Andric // Internalization itself happens in the backend after import is finished
144*b5893f02SDimitry Andric // See internalizeImmutableGVs.
propagateConstants(const DenseSet<GlobalValue::GUID> & GUIDPreservedSymbols)145*b5893f02SDimitry Andric void ModuleSummaryIndex::propagateConstants(
146*b5893f02SDimitry Andric const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) {
147*b5893f02SDimitry Andric for (auto &P : *this)
148*b5893f02SDimitry Andric for (auto &S : P.second.SummaryList) {
149*b5893f02SDimitry Andric if (!isGlobalValueLive(S.get()))
150*b5893f02SDimitry Andric // We don't examine references from dead objects
151*b5893f02SDimitry Andric continue;
152*b5893f02SDimitry Andric
153*b5893f02SDimitry Andric // Global variable can't be marked read only if it is not eligible
154*b5893f02SDimitry Andric // to import since we need to ensure that all external references
155*b5893f02SDimitry Andric // get a local (imported) copy. It also can't be marked read only
156*b5893f02SDimitry Andric // if it or any alias (since alias points to the same memory) are
157*b5893f02SDimitry Andric // preserved or notEligibleToImport, since either of those means
158*b5893f02SDimitry Andric // there could be writes that are not visible (because preserved
159*b5893f02SDimitry Andric // means it could have external to DSO writes, and notEligibleToImport
160*b5893f02SDimitry Andric // means it could have writes via inline assembly leading it to be
161*b5893f02SDimitry Andric // in the @llvm.*used).
162*b5893f02SDimitry Andric if (auto *GVS = dyn_cast<GlobalVarSummary>(S->getBaseObject()))
163*b5893f02SDimitry Andric // Here we intentionally pass S.get() not GVS, because S could be
164*b5893f02SDimitry Andric // an alias.
165*b5893f02SDimitry Andric if (!canImportGlobalVar(S.get()) || GUIDPreservedSymbols.count(P.first))
166*b5893f02SDimitry Andric GVS->setReadOnly(false);
167*b5893f02SDimitry Andric propagateConstantsToRefs(S.get());
168*b5893f02SDimitry Andric }
169*b5893f02SDimitry Andric if (llvm::AreStatisticsEnabled())
170*b5893f02SDimitry Andric for (auto &P : *this)
171*b5893f02SDimitry Andric if (P.second.SummaryList.size())
172*b5893f02SDimitry Andric if (auto *GVS = dyn_cast<GlobalVarSummary>(
173*b5893f02SDimitry Andric P.second.SummaryList[0]->getBaseObject()))
174*b5893f02SDimitry Andric if (isGlobalValueLive(GVS) && GVS->isReadOnly())
175*b5893f02SDimitry Andric ReadOnlyLiveGVars++;
176*b5893f02SDimitry Andric }
177*b5893f02SDimitry Andric
1784ba319b5SDimitry Andric // TODO: write a graphviz dumper for SCCs (see ModuleSummaryIndex::exportToDot)
1794ba319b5SDimitry Andric // then delete this function and update its tests
1804ba319b5SDimitry Andric LLVM_DUMP_METHOD
dumpSCCs(raw_ostream & O)1814ba319b5SDimitry Andric void ModuleSummaryIndex::dumpSCCs(raw_ostream &O) {
1824ba319b5SDimitry Andric for (scc_iterator<ModuleSummaryIndex *> I =
1834ba319b5SDimitry Andric scc_begin<ModuleSummaryIndex *>(this);
1844ba319b5SDimitry Andric !I.isAtEnd(); ++I) {
1854ba319b5SDimitry Andric O << "SCC (" << utostr(I->size()) << " node" << (I->size() == 1 ? "" : "s")
1864ba319b5SDimitry Andric << ") {\n";
1874ba319b5SDimitry Andric for (const ValueInfo V : *I) {
1884ba319b5SDimitry Andric FunctionSummary *F = nullptr;
1894ba319b5SDimitry Andric if (V.getSummaryList().size())
1904ba319b5SDimitry Andric F = cast<FunctionSummary>(V.getSummaryList().front().get());
1914ba319b5SDimitry Andric O << " " << (F == nullptr ? "External" : "") << " " << utostr(V.getGUID())
1924ba319b5SDimitry Andric << (I.hasLoop() ? " (has loop)" : "") << "\n";
1934ba319b5SDimitry Andric }
1944ba319b5SDimitry Andric O << "}\n";
1954ba319b5SDimitry Andric }
1964ba319b5SDimitry Andric }
1974ba319b5SDimitry Andric
1984ba319b5SDimitry Andric namespace {
1994ba319b5SDimitry Andric struct Attributes {
2004ba319b5SDimitry Andric void add(const Twine &Name, const Twine &Value,
2014ba319b5SDimitry Andric const Twine &Comment = Twine());
202*b5893f02SDimitry Andric void addComment(const Twine &Comment);
2034ba319b5SDimitry Andric std::string getAsString() const;
2044ba319b5SDimitry Andric
2054ba319b5SDimitry Andric std::vector<std::string> Attrs;
2064ba319b5SDimitry Andric std::string Comments;
2074ba319b5SDimitry Andric };
2084ba319b5SDimitry Andric
2094ba319b5SDimitry Andric struct Edge {
2104ba319b5SDimitry Andric uint64_t SrcMod;
2114ba319b5SDimitry Andric int Hotness;
2124ba319b5SDimitry Andric GlobalValue::GUID Src;
2134ba319b5SDimitry Andric GlobalValue::GUID Dst;
2144ba319b5SDimitry Andric };
2154ba319b5SDimitry Andric }
2164ba319b5SDimitry Andric
add(const Twine & Name,const Twine & Value,const Twine & Comment)2174ba319b5SDimitry Andric void Attributes::add(const Twine &Name, const Twine &Value,
2184ba319b5SDimitry Andric const Twine &Comment) {
2194ba319b5SDimitry Andric std::string A = Name.str();
2204ba319b5SDimitry Andric A += "=\"";
2214ba319b5SDimitry Andric A += Value.str();
2224ba319b5SDimitry Andric A += "\"";
2234ba319b5SDimitry Andric Attrs.push_back(A);
224*b5893f02SDimitry Andric addComment(Comment);
225*b5893f02SDimitry Andric }
226*b5893f02SDimitry Andric
addComment(const Twine & Comment)227*b5893f02SDimitry Andric void Attributes::addComment(const Twine &Comment) {
2284ba319b5SDimitry Andric if (!Comment.isTriviallyEmpty()) {
2294ba319b5SDimitry Andric if (Comments.empty())
2304ba319b5SDimitry Andric Comments = " // ";
2314ba319b5SDimitry Andric else
2324ba319b5SDimitry Andric Comments += ", ";
2334ba319b5SDimitry Andric Comments += Comment.str();
2344ba319b5SDimitry Andric }
2354ba319b5SDimitry Andric }
2364ba319b5SDimitry Andric
getAsString() const2374ba319b5SDimitry Andric std::string Attributes::getAsString() const {
2384ba319b5SDimitry Andric if (Attrs.empty())
2394ba319b5SDimitry Andric return "";
2404ba319b5SDimitry Andric
2414ba319b5SDimitry Andric std::string Ret = "[";
2424ba319b5SDimitry Andric for (auto &A : Attrs)
2434ba319b5SDimitry Andric Ret += A + ",";
2444ba319b5SDimitry Andric Ret.pop_back();
2454ba319b5SDimitry Andric Ret += "];";
2464ba319b5SDimitry Andric Ret += Comments;
2474ba319b5SDimitry Andric return Ret;
2484ba319b5SDimitry Andric }
2494ba319b5SDimitry Andric
linkageToString(GlobalValue::LinkageTypes LT)2504ba319b5SDimitry Andric static std::string linkageToString(GlobalValue::LinkageTypes LT) {
2514ba319b5SDimitry Andric switch (LT) {
2524ba319b5SDimitry Andric case GlobalValue::ExternalLinkage:
2534ba319b5SDimitry Andric return "extern";
2544ba319b5SDimitry Andric case GlobalValue::AvailableExternallyLinkage:
2554ba319b5SDimitry Andric return "av_ext";
2564ba319b5SDimitry Andric case GlobalValue::LinkOnceAnyLinkage:
2574ba319b5SDimitry Andric return "linkonce";
2584ba319b5SDimitry Andric case GlobalValue::LinkOnceODRLinkage:
2594ba319b5SDimitry Andric return "linkonce_odr";
2604ba319b5SDimitry Andric case GlobalValue::WeakAnyLinkage:
2614ba319b5SDimitry Andric return "weak";
2624ba319b5SDimitry Andric case GlobalValue::WeakODRLinkage:
2634ba319b5SDimitry Andric return "weak_odr";
2644ba319b5SDimitry Andric case GlobalValue::AppendingLinkage:
2654ba319b5SDimitry Andric return "appending";
2664ba319b5SDimitry Andric case GlobalValue::InternalLinkage:
2674ba319b5SDimitry Andric return "internal";
2684ba319b5SDimitry Andric case GlobalValue::PrivateLinkage:
2694ba319b5SDimitry Andric return "private";
2704ba319b5SDimitry Andric case GlobalValue::ExternalWeakLinkage:
2714ba319b5SDimitry Andric return "extern_weak";
2724ba319b5SDimitry Andric case GlobalValue::CommonLinkage:
2734ba319b5SDimitry Andric return "common";
2744ba319b5SDimitry Andric }
2754ba319b5SDimitry Andric
2764ba319b5SDimitry Andric return "<unknown>";
2774ba319b5SDimitry Andric }
2784ba319b5SDimitry Andric
fflagsToString(FunctionSummary::FFlags F)2794ba319b5SDimitry Andric static std::string fflagsToString(FunctionSummary::FFlags F) {
2804ba319b5SDimitry Andric auto FlagValue = [](unsigned V) { return V ? '1' : '0'; };
2814ba319b5SDimitry Andric char FlagRep[] = {FlagValue(F.ReadNone), FlagValue(F.ReadOnly),
282*b5893f02SDimitry Andric FlagValue(F.NoRecurse), FlagValue(F.ReturnDoesNotAlias),
283*b5893f02SDimitry Andric FlagValue(F.NoInline), 0};
2844ba319b5SDimitry Andric
2854ba319b5SDimitry Andric return FlagRep;
2864ba319b5SDimitry Andric }
2874ba319b5SDimitry Andric
2884ba319b5SDimitry Andric // Get string representation of function instruction count and flags.
getSummaryAttributes(GlobalValueSummary * GVS)2894ba319b5SDimitry Andric static std::string getSummaryAttributes(GlobalValueSummary* GVS) {
2904ba319b5SDimitry Andric auto *FS = dyn_cast_or_null<FunctionSummary>(GVS);
2914ba319b5SDimitry Andric if (!FS)
2924ba319b5SDimitry Andric return "";
2934ba319b5SDimitry Andric
2944ba319b5SDimitry Andric return std::string("inst: ") + std::to_string(FS->instCount()) +
2954ba319b5SDimitry Andric ", ffl: " + fflagsToString(FS->fflags());
2964ba319b5SDimitry Andric }
2974ba319b5SDimitry Andric
getNodeVisualName(GlobalValue::GUID Id)298*b5893f02SDimitry Andric static std::string getNodeVisualName(GlobalValue::GUID Id) {
299*b5893f02SDimitry Andric return std::string("@") + std::to_string(Id);
300*b5893f02SDimitry Andric }
301*b5893f02SDimitry Andric
getNodeVisualName(const ValueInfo & VI)3024ba319b5SDimitry Andric static std::string getNodeVisualName(const ValueInfo &VI) {
303*b5893f02SDimitry Andric return VI.name().empty() ? getNodeVisualName(VI.getGUID()) : VI.name().str();
3044ba319b5SDimitry Andric }
3054ba319b5SDimitry Andric
getNodeLabel(const ValueInfo & VI,GlobalValueSummary * GVS)3064ba319b5SDimitry Andric static std::string getNodeLabel(const ValueInfo &VI, GlobalValueSummary *GVS) {
3074ba319b5SDimitry Andric if (isa<AliasSummary>(GVS))
3084ba319b5SDimitry Andric return getNodeVisualName(VI);
3094ba319b5SDimitry Andric
3104ba319b5SDimitry Andric std::string Attrs = getSummaryAttributes(GVS);
3114ba319b5SDimitry Andric std::string Label =
3124ba319b5SDimitry Andric getNodeVisualName(VI) + "|" + linkageToString(GVS->linkage());
3134ba319b5SDimitry Andric if (!Attrs.empty())
3144ba319b5SDimitry Andric Label += std::string(" (") + Attrs + ")";
3154ba319b5SDimitry Andric Label += "}";
3164ba319b5SDimitry Andric
3174ba319b5SDimitry Andric return Label;
3184ba319b5SDimitry Andric }
3194ba319b5SDimitry Andric
3204ba319b5SDimitry Andric // Write definition of external node, which doesn't have any
3214ba319b5SDimitry Andric // specific module associated with it. Typically this is function
3224ba319b5SDimitry Andric // or variable defined in native object or library.
defineExternalNode(raw_ostream & OS,const char * Pfx,const ValueInfo & VI,GlobalValue::GUID Id)3234ba319b5SDimitry Andric static void defineExternalNode(raw_ostream &OS, const char *Pfx,
324*b5893f02SDimitry Andric const ValueInfo &VI, GlobalValue::GUID Id) {
325*b5893f02SDimitry Andric auto StrId = std::to_string(Id);
326*b5893f02SDimitry Andric OS << " " << StrId << " [label=\"";
327*b5893f02SDimitry Andric
328*b5893f02SDimitry Andric if (VI) {
329*b5893f02SDimitry Andric OS << getNodeVisualName(VI);
330*b5893f02SDimitry Andric } else {
331*b5893f02SDimitry Andric OS << getNodeVisualName(Id);
332*b5893f02SDimitry Andric }
333*b5893f02SDimitry Andric OS << "\"]; // defined externally\n";
334*b5893f02SDimitry Andric }
335*b5893f02SDimitry Andric
hasReadOnlyFlag(const GlobalValueSummary * S)336*b5893f02SDimitry Andric static bool hasReadOnlyFlag(const GlobalValueSummary *S) {
337*b5893f02SDimitry Andric if (auto *GVS = dyn_cast<GlobalVarSummary>(S))
338*b5893f02SDimitry Andric return GVS->isReadOnly();
339*b5893f02SDimitry Andric return false;
3404ba319b5SDimitry Andric }
3414ba319b5SDimitry Andric
exportToDot(raw_ostream & OS) const3424ba319b5SDimitry Andric void ModuleSummaryIndex::exportToDot(raw_ostream &OS) const {
3434ba319b5SDimitry Andric std::vector<Edge> CrossModuleEdges;
3444ba319b5SDimitry Andric DenseMap<GlobalValue::GUID, std::vector<uint64_t>> NodeMap;
3454ba319b5SDimitry Andric StringMap<GVSummaryMapTy> ModuleToDefinedGVS;
3464ba319b5SDimitry Andric collectDefinedGVSummariesPerModule(ModuleToDefinedGVS);
3474ba319b5SDimitry Andric
3484ba319b5SDimitry Andric // Get node identifier in form MXXX_<GUID>. The MXXX prefix is required,
3494ba319b5SDimitry Andric // because we may have multiple linkonce functions summaries.
3504ba319b5SDimitry Andric auto NodeId = [](uint64_t ModId, GlobalValue::GUID Id) {
3514ba319b5SDimitry Andric return ModId == (uint64_t)-1 ? std::to_string(Id)
3524ba319b5SDimitry Andric : std::string("M") + std::to_string(ModId) +
3534ba319b5SDimitry Andric "_" + std::to_string(Id);
3544ba319b5SDimitry Andric };
3554ba319b5SDimitry Andric
356*b5893f02SDimitry Andric auto DrawEdge = [&](const char *Pfx, uint64_t SrcMod, GlobalValue::GUID SrcId,
357*b5893f02SDimitry Andric uint64_t DstMod, GlobalValue::GUID DstId,
358*b5893f02SDimitry Andric int TypeOrHotness) {
359*b5893f02SDimitry Andric // 0 - alias
360*b5893f02SDimitry Andric // 1 - reference
361*b5893f02SDimitry Andric // 2 - constant reference
362*b5893f02SDimitry Andric // Other value: (hotness - 3).
363*b5893f02SDimitry Andric TypeOrHotness += 3;
3644ba319b5SDimitry Andric static const char *EdgeAttrs[] = {
3654ba319b5SDimitry Andric " [style=dotted]; // alias",
3664ba319b5SDimitry Andric " [style=dashed]; // ref",
367*b5893f02SDimitry Andric " [style=dashed,color=forestgreen]; // const-ref",
3684ba319b5SDimitry Andric " // call (hotness : Unknown)",
3694ba319b5SDimitry Andric " [color=blue]; // call (hotness : Cold)",
3704ba319b5SDimitry Andric " // call (hotness : None)",
3714ba319b5SDimitry Andric " [color=brown]; // call (hotness : Hot)",
3724ba319b5SDimitry Andric " [style=bold,color=red]; // call (hotness : Critical)"};
3734ba319b5SDimitry Andric
3744ba319b5SDimitry Andric assert(static_cast<size_t>(TypeOrHotness) <
3754ba319b5SDimitry Andric sizeof(EdgeAttrs) / sizeof(EdgeAttrs[0]));
3764ba319b5SDimitry Andric OS << Pfx << NodeId(SrcMod, SrcId) << " -> " << NodeId(DstMod, DstId)
3774ba319b5SDimitry Andric << EdgeAttrs[TypeOrHotness] << "\n";
3784ba319b5SDimitry Andric };
3794ba319b5SDimitry Andric
3804ba319b5SDimitry Andric OS << "digraph Summary {\n";
3814ba319b5SDimitry Andric for (auto &ModIt : ModuleToDefinedGVS) {
3824ba319b5SDimitry Andric auto ModId = getModuleId(ModIt.first());
3834ba319b5SDimitry Andric OS << " // Module: " << ModIt.first() << "\n";
3844ba319b5SDimitry Andric OS << " subgraph cluster_" << std::to_string(ModId) << " {\n";
3854ba319b5SDimitry Andric OS << " style = filled;\n";
3864ba319b5SDimitry Andric OS << " color = lightgrey;\n";
3874ba319b5SDimitry Andric OS << " label = \"" << sys::path::filename(ModIt.first()) << "\";\n";
3884ba319b5SDimitry Andric OS << " node [style=filled,fillcolor=lightblue];\n";
3894ba319b5SDimitry Andric
3904ba319b5SDimitry Andric auto &GVSMap = ModIt.second;
3914ba319b5SDimitry Andric auto Draw = [&](GlobalValue::GUID IdFrom, GlobalValue::GUID IdTo, int Hotness) {
3924ba319b5SDimitry Andric if (!GVSMap.count(IdTo)) {
3934ba319b5SDimitry Andric CrossModuleEdges.push_back({ModId, Hotness, IdFrom, IdTo});
3944ba319b5SDimitry Andric return;
3954ba319b5SDimitry Andric }
3964ba319b5SDimitry Andric DrawEdge(" ", ModId, IdFrom, ModId, IdTo, Hotness);
3974ba319b5SDimitry Andric };
3984ba319b5SDimitry Andric
3994ba319b5SDimitry Andric for (auto &SummaryIt : GVSMap) {
4004ba319b5SDimitry Andric NodeMap[SummaryIt.first].push_back(ModId);
4014ba319b5SDimitry Andric auto Flags = SummaryIt.second->flags();
4024ba319b5SDimitry Andric Attributes A;
4034ba319b5SDimitry Andric if (isa<FunctionSummary>(SummaryIt.second)) {
4044ba319b5SDimitry Andric A.add("shape", "record", "function");
4054ba319b5SDimitry Andric } else if (isa<AliasSummary>(SummaryIt.second)) {
4064ba319b5SDimitry Andric A.add("style", "dotted,filled", "alias");
4074ba319b5SDimitry Andric A.add("shape", "box");
4084ba319b5SDimitry Andric } else {
4094ba319b5SDimitry Andric A.add("shape", "Mrecord", "variable");
410*b5893f02SDimitry Andric if (Flags.Live && hasReadOnlyFlag(SummaryIt.second))
411*b5893f02SDimitry Andric A.addComment("immutable");
4124ba319b5SDimitry Andric }
4134ba319b5SDimitry Andric
4144ba319b5SDimitry Andric auto VI = getValueInfo(SummaryIt.first);
4154ba319b5SDimitry Andric A.add("label", getNodeLabel(VI, SummaryIt.second));
4164ba319b5SDimitry Andric if (!Flags.Live)
4174ba319b5SDimitry Andric A.add("fillcolor", "red", "dead");
4184ba319b5SDimitry Andric else if (Flags.NotEligibleToImport)
4194ba319b5SDimitry Andric A.add("fillcolor", "yellow", "not eligible to import");
4204ba319b5SDimitry Andric
4214ba319b5SDimitry Andric OS << " " << NodeId(ModId, SummaryIt.first) << " " << A.getAsString()
4224ba319b5SDimitry Andric << "\n";
4234ba319b5SDimitry Andric }
4244ba319b5SDimitry Andric OS << " // Edges:\n";
4254ba319b5SDimitry Andric
4264ba319b5SDimitry Andric for (auto &SummaryIt : GVSMap) {
4274ba319b5SDimitry Andric auto *GVS = SummaryIt.second;
4284ba319b5SDimitry Andric for (auto &R : GVS->refs())
429*b5893f02SDimitry Andric Draw(SummaryIt.first, R.getGUID(), R.isReadOnly() ? -1 : -2);
4304ba319b5SDimitry Andric
4314ba319b5SDimitry Andric if (auto *AS = dyn_cast_or_null<AliasSummary>(SummaryIt.second)) {
432*b5893f02SDimitry Andric GlobalValue::GUID AliaseeId;
433*b5893f02SDimitry Andric if (AS->hasAliaseeGUID())
434*b5893f02SDimitry Andric AliaseeId = AS->getAliaseeGUID();
435*b5893f02SDimitry Andric else {
4364ba319b5SDimitry Andric auto AliaseeOrigId = AS->getAliasee().getOriginalName();
437*b5893f02SDimitry Andric AliaseeId = getGUIDFromOriginalID(AliaseeOrigId);
438*b5893f02SDimitry Andric if (!AliaseeId)
439*b5893f02SDimitry Andric AliaseeId = AliaseeOrigId;
440*b5893f02SDimitry Andric }
4414ba319b5SDimitry Andric
442*b5893f02SDimitry Andric Draw(SummaryIt.first, AliaseeId, -3);
4434ba319b5SDimitry Andric continue;
4444ba319b5SDimitry Andric }
4454ba319b5SDimitry Andric
4464ba319b5SDimitry Andric if (auto *FS = dyn_cast_or_null<FunctionSummary>(SummaryIt.second))
4474ba319b5SDimitry Andric for (auto &CGEdge : FS->calls())
4484ba319b5SDimitry Andric Draw(SummaryIt.first, CGEdge.first.getGUID(),
4494ba319b5SDimitry Andric static_cast<int>(CGEdge.second.Hotness));
4504ba319b5SDimitry Andric }
4514ba319b5SDimitry Andric OS << " }\n";
4524ba319b5SDimitry Andric }
4534ba319b5SDimitry Andric
4544ba319b5SDimitry Andric OS << " // Cross-module edges:\n";
4554ba319b5SDimitry Andric for (auto &E : CrossModuleEdges) {
4564ba319b5SDimitry Andric auto &ModList = NodeMap[E.Dst];
4574ba319b5SDimitry Andric if (ModList.empty()) {
458*b5893f02SDimitry Andric defineExternalNode(OS, " ", getValueInfo(E.Dst), E.Dst);
4594ba319b5SDimitry Andric // Add fake module to the list to draw an edge to an external node
4604ba319b5SDimitry Andric // in the loop below.
4614ba319b5SDimitry Andric ModList.push_back(-1);
4624ba319b5SDimitry Andric }
4634ba319b5SDimitry Andric for (auto DstMod : ModList)
4644ba319b5SDimitry Andric // The edge representing call or ref is drawn to every module where target
4654ba319b5SDimitry Andric // symbol is defined. When target is a linkonce symbol there can be
4664ba319b5SDimitry Andric // multiple edges representing a single call or ref, both intra-module and
4674ba319b5SDimitry Andric // cross-module. As we've already drawn all intra-module edges before we
4684ba319b5SDimitry Andric // skip it here.
4694ba319b5SDimitry Andric if (DstMod != E.SrcMod)
4704ba319b5SDimitry Andric DrawEdge(" ", E.SrcMod, E.Src, DstMod, E.Dst, E.Hotness);
4714ba319b5SDimitry Andric }
4724ba319b5SDimitry Andric
4734ba319b5SDimitry Andric OS << "}";
4744ba319b5SDimitry Andric }
475