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