xref: /llvm-project/llvm/lib/IR/ModuleSummaryIndex.cpp (revision 176889868024d98db032842bc47b416997d9e349)
1 //===-- ModuleSummaryIndex.cpp - Module Summary Index ---------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements the module index and summary classes for the
10 // IR library.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/IR/ModuleSummaryIndex.h"
15 #include "llvm/ADT/SCCIterator.h"
16 #include "llvm/ADT/Statistic.h"
17 #include "llvm/Support/CommandLine.h"
18 #include "llvm/Support/Path.h"
19 #include "llvm/Support/raw_ostream.h"
20 using namespace llvm;
21 
22 #define DEBUG_TYPE "module-summary-index"
23 
24 STATISTIC(ReadOnlyLiveGVars,
25           "Number of live global variables marked read only");
26 STATISTIC(WriteOnlyLiveGVars,
27           "Number of live global variables marked write only");
28 
29 static cl::opt<bool> PropagateAttrs("propagate-attrs", cl::init(true),
30                                     cl::Hidden,
31                                     cl::desc("Propagate attributes in index"));
32 
33 static cl::opt<bool> ImportConstantsWithRefs(
34     "import-constants-with-refs", cl::init(true), cl::Hidden,
35     cl::desc("Import constant global variables with references"));
36 
37 constexpr uint32_t FunctionSummary::ParamAccess::RangeWidth;
38 
39 FunctionSummary FunctionSummary::ExternalNode =
40     FunctionSummary::makeDummyFunctionSummary({});
41 
42 GlobalValue::VisibilityTypes ValueInfo::getELFVisibility() const {
43   bool HasProtected = false;
44   for (const auto &S : make_pointee_range(getSummaryList())) {
45     if (S.getVisibility() == GlobalValue::HiddenVisibility)
46       return GlobalValue::HiddenVisibility;
47     if (S.getVisibility() == GlobalValue::ProtectedVisibility)
48       HasProtected = true;
49   }
50   return HasProtected ? GlobalValue::ProtectedVisibility
51                       : GlobalValue::DefaultVisibility;
52 }
53 
54 bool ValueInfo::isDSOLocal(bool WithDSOLocalPropagation) const {
55   // With DSOLocal propagation done, the flag in evey summary is the same.
56   // Check the first one is enough.
57   return WithDSOLocalPropagation
58              ? getSummaryList().size() && getSummaryList()[0]->isDSOLocal()
59              : getSummaryList().size() &&
60                    llvm::all_of(
61                        getSummaryList(),
62                        [](const std::unique_ptr<GlobalValueSummary> &Summary) {
63                          return Summary->isDSOLocal();
64                        });
65 }
66 
67 bool ValueInfo::canAutoHide() const {
68   // Can only auto hide if all copies are eligible to auto hide.
69   return getSummaryList().size() &&
70          llvm::all_of(getSummaryList(),
71                       [](const std::unique_ptr<GlobalValueSummary> &Summary) {
72                         return Summary->canAutoHide();
73                       });
74 }
75 
76 // Gets the number of readonly and writeonly refs in RefEdgeList
77 std::pair<unsigned, unsigned> FunctionSummary::specialRefCounts() const {
78   // Here we take advantage of having all readonly and writeonly references
79   // located in the end of the RefEdgeList.
80   auto Refs = refs();
81   unsigned RORefCnt = 0, WORefCnt = 0;
82   int I;
83   for (I = Refs.size() - 1; I >= 0 && Refs[I].isWriteOnly(); --I)
84     WORefCnt++;
85   for (; I >= 0 && Refs[I].isReadOnly(); --I)
86     RORefCnt++;
87   return {RORefCnt, WORefCnt};
88 }
89 
90 constexpr uint64_t ModuleSummaryIndex::BitcodeSummaryVersion;
91 
92 uint64_t ModuleSummaryIndex::getFlags() const {
93   uint64_t Flags = 0;
94   if (withGlobalValueDeadStripping())
95     Flags |= 0x1;
96   if (skipModuleByDistributedBackend())
97     Flags |= 0x2;
98   if (hasSyntheticEntryCounts())
99     Flags |= 0x4;
100   if (enableSplitLTOUnit())
101     Flags |= 0x8;
102   if (partiallySplitLTOUnits())
103     Flags |= 0x10;
104   if (withAttributePropagation())
105     Flags |= 0x20;
106   if (withDSOLocalPropagation())
107     Flags |= 0x40;
108   if (withWholeProgramVisibility())
109     Flags |= 0x80;
110   if (withSupportsHotColdNew())
111     Flags |= 0x100;
112   return Flags;
113 }
114 
115 void ModuleSummaryIndex::setFlags(uint64_t Flags) {
116   assert(Flags <= 0x1ff && "Unexpected bits in flag");
117   // 1 bit: WithGlobalValueDeadStripping flag.
118   // Set on combined index only.
119   if (Flags & 0x1)
120     setWithGlobalValueDeadStripping();
121   // 1 bit: SkipModuleByDistributedBackend flag.
122   // Set on combined index only.
123   if (Flags & 0x2)
124     setSkipModuleByDistributedBackend();
125   // 1 bit: HasSyntheticEntryCounts flag.
126   // Set on combined index only.
127   if (Flags & 0x4)
128     setHasSyntheticEntryCounts();
129   // 1 bit: DisableSplitLTOUnit flag.
130   // Set on per module indexes. It is up to the client to validate
131   // the consistency of this flag across modules being linked.
132   if (Flags & 0x8)
133     setEnableSplitLTOUnit();
134   // 1 bit: PartiallySplitLTOUnits flag.
135   // Set on combined index only.
136   if (Flags & 0x10)
137     setPartiallySplitLTOUnits();
138   // 1 bit: WithAttributePropagation flag.
139   // Set on combined index only.
140   if (Flags & 0x20)
141     setWithAttributePropagation();
142   // 1 bit: WithDSOLocalPropagation flag.
143   // Set on combined index only.
144   if (Flags & 0x40)
145     setWithDSOLocalPropagation();
146   // 1 bit: WithWholeProgramVisibility flag.
147   // Set on combined index only.
148   if (Flags & 0x80)
149     setWithWholeProgramVisibility();
150   // 1 bit: WithSupportsHotColdNew flag.
151   // Set on combined index only.
152   if (Flags & 0x100)
153     setWithSupportsHotColdNew();
154 }
155 
156 // Collect for the given module the list of function it defines
157 // (GUID -> Summary).
158 void ModuleSummaryIndex::collectDefinedFunctionsForModule(
159     StringRef ModulePath, GVSummaryMapTy &GVSummaryMap) const {
160   for (auto &GlobalList : *this) {
161     auto GUID = GlobalList.first;
162     for (auto &GlobSummary : GlobalList.second.SummaryList) {
163       auto *Summary = dyn_cast_or_null<FunctionSummary>(GlobSummary.get());
164       if (!Summary)
165         // Ignore global variable, focus on functions
166         continue;
167       // Ignore summaries from other modules.
168       if (Summary->modulePath() != ModulePath)
169         continue;
170       GVSummaryMap[GUID] = Summary;
171     }
172   }
173 }
174 
175 GlobalValueSummary *
176 ModuleSummaryIndex::getGlobalValueSummary(uint64_t ValueGUID,
177                                           bool PerModuleIndex) const {
178   auto VI = getValueInfo(ValueGUID);
179   assert(VI && "GlobalValue not found in index");
180   assert((!PerModuleIndex || VI.getSummaryList().size() == 1) &&
181          "Expected a single entry per global value in per-module index");
182   auto &Summary = VI.getSummaryList()[0];
183   return Summary.get();
184 }
185 
186 bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID) const {
187   auto VI = getValueInfo(GUID);
188   if (!VI)
189     return true;
190   const auto &SummaryList = VI.getSummaryList();
191   if (SummaryList.empty())
192     return true;
193   for (auto &I : SummaryList)
194     if (isGlobalValueLive(I.get()))
195       return true;
196   return false;
197 }
198 
199 static void
200 propagateAttributesToRefs(GlobalValueSummary *S,
201                           DenseSet<ValueInfo> &MarkedNonReadWriteOnly) {
202   // If reference is not readonly or writeonly then referenced summary is not
203   // read/writeonly either. Note that:
204   // - All references from GlobalVarSummary are conservatively considered as
205   //   not readonly or writeonly. Tracking them properly requires more complex
206   //   analysis then we have now.
207   //
208   // - AliasSummary objects have no refs at all so this function is a no-op
209   //   for them.
210   for (auto &VI : S->refs()) {
211     assert(VI.getAccessSpecifier() == 0 || isa<FunctionSummary>(S));
212     if (!VI.getAccessSpecifier()) {
213       if (!MarkedNonReadWriteOnly.insert(VI).second)
214         continue;
215     } else if (MarkedNonReadWriteOnly.contains(VI))
216       continue;
217     for (auto &Ref : VI.getSummaryList())
218       // If references to alias is not read/writeonly then aliasee
219       // is not read/writeonly
220       if (auto *GVS = dyn_cast<GlobalVarSummary>(Ref->getBaseObject())) {
221         if (!VI.isReadOnly())
222           GVS->setReadOnly(false);
223         if (!VI.isWriteOnly())
224           GVS->setWriteOnly(false);
225       }
226   }
227 }
228 
229 // Do the access attribute and DSOLocal propagation in combined index.
230 // The goal of attribute propagation is internalization of readonly (RO)
231 // or writeonly (WO) variables. To determine which variables are RO or WO
232 // and which are not we take following steps:
233 // - During analysis we speculatively assign readonly and writeonly
234 //   attribute to all variables which can be internalized. When computing
235 //   function summary we also assign readonly or writeonly attribute to a
236 //   reference if function doesn't modify referenced variable (readonly)
237 //   or doesn't read it (writeonly).
238 //
239 // - After computing dead symbols in combined index we do the attribute
240 //   and DSOLocal propagation. During this step we:
241 //   a. clear RO and WO attributes from variables which are preserved or
242 //      can't be imported
243 //   b. clear RO and WO attributes from variables referenced by any global
244 //      variable initializer
245 //   c. clear RO attribute from variable referenced by a function when
246 //      reference is not readonly
247 //   d. clear WO attribute from variable referenced by a function when
248 //      reference is not writeonly
249 //   e. clear IsDSOLocal flag in every summary if any of them is false.
250 //
251 //   Because of (c, d) we don't internalize variables read by function A
252 //   and modified by function B.
253 //
254 // Internalization itself happens in the backend after import is finished
255 // See internalizeGVsAfterImport.
256 void ModuleSummaryIndex::propagateAttributes(
257     const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) {
258   if (!PropagateAttrs)
259     return;
260   DenseSet<ValueInfo> MarkedNonReadWriteOnly;
261   for (auto &P : *this) {
262     bool IsDSOLocal = true;
263     for (auto &S : P.second.SummaryList) {
264       if (!isGlobalValueLive(S.get())) {
265         // computeDeadSymbolsAndUpdateIndirectCalls should have marked all
266         // copies live. Note that it is possible that there is a GUID collision
267         // between internal symbols with the same name in different files of the
268         // same name but not enough distinguishing path. Because
269         // computeDeadSymbolsAndUpdateIndirectCalls should conservatively mark
270         // all copies live we can assert here that all are dead if any copy is
271         // dead.
272         assert(llvm::none_of(
273             P.second.SummaryList,
274             [&](const std::unique_ptr<GlobalValueSummary> &Summary) {
275               return isGlobalValueLive(Summary.get());
276             }));
277         // We don't examine references from dead objects
278         break;
279       }
280 
281       // Global variable can't be marked read/writeonly if it is not eligible
282       // to import since we need to ensure that all external references get
283       // a local (imported) copy. It also can't be marked read/writeonly if
284       // it or any alias (since alias points to the same memory) are preserved
285       // or notEligibleToImport, since either of those means there could be
286       // writes (or reads in case of writeonly) that are not visible (because
287       // preserved means it could have external to DSO writes or reads, and
288       // notEligibleToImport means it could have writes or reads via inline
289       // assembly leading it to be in the @llvm.*used).
290       if (auto *GVS = dyn_cast<GlobalVarSummary>(S->getBaseObject()))
291         // Here we intentionally pass S.get() not GVS, because S could be
292         // an alias. We don't analyze references here, because we have to
293         // know exactly if GV is readonly to do so.
294         if (!canImportGlobalVar(S.get(), /* AnalyzeRefs */ false) ||
295             GUIDPreservedSymbols.count(P.first)) {
296           GVS->setReadOnly(false);
297           GVS->setWriteOnly(false);
298         }
299       propagateAttributesToRefs(S.get(), MarkedNonReadWriteOnly);
300 
301       // If the flag from any summary is false, the GV is not DSOLocal.
302       IsDSOLocal &= S->isDSOLocal();
303     }
304     if (!IsDSOLocal)
305       // Mark the flag in all summaries false so that we can do quick check
306       // without going through the whole list.
307       for (const std::unique_ptr<GlobalValueSummary> &Summary :
308            P.second.SummaryList)
309         Summary->setDSOLocal(false);
310   }
311   setWithAttributePropagation();
312   setWithDSOLocalPropagation();
313   if (llvm::AreStatisticsEnabled())
314     for (auto &P : *this)
315       if (P.second.SummaryList.size())
316         if (auto *GVS = dyn_cast<GlobalVarSummary>(
317                 P.second.SummaryList[0]->getBaseObject()))
318           if (isGlobalValueLive(GVS)) {
319             if (GVS->maybeReadOnly())
320               ReadOnlyLiveGVars++;
321             if (GVS->maybeWriteOnly())
322               WriteOnlyLiveGVars++;
323           }
324 }
325 
326 bool ModuleSummaryIndex::canImportGlobalVar(const GlobalValueSummary *S,
327                                             bool AnalyzeRefs) const {
328   auto HasRefsPreventingImport = [this](const GlobalVarSummary *GVS) {
329     // We don't analyze GV references during attribute propagation, so
330     // GV with non-trivial initializer can be marked either read or
331     // write-only.
332     // Importing definiton of readonly GV with non-trivial initializer
333     // allows us doing some extra optimizations (like converting indirect
334     // calls to direct).
335     // Definition of writeonly GV with non-trivial initializer should also
336     // be imported. Not doing so will result in:
337     // a) GV internalization in source module (because it's writeonly)
338     // b) Importing of GV declaration to destination module as a result
339     //    of promotion.
340     // c) Link error (external declaration with internal definition).
341     // However we do not promote objects referenced by writeonly GV
342     // initializer by means of converting it to 'zeroinitializer'
343     return !(ImportConstantsWithRefs && GVS->isConstant()) &&
344            !isReadOnly(GVS) && !isWriteOnly(GVS) && GVS->refs().size();
345   };
346   auto *GVS = cast<GlobalVarSummary>(S->getBaseObject());
347 
348   // Global variable with non-trivial initializer can be imported
349   // if it's readonly. This gives us extra opportunities for constant
350   // folding and converting indirect calls to direct calls. We don't
351   // analyze GV references during attribute propagation, because we
352   // don't know yet if it is readonly or not.
353   return !GlobalValue::isInterposableLinkage(S->linkage()) &&
354          !S->notEligibleToImport() &&
355          (!AnalyzeRefs || !HasRefsPreventingImport(GVS));
356 }
357 
358 // TODO: write a graphviz dumper for SCCs (see ModuleSummaryIndex::exportToDot)
359 // then delete this function and update its tests
360 LLVM_DUMP_METHOD
361 void ModuleSummaryIndex::dumpSCCs(raw_ostream &O) {
362   for (scc_iterator<ModuleSummaryIndex *> I =
363            scc_begin<ModuleSummaryIndex *>(this);
364        !I.isAtEnd(); ++I) {
365     O << "SCC (" << utostr(I->size()) << " node" << (I->size() == 1 ? "" : "s")
366       << ") {\n";
367     for (const ValueInfo &V : *I) {
368       FunctionSummary *F = nullptr;
369       if (V.getSummaryList().size())
370         F = cast<FunctionSummary>(V.getSummaryList().front().get());
371       O << " " << (F == nullptr ? "External" : "") << " " << utostr(V.getGUID())
372         << (I.hasCycle() ? " (has cycle)" : "") << "\n";
373     }
374     O << "}\n";
375   }
376 }
377 
378 namespace {
379 struct Attributes {
380   void add(const Twine &Name, const Twine &Value,
381            const Twine &Comment = Twine());
382   void addComment(const Twine &Comment);
383   std::string getAsString() const;
384 
385   std::vector<std::string> Attrs;
386   std::string Comments;
387 };
388 
389 struct Edge {
390   uint64_t SrcMod;
391   int Hotness;
392   GlobalValue::GUID Src;
393   GlobalValue::GUID Dst;
394 };
395 }
396 
397 void Attributes::add(const Twine &Name, const Twine &Value,
398                      const Twine &Comment) {
399   std::string A = Name.str();
400   A += "=\"";
401   A += Value.str();
402   A += "\"";
403   Attrs.push_back(A);
404   addComment(Comment);
405 }
406 
407 void Attributes::addComment(const Twine &Comment) {
408   if (!Comment.isTriviallyEmpty()) {
409     if (Comments.empty())
410       Comments = " // ";
411     else
412       Comments += ", ";
413     Comments += Comment.str();
414   }
415 }
416 
417 std::string Attributes::getAsString() const {
418   if (Attrs.empty())
419     return "";
420 
421   std::string Ret = "[";
422   for (auto &A : Attrs)
423     Ret += A + ",";
424   Ret.pop_back();
425   Ret += "];";
426   Ret += Comments;
427   return Ret;
428 }
429 
430 static std::string linkageToString(GlobalValue::LinkageTypes LT) {
431   switch (LT) {
432   case GlobalValue::ExternalLinkage:
433     return "extern";
434   case GlobalValue::AvailableExternallyLinkage:
435     return "av_ext";
436   case GlobalValue::LinkOnceAnyLinkage:
437     return "linkonce";
438   case GlobalValue::LinkOnceODRLinkage:
439     return "linkonce_odr";
440   case GlobalValue::WeakAnyLinkage:
441     return "weak";
442   case GlobalValue::WeakODRLinkage:
443     return "weak_odr";
444   case GlobalValue::AppendingLinkage:
445     return "appending";
446   case GlobalValue::InternalLinkage:
447     return "internal";
448   case GlobalValue::PrivateLinkage:
449     return "private";
450   case GlobalValue::ExternalWeakLinkage:
451     return "extern_weak";
452   case GlobalValue::CommonLinkage:
453     return "common";
454   }
455 
456   return "<unknown>";
457 }
458 
459 static std::string fflagsToString(FunctionSummary::FFlags F) {
460   auto FlagValue = [](unsigned V) { return V ? '1' : '0'; };
461   char FlagRep[] = {FlagValue(F.ReadNone),
462                     FlagValue(F.ReadOnly),
463                     FlagValue(F.NoRecurse),
464                     FlagValue(F.ReturnDoesNotAlias),
465                     FlagValue(F.NoInline),
466                     FlagValue(F.AlwaysInline),
467                     FlagValue(F.NoUnwind),
468                     FlagValue(F.MayThrow),
469                     FlagValue(F.HasUnknownCall),
470                     FlagValue(F.MustBeUnreachable),
471                     0};
472 
473   return FlagRep;
474 }
475 
476 // Get string representation of function instruction count and flags.
477 static std::string getSummaryAttributes(GlobalValueSummary* GVS) {
478   auto *FS = dyn_cast_or_null<FunctionSummary>(GVS);
479   if (!FS)
480     return "";
481 
482   return std::string("inst: ") + std::to_string(FS->instCount()) +
483          ", ffl: " + fflagsToString(FS->fflags());
484 }
485 
486 static std::string getNodeVisualName(GlobalValue::GUID Id) {
487   return std::string("@") + std::to_string(Id);
488 }
489 
490 static std::string getNodeVisualName(const ValueInfo &VI) {
491   return VI.name().empty() ? getNodeVisualName(VI.getGUID()) : VI.name().str();
492 }
493 
494 static std::string getNodeLabel(const ValueInfo &VI, GlobalValueSummary *GVS) {
495   if (isa<AliasSummary>(GVS))
496     return getNodeVisualName(VI);
497 
498   std::string Attrs = getSummaryAttributes(GVS);
499   std::string Label =
500       getNodeVisualName(VI) + "|" + linkageToString(GVS->linkage());
501   if (!Attrs.empty())
502     Label += std::string(" (") + Attrs + ")";
503   Label += "}";
504 
505   return Label;
506 }
507 
508 // Write definition of external node, which doesn't have any
509 // specific module associated with it. Typically this is function
510 // or variable defined in native object or library.
511 static void defineExternalNode(raw_ostream &OS, const char *Pfx,
512                                const ValueInfo &VI, GlobalValue::GUID Id) {
513   auto StrId = std::to_string(Id);
514   OS << "  " << StrId << " [label=\"";
515 
516   if (VI) {
517     OS << getNodeVisualName(VI);
518   } else {
519     OS << getNodeVisualName(Id);
520   }
521   OS << "\"]; // defined externally\n";
522 }
523 
524 static bool hasReadOnlyFlag(const GlobalValueSummary *S) {
525   if (auto *GVS = dyn_cast<GlobalVarSummary>(S))
526     return GVS->maybeReadOnly();
527   return false;
528 }
529 
530 static bool hasWriteOnlyFlag(const GlobalValueSummary *S) {
531   if (auto *GVS = dyn_cast<GlobalVarSummary>(S))
532     return GVS->maybeWriteOnly();
533   return false;
534 }
535 
536 static bool hasConstantFlag(const GlobalValueSummary *S) {
537   if (auto *GVS = dyn_cast<GlobalVarSummary>(S))
538     return GVS->isConstant();
539   return false;
540 }
541 
542 void ModuleSummaryIndex::exportToDot(
543     raw_ostream &OS,
544     const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) const {
545   std::vector<Edge> CrossModuleEdges;
546   DenseMap<GlobalValue::GUID, std::vector<uint64_t>> NodeMap;
547   using GVSOrderedMapTy = std::map<GlobalValue::GUID, GlobalValueSummary *>;
548   std::map<StringRef, GVSOrderedMapTy> ModuleToDefinedGVS;
549   collectDefinedGVSummariesPerModule(ModuleToDefinedGVS);
550 
551   // Get node identifier in form MXXX_<GUID>. The MXXX prefix is required,
552   // because we may have multiple linkonce functions summaries.
553   auto NodeId = [](uint64_t ModId, GlobalValue::GUID Id) {
554     return ModId == (uint64_t)-1 ? std::to_string(Id)
555                                  : std::string("M") + std::to_string(ModId) +
556                                        "_" + std::to_string(Id);
557   };
558 
559   auto DrawEdge = [&](const char *Pfx, uint64_t SrcMod, GlobalValue::GUID SrcId,
560                       uint64_t DstMod, GlobalValue::GUID DstId,
561                       int TypeOrHotness) {
562     // 0 - alias
563     // 1 - reference
564     // 2 - constant reference
565     // 3 - writeonly reference
566     // Other value: (hotness - 4).
567     TypeOrHotness += 4;
568     static const char *EdgeAttrs[] = {
569         " [style=dotted]; // alias",
570         " [style=dashed]; // ref",
571         " [style=dashed,color=forestgreen]; // const-ref",
572         " [style=dashed,color=violetred]; // writeOnly-ref",
573         " // call (hotness : Unknown)",
574         " [color=blue]; // call (hotness : Cold)",
575         " // call (hotness : None)",
576         " [color=brown]; // call (hotness : Hot)",
577         " [style=bold,color=red]; // call (hotness : Critical)"};
578 
579     assert(static_cast<size_t>(TypeOrHotness) < std::size(EdgeAttrs));
580     OS << Pfx << NodeId(SrcMod, SrcId) << " -> " << NodeId(DstMod, DstId)
581        << EdgeAttrs[TypeOrHotness] << "\n";
582   };
583 
584   OS << "digraph Summary {\n";
585   for (auto &ModIt : ModuleToDefinedGVS) {
586     auto ModId = getModuleId(ModIt.first);
587     OS << "  // Module: " << ModIt.first << "\n";
588     OS << "  subgraph cluster_" << std::to_string(ModId) << " {\n";
589     OS << "    style = filled;\n";
590     OS << "    color = lightgrey;\n";
591     OS << "    label = \"" << sys::path::filename(ModIt.first) << "\";\n";
592     OS << "    node [style=filled,fillcolor=lightblue];\n";
593 
594     auto &GVSMap = ModIt.second;
595     auto Draw = [&](GlobalValue::GUID IdFrom, GlobalValue::GUID IdTo, int Hotness) {
596       if (!GVSMap.count(IdTo)) {
597         CrossModuleEdges.push_back({ModId, Hotness, IdFrom, IdTo});
598         return;
599       }
600       DrawEdge("    ", ModId, IdFrom, ModId, IdTo, Hotness);
601     };
602 
603     for (auto &SummaryIt : GVSMap) {
604       NodeMap[SummaryIt.first].push_back(ModId);
605       auto Flags = SummaryIt.second->flags();
606       Attributes A;
607       if (isa<FunctionSummary>(SummaryIt.second)) {
608         A.add("shape", "record", "function");
609       } else if (isa<AliasSummary>(SummaryIt.second)) {
610         A.add("style", "dotted,filled", "alias");
611         A.add("shape", "box");
612       } else {
613         A.add("shape", "Mrecord", "variable");
614         if (Flags.Live && hasReadOnlyFlag(SummaryIt.second))
615           A.addComment("immutable");
616         if (Flags.Live && hasWriteOnlyFlag(SummaryIt.second))
617           A.addComment("writeOnly");
618         if (Flags.Live && hasConstantFlag(SummaryIt.second))
619           A.addComment("constant");
620       }
621       if (Flags.Visibility)
622         A.addComment("visibility");
623       if (Flags.DSOLocal)
624         A.addComment("dsoLocal");
625       if (Flags.CanAutoHide)
626         A.addComment("canAutoHide");
627       if (GUIDPreservedSymbols.count(SummaryIt.first))
628         A.addComment("preserved");
629 
630       auto VI = getValueInfo(SummaryIt.first);
631       A.add("label", getNodeLabel(VI, SummaryIt.second));
632       if (!Flags.Live)
633         A.add("fillcolor", "red", "dead");
634       else if (Flags.NotEligibleToImport)
635         A.add("fillcolor", "yellow", "not eligible to import");
636 
637       OS << "    " << NodeId(ModId, SummaryIt.first) << " " << A.getAsString()
638          << "\n";
639     }
640     OS << "    // Edges:\n";
641 
642     for (auto &SummaryIt : GVSMap) {
643       auto *GVS = SummaryIt.second;
644       for (auto &R : GVS->refs())
645         Draw(SummaryIt.first, R.getGUID(),
646              R.isWriteOnly() ? -1 : (R.isReadOnly() ? -2 : -3));
647 
648       if (auto *AS = dyn_cast_or_null<AliasSummary>(SummaryIt.second)) {
649         Draw(SummaryIt.first, AS->getAliaseeGUID(), -4);
650         continue;
651       }
652 
653       if (auto *FS = dyn_cast_or_null<FunctionSummary>(SummaryIt.second))
654         for (auto &CGEdge : FS->calls())
655           Draw(SummaryIt.first, CGEdge.first.getGUID(),
656                static_cast<int>(CGEdge.second.Hotness));
657     }
658     OS << "  }\n";
659   }
660 
661   OS << "  // Cross-module edges:\n";
662   for (auto &E : CrossModuleEdges) {
663     auto &ModList = NodeMap[E.Dst];
664     if (ModList.empty()) {
665       defineExternalNode(OS, "  ", getValueInfo(E.Dst), E.Dst);
666       // Add fake module to the list to draw an edge to an external node
667       // in the loop below.
668       ModList.push_back(-1);
669     }
670     for (auto DstMod : ModList)
671       // The edge representing call or ref is drawn to every module where target
672       // symbol is defined. When target is a linkonce symbol there can be
673       // multiple edges representing a single call or ref, both intra-module and
674       // cross-module. As we've already drawn all intra-module edges before we
675       // skip it here.
676       if (DstMod != E.SrcMod)
677         DrawEdge("  ", E.SrcMod, E.Src, DstMod, E.Dst, E.Hotness);
678   }
679 
680   OS << "}";
681 }
682