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