xref: /src/contrib/llvm-project/llvm/lib/IR/ModuleSummaryIndex.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
101095a5dSDimitry Andric //===-- ModuleSummaryIndex.cpp - Module Summary Index ---------------------===//
201095a5dSDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
601095a5dSDimitry Andric //
701095a5dSDimitry Andric //===----------------------------------------------------------------------===//
801095a5dSDimitry Andric //
901095a5dSDimitry Andric // This file implements the module index and summary classes for the
1001095a5dSDimitry Andric // IR library.
1101095a5dSDimitry Andric //
1201095a5dSDimitry Andric //===----------------------------------------------------------------------===//
1301095a5dSDimitry Andric 
1401095a5dSDimitry Andric #include "llvm/IR/ModuleSummaryIndex.h"
15eb11fae6SDimitry Andric #include "llvm/ADT/SCCIterator.h"
16d8e91e46SDimitry Andric #include "llvm/ADT/Statistic.h"
17706b4fc4SDimitry Andric #include "llvm/Support/CommandLine.h"
18eb11fae6SDimitry Andric #include "llvm/Support/Path.h"
19eb11fae6SDimitry Andric #include "llvm/Support/raw_ostream.h"
2001095a5dSDimitry Andric using namespace llvm;
2101095a5dSDimitry Andric 
22d8e91e46SDimitry Andric #define DEBUG_TYPE "module-summary-index"
23d8e91e46SDimitry Andric 
24d8e91e46SDimitry Andric STATISTIC(ReadOnlyLiveGVars,
25d8e91e46SDimitry Andric           "Number of live global variables marked read only");
26e6d15924SDimitry Andric STATISTIC(WriteOnlyLiveGVars,
27e6d15924SDimitry Andric           "Number of live global variables marked write only");
28d8e91e46SDimitry Andric 
29706b4fc4SDimitry Andric static cl::opt<bool> PropagateAttrs("propagate-attrs", cl::init(true),
30706b4fc4SDimitry Andric                                     cl::Hidden,
31706b4fc4SDimitry Andric                                     cl::desc("Propagate attributes in index"));
32706b4fc4SDimitry Andric 
33cfca06d7SDimitry Andric static cl::opt<bool> ImportConstantsWithRefs(
34cfca06d7SDimitry Andric     "import-constants-with-refs", cl::init(true), cl::Hidden,
35cfca06d7SDimitry Andric     cl::desc("Import constant global variables with references"));
36cfca06d7SDimitry Andric 
37cfca06d7SDimitry Andric constexpr uint32_t FunctionSummary::ParamAccess::RangeWidth;
38cfca06d7SDimitry Andric 
39eb11fae6SDimitry Andric FunctionSummary FunctionSummary::ExternalNode =
40eb11fae6SDimitry Andric     FunctionSummary::makeDummyFunctionSummary({});
41e6d15924SDimitry Andric 
getELFVisibility() const42344a3780SDimitry Andric GlobalValue::VisibilityTypes ValueInfo::getELFVisibility() const {
43344a3780SDimitry Andric   bool HasProtected = false;
44344a3780SDimitry Andric   for (const auto &S : make_pointee_range(getSummaryList())) {
45344a3780SDimitry Andric     if (S.getVisibility() == GlobalValue::HiddenVisibility)
46344a3780SDimitry Andric       return GlobalValue::HiddenVisibility;
47344a3780SDimitry Andric     if (S.getVisibility() == GlobalValue::ProtectedVisibility)
48344a3780SDimitry Andric       HasProtected = true;
49344a3780SDimitry Andric   }
50344a3780SDimitry Andric   return HasProtected ? GlobalValue::ProtectedVisibility
51344a3780SDimitry Andric                       : GlobalValue::DefaultVisibility;
52344a3780SDimitry Andric }
53344a3780SDimitry Andric 
isDSOLocal(bool WithDSOLocalPropagation) const54344a3780SDimitry Andric bool ValueInfo::isDSOLocal(bool WithDSOLocalPropagation) const {
55344a3780SDimitry Andric   // With DSOLocal propagation done, the flag in evey summary is the same.
56344a3780SDimitry Andric   // Check the first one is enough.
57344a3780SDimitry Andric   return WithDSOLocalPropagation
58344a3780SDimitry Andric              ? getSummaryList().size() && getSummaryList()[0]->isDSOLocal()
59344a3780SDimitry Andric              : getSummaryList().size() &&
60344a3780SDimitry Andric                    llvm::all_of(
61344a3780SDimitry Andric                        getSummaryList(),
62eb11fae6SDimitry Andric                        [](const std::unique_ptr<GlobalValueSummary> &Summary) {
63eb11fae6SDimitry Andric                          return Summary->isDSOLocal();
64eb11fae6SDimitry Andric                        });
65eb11fae6SDimitry Andric }
66eb11fae6SDimitry Andric 
canAutoHide() const67e6d15924SDimitry Andric bool ValueInfo::canAutoHide() const {
68e6d15924SDimitry Andric   // Can only auto hide if all copies are eligible to auto hide.
69e6d15924SDimitry Andric   return getSummaryList().size() &&
70e6d15924SDimitry Andric          llvm::all_of(getSummaryList(),
71e6d15924SDimitry Andric                       [](const std::unique_ptr<GlobalValueSummary> &Summary) {
72e6d15924SDimitry Andric                         return Summary->canAutoHide();
73e6d15924SDimitry Andric                       });
74e6d15924SDimitry Andric }
75e6d15924SDimitry Andric 
76e6d15924SDimitry Andric // Gets the number of readonly and writeonly refs in RefEdgeList
specialRefCounts() const77e6d15924SDimitry Andric std::pair<unsigned, unsigned> FunctionSummary::specialRefCounts() const {
78e6d15924SDimitry Andric   // Here we take advantage of having all readonly and writeonly references
79d8e91e46SDimitry Andric   // located in the end of the RefEdgeList.
80d8e91e46SDimitry Andric   auto Refs = refs();
81e6d15924SDimitry Andric   unsigned RORefCnt = 0, WORefCnt = 0;
82e6d15924SDimitry Andric   int I;
83e6d15924SDimitry Andric   for (I = Refs.size() - 1; I >= 0 && Refs[I].isWriteOnly(); --I)
84e6d15924SDimitry Andric     WORefCnt++;
85e6d15924SDimitry Andric   for (; I >= 0 && Refs[I].isReadOnly(); --I)
86e6d15924SDimitry Andric     RORefCnt++;
87e6d15924SDimitry Andric   return {RORefCnt, WORefCnt};
88d8e91e46SDimitry Andric }
89d8e91e46SDimitry Andric 
90706b4fc4SDimitry Andric constexpr uint64_t ModuleSummaryIndex::BitcodeSummaryVersion;
91706b4fc4SDimitry Andric 
getFlags() const92cfca06d7SDimitry Andric uint64_t ModuleSummaryIndex::getFlags() const {
93cfca06d7SDimitry Andric   uint64_t Flags = 0;
94cfca06d7SDimitry Andric   if (withGlobalValueDeadStripping())
95cfca06d7SDimitry Andric     Flags |= 0x1;
96cfca06d7SDimitry Andric   if (skipModuleByDistributedBackend())
97cfca06d7SDimitry Andric     Flags |= 0x2;
98cfca06d7SDimitry Andric   if (hasSyntheticEntryCounts())
99cfca06d7SDimitry Andric     Flags |= 0x4;
100cfca06d7SDimitry Andric   if (enableSplitLTOUnit())
101cfca06d7SDimitry Andric     Flags |= 0x8;
102cfca06d7SDimitry Andric   if (partiallySplitLTOUnits())
103cfca06d7SDimitry Andric     Flags |= 0x10;
104cfca06d7SDimitry Andric   if (withAttributePropagation())
105cfca06d7SDimitry Andric     Flags |= 0x20;
106344a3780SDimitry Andric   if (withDSOLocalPropagation())
107344a3780SDimitry Andric     Flags |= 0x40;
10808e8dd7bSDimitry Andric   if (withWholeProgramVisibility())
10908e8dd7bSDimitry Andric     Flags |= 0x80;
1107fa27ce4SDimitry Andric   if (withSupportsHotColdNew())
1117fa27ce4SDimitry Andric     Flags |= 0x100;
1127fa27ce4SDimitry Andric   if (hasUnifiedLTO())
1137fa27ce4SDimitry Andric     Flags |= 0x200;
114cfca06d7SDimitry Andric   return Flags;
115cfca06d7SDimitry Andric }
116cfca06d7SDimitry Andric 
setFlags(uint64_t Flags)117cfca06d7SDimitry Andric void ModuleSummaryIndex::setFlags(uint64_t Flags) {
1187fa27ce4SDimitry Andric   assert(Flags <= 0x2ff && "Unexpected bits in flag");
119cfca06d7SDimitry Andric   // 1 bit: WithGlobalValueDeadStripping flag.
120cfca06d7SDimitry Andric   // Set on combined index only.
121cfca06d7SDimitry Andric   if (Flags & 0x1)
122cfca06d7SDimitry Andric     setWithGlobalValueDeadStripping();
123cfca06d7SDimitry Andric   // 1 bit: SkipModuleByDistributedBackend flag.
124cfca06d7SDimitry Andric   // Set on combined index only.
125cfca06d7SDimitry Andric   if (Flags & 0x2)
126cfca06d7SDimitry Andric     setSkipModuleByDistributedBackend();
127cfca06d7SDimitry Andric   // 1 bit: HasSyntheticEntryCounts flag.
128cfca06d7SDimitry Andric   // Set on combined index only.
129cfca06d7SDimitry Andric   if (Flags & 0x4)
130cfca06d7SDimitry Andric     setHasSyntheticEntryCounts();
131cfca06d7SDimitry Andric   // 1 bit: DisableSplitLTOUnit flag.
132cfca06d7SDimitry Andric   // Set on per module indexes. It is up to the client to validate
133cfca06d7SDimitry Andric   // the consistency of this flag across modules being linked.
134cfca06d7SDimitry Andric   if (Flags & 0x8)
135cfca06d7SDimitry Andric     setEnableSplitLTOUnit();
136cfca06d7SDimitry Andric   // 1 bit: PartiallySplitLTOUnits flag.
137cfca06d7SDimitry Andric   // Set on combined index only.
138cfca06d7SDimitry Andric   if (Flags & 0x10)
139cfca06d7SDimitry Andric     setPartiallySplitLTOUnits();
140cfca06d7SDimitry Andric   // 1 bit: WithAttributePropagation flag.
141cfca06d7SDimitry Andric   // Set on combined index only.
142cfca06d7SDimitry Andric   if (Flags & 0x20)
143cfca06d7SDimitry Andric     setWithAttributePropagation();
144344a3780SDimitry Andric   // 1 bit: WithDSOLocalPropagation flag.
145344a3780SDimitry Andric   // Set on combined index only.
146344a3780SDimitry Andric   if (Flags & 0x40)
147344a3780SDimitry Andric     setWithDSOLocalPropagation();
14808e8dd7bSDimitry Andric   // 1 bit: WithWholeProgramVisibility flag.
14908e8dd7bSDimitry Andric   // Set on combined index only.
15008e8dd7bSDimitry Andric   if (Flags & 0x80)
15108e8dd7bSDimitry Andric     setWithWholeProgramVisibility();
1527fa27ce4SDimitry Andric   // 1 bit: WithSupportsHotColdNew flag.
1537fa27ce4SDimitry Andric   // Set on combined index only.
1547fa27ce4SDimitry Andric   if (Flags & 0x100)
1557fa27ce4SDimitry Andric     setWithSupportsHotColdNew();
1567fa27ce4SDimitry Andric   // 1 bit: WithUnifiedLTO flag.
1577fa27ce4SDimitry Andric   // Set on combined index only.
1587fa27ce4SDimitry Andric   if (Flags & 0x200)
1597fa27ce4SDimitry Andric     setUnifiedLTO();
160cfca06d7SDimitry Andric }
161cfca06d7SDimitry Andric 
16201095a5dSDimitry Andric // Collect for the given module the list of function it defines
16301095a5dSDimitry Andric // (GUID -> Summary).
collectDefinedFunctionsForModule(StringRef ModulePath,GVSummaryMapTy & GVSummaryMap) const16401095a5dSDimitry Andric void ModuleSummaryIndex::collectDefinedFunctionsForModule(
16501095a5dSDimitry Andric     StringRef ModulePath, GVSummaryMapTy &GVSummaryMap) const {
16601095a5dSDimitry Andric   for (auto &GlobalList : *this) {
16701095a5dSDimitry Andric     auto GUID = GlobalList.first;
168c46e6a59SDimitry Andric     for (auto &GlobSummary : GlobalList.second.SummaryList) {
16901095a5dSDimitry Andric       auto *Summary = dyn_cast_or_null<FunctionSummary>(GlobSummary.get());
17001095a5dSDimitry Andric       if (!Summary)
17101095a5dSDimitry Andric         // Ignore global variable, focus on functions
17201095a5dSDimitry Andric         continue;
17301095a5dSDimitry Andric       // Ignore summaries from other modules.
17401095a5dSDimitry Andric       if (Summary->modulePath() != ModulePath)
17501095a5dSDimitry Andric         continue;
17601095a5dSDimitry Andric       GVSummaryMap[GUID] = Summary;
17701095a5dSDimitry Andric     }
17801095a5dSDimitry Andric   }
17901095a5dSDimitry Andric }
18001095a5dSDimitry Andric 
18101095a5dSDimitry Andric GlobalValueSummary *
getGlobalValueSummary(uint64_t ValueGUID,bool PerModuleIndex) const18201095a5dSDimitry Andric ModuleSummaryIndex::getGlobalValueSummary(uint64_t ValueGUID,
18301095a5dSDimitry Andric                                           bool PerModuleIndex) const {
184c46e6a59SDimitry Andric   auto VI = getValueInfo(ValueGUID);
185c46e6a59SDimitry Andric   assert(VI && "GlobalValue not found in index");
186c46e6a59SDimitry Andric   assert((!PerModuleIndex || VI.getSummaryList().size() == 1) &&
18701095a5dSDimitry Andric          "Expected a single entry per global value in per-module index");
188c46e6a59SDimitry Andric   auto &Summary = VI.getSummaryList()[0];
18901095a5dSDimitry Andric   return Summary.get();
19001095a5dSDimitry Andric }
1917c7aba6eSDimitry Andric 
isGUIDLive(GlobalValue::GUID GUID) const1927c7aba6eSDimitry Andric bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID) const {
1937c7aba6eSDimitry Andric   auto VI = getValueInfo(GUID);
1947c7aba6eSDimitry Andric   if (!VI)
1957c7aba6eSDimitry Andric     return true;
1967c7aba6eSDimitry Andric   const auto &SummaryList = VI.getSummaryList();
1977c7aba6eSDimitry Andric   if (SummaryList.empty())
1987c7aba6eSDimitry Andric     return true;
1997c7aba6eSDimitry Andric   for (auto &I : SummaryList)
2007c7aba6eSDimitry Andric     if (isGlobalValueLive(I.get()))
2017c7aba6eSDimitry Andric       return true;
2027c7aba6eSDimitry Andric   return false;
2037c7aba6eSDimitry Andric }
204eb11fae6SDimitry Andric 
205b60736ecSDimitry Andric static void
propagateAttributesToRefs(GlobalValueSummary * S,DenseSet<ValueInfo> & MarkedNonReadWriteOnly)206b60736ecSDimitry Andric propagateAttributesToRefs(GlobalValueSummary *S,
207b60736ecSDimitry Andric                           DenseSet<ValueInfo> &MarkedNonReadWriteOnly) {
208e6d15924SDimitry Andric   // If reference is not readonly or writeonly then referenced summary is not
209e6d15924SDimitry Andric   // read/writeonly either. Note that:
210d8e91e46SDimitry Andric   // - All references from GlobalVarSummary are conservatively considered as
211e6d15924SDimitry Andric   //   not readonly or writeonly. Tracking them properly requires more complex
212e6d15924SDimitry Andric   //   analysis then we have now.
213d8e91e46SDimitry Andric   //
214d8e91e46SDimitry Andric   // - AliasSummary objects have no refs at all so this function is a no-op
215d8e91e46SDimitry Andric   //   for them.
216d8e91e46SDimitry Andric   for (auto &VI : S->refs()) {
217e6d15924SDimitry Andric     assert(VI.getAccessSpecifier() == 0 || isa<FunctionSummary>(S));
218b60736ecSDimitry Andric     if (!VI.getAccessSpecifier()) {
219b60736ecSDimitry Andric       if (!MarkedNonReadWriteOnly.insert(VI).second)
220b60736ecSDimitry Andric         continue;
221b60736ecSDimitry Andric     } else if (MarkedNonReadWriteOnly.contains(VI))
222b60736ecSDimitry Andric       continue;
223d8e91e46SDimitry Andric     for (auto &Ref : VI.getSummaryList())
224e6d15924SDimitry Andric       // If references to alias is not read/writeonly then aliasee
225e6d15924SDimitry Andric       // is not read/writeonly
226e6d15924SDimitry Andric       if (auto *GVS = dyn_cast<GlobalVarSummary>(Ref->getBaseObject())) {
227e6d15924SDimitry Andric         if (!VI.isReadOnly())
228d8e91e46SDimitry Andric           GVS->setReadOnly(false);
229e6d15924SDimitry Andric         if (!VI.isWriteOnly())
230e6d15924SDimitry Andric           GVS->setWriteOnly(false);
231e6d15924SDimitry Andric       }
232d8e91e46SDimitry Andric   }
233d8e91e46SDimitry Andric }
234d8e91e46SDimitry Andric 
235344a3780SDimitry Andric // Do the access attribute and DSOLocal propagation in combined index.
236e6d15924SDimitry Andric // The goal of attribute propagation is internalization of readonly (RO)
237e6d15924SDimitry Andric // or writeonly (WO) variables. To determine which variables are RO or WO
238e6d15924SDimitry Andric // and which are not we take following steps:
239e6d15924SDimitry Andric // - During analysis we speculatively assign readonly and writeonly
240e6d15924SDimitry Andric //   attribute to all variables which can be internalized. When computing
241e6d15924SDimitry Andric //   function summary we also assign readonly or writeonly attribute to a
242e6d15924SDimitry Andric //   reference if function doesn't modify referenced variable (readonly)
243e6d15924SDimitry Andric //   or doesn't read it (writeonly).
244d8e91e46SDimitry Andric //
245e6d15924SDimitry Andric // - After computing dead symbols in combined index we do the attribute
246344a3780SDimitry Andric //   and DSOLocal propagation. During this step we:
247e6d15924SDimitry Andric //   a. clear RO and WO attributes from variables which are preserved or
248e6d15924SDimitry Andric //      can't be imported
249e6d15924SDimitry Andric //   b. clear RO and WO attributes from variables referenced by any global
250e6d15924SDimitry Andric //      variable initializer
251e6d15924SDimitry Andric //   c. clear RO attribute from variable referenced by a function when
252e6d15924SDimitry Andric //      reference is not readonly
253e6d15924SDimitry Andric //   d. clear WO attribute from variable referenced by a function when
254e6d15924SDimitry Andric //      reference is not writeonly
255344a3780SDimitry Andric //   e. clear IsDSOLocal flag in every summary if any of them is false.
256e6d15924SDimitry Andric //
257e6d15924SDimitry Andric //   Because of (c, d) we don't internalize variables read by function A
258e6d15924SDimitry Andric //   and modified by function B.
259d8e91e46SDimitry Andric //
260d8e91e46SDimitry Andric // Internalization itself happens in the backend after import is finished
261e6d15924SDimitry Andric // See internalizeGVsAfterImport.
propagateAttributes(const DenseSet<GlobalValue::GUID> & GUIDPreservedSymbols)262e6d15924SDimitry Andric void ModuleSummaryIndex::propagateAttributes(
263d8e91e46SDimitry Andric     const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) {
264706b4fc4SDimitry Andric   if (!PropagateAttrs)
265706b4fc4SDimitry Andric     return;
266b60736ecSDimitry Andric   DenseSet<ValueInfo> MarkedNonReadWriteOnly;
267344a3780SDimitry Andric   for (auto &P : *this) {
268344a3780SDimitry Andric     bool IsDSOLocal = true;
269d8e91e46SDimitry Andric     for (auto &S : P.second.SummaryList) {
270b60736ecSDimitry Andric       if (!isGlobalValueLive(S.get())) {
271c0981da4SDimitry Andric         // computeDeadSymbolsAndUpdateIndirectCalls should have marked all
272c0981da4SDimitry Andric         // copies live. Note that it is possible that there is a GUID collision
273c0981da4SDimitry Andric         // between internal symbols with the same name in different files of the
274c0981da4SDimitry Andric         // same name but not enough distinguishing path. Because
275c0981da4SDimitry Andric         // computeDeadSymbolsAndUpdateIndirectCalls should conservatively mark
276c0981da4SDimitry Andric         // all copies live we can assert here that all are dead if any copy is
277c0981da4SDimitry Andric         // dead.
278b60736ecSDimitry Andric         assert(llvm::none_of(
279b60736ecSDimitry Andric             P.second.SummaryList,
280b60736ecSDimitry Andric             [&](const std::unique_ptr<GlobalValueSummary> &Summary) {
281b60736ecSDimitry Andric               return isGlobalValueLive(Summary.get());
282b60736ecSDimitry Andric             }));
283d8e91e46SDimitry Andric         // We don't examine references from dead objects
284b60736ecSDimitry Andric         break;
285b60736ecSDimitry Andric       }
286d8e91e46SDimitry Andric 
287e6d15924SDimitry Andric       // Global variable can't be marked read/writeonly if it is not eligible
288e6d15924SDimitry Andric       // to import since we need to ensure that all external references get
289e6d15924SDimitry Andric       // a local (imported) copy. It also can't be marked read/writeonly if
290e6d15924SDimitry Andric       // it or any alias (since alias points to the same memory) are preserved
291e6d15924SDimitry Andric       // or notEligibleToImport, since either of those means there could be
292e6d15924SDimitry Andric       // writes (or reads in case of writeonly) that are not visible (because
293e6d15924SDimitry Andric       // preserved means it could have external to DSO writes or reads, and
294e6d15924SDimitry Andric       // notEligibleToImport means it could have writes or reads via inline
295e6d15924SDimitry Andric       // assembly leading it to be in the @llvm.*used).
296d8e91e46SDimitry Andric       if (auto *GVS = dyn_cast<GlobalVarSummary>(S->getBaseObject()))
297d8e91e46SDimitry Andric         // Here we intentionally pass S.get() not GVS, because S could be
298706b4fc4SDimitry Andric         // an alias. We don't analyze references here, because we have to
299706b4fc4SDimitry Andric         // know exactly if GV is readonly to do so.
300706b4fc4SDimitry Andric         if (!canImportGlobalVar(S.get(), /* AnalyzeRefs */ false) ||
301e6d15924SDimitry Andric             GUIDPreservedSymbols.count(P.first)) {
302d8e91e46SDimitry Andric           GVS->setReadOnly(false);
303e6d15924SDimitry Andric           GVS->setWriteOnly(false);
304e6d15924SDimitry Andric         }
305b60736ecSDimitry Andric       propagateAttributesToRefs(S.get(), MarkedNonReadWriteOnly);
306344a3780SDimitry Andric 
307344a3780SDimitry Andric       // If the flag from any summary is false, the GV is not DSOLocal.
308344a3780SDimitry Andric       IsDSOLocal &= S->isDSOLocal();
309344a3780SDimitry Andric     }
310344a3780SDimitry Andric     if (!IsDSOLocal)
311344a3780SDimitry Andric       // Mark the flag in all summaries false so that we can do quick check
312344a3780SDimitry Andric       // without going through the whole list.
313344a3780SDimitry Andric       for (const std::unique_ptr<GlobalValueSummary> &Summary :
314344a3780SDimitry Andric            P.second.SummaryList)
315344a3780SDimitry Andric         Summary->setDSOLocal(false);
316d8e91e46SDimitry Andric   }
317706b4fc4SDimitry Andric   setWithAttributePropagation();
318344a3780SDimitry Andric   setWithDSOLocalPropagation();
319d8e91e46SDimitry Andric   if (llvm::AreStatisticsEnabled())
320d8e91e46SDimitry Andric     for (auto &P : *this)
321d8e91e46SDimitry Andric       if (P.second.SummaryList.size())
322d8e91e46SDimitry Andric         if (auto *GVS = dyn_cast<GlobalVarSummary>(
323d8e91e46SDimitry Andric                 P.second.SummaryList[0]->getBaseObject()))
324e6d15924SDimitry Andric           if (isGlobalValueLive(GVS)) {
325e6d15924SDimitry Andric             if (GVS->maybeReadOnly())
326d8e91e46SDimitry Andric               ReadOnlyLiveGVars++;
327e6d15924SDimitry Andric             if (GVS->maybeWriteOnly())
328e6d15924SDimitry Andric               WriteOnlyLiveGVars++;
329e6d15924SDimitry Andric           }
330d8e91e46SDimitry Andric }
331d8e91e46SDimitry Andric 
canImportGlobalVar(const GlobalValueSummary * S,bool AnalyzeRefs) const3327fa27ce4SDimitry Andric bool ModuleSummaryIndex::canImportGlobalVar(const GlobalValueSummary *S,
333706b4fc4SDimitry Andric                                             bool AnalyzeRefs) const {
334706b4fc4SDimitry Andric   auto HasRefsPreventingImport = [this](const GlobalVarSummary *GVS) {
335706b4fc4SDimitry Andric     // We don't analyze GV references during attribute propagation, so
336706b4fc4SDimitry Andric     // GV with non-trivial initializer can be marked either read or
337706b4fc4SDimitry Andric     // write-only.
338706b4fc4SDimitry Andric     // Importing definiton of readonly GV with non-trivial initializer
339706b4fc4SDimitry Andric     // allows us doing some extra optimizations (like converting indirect
340706b4fc4SDimitry Andric     // calls to direct).
341706b4fc4SDimitry Andric     // Definition of writeonly GV with non-trivial initializer should also
342706b4fc4SDimitry Andric     // be imported. Not doing so will result in:
343706b4fc4SDimitry Andric     // a) GV internalization in source module (because it's writeonly)
344706b4fc4SDimitry Andric     // b) Importing of GV declaration to destination module as a result
345706b4fc4SDimitry Andric     //    of promotion.
346706b4fc4SDimitry Andric     // c) Link error (external declaration with internal definition).
347706b4fc4SDimitry Andric     // However we do not promote objects referenced by writeonly GV
348706b4fc4SDimitry Andric     // initializer by means of converting it to 'zeroinitializer'
349cfca06d7SDimitry Andric     return !(ImportConstantsWithRefs && GVS->isConstant()) &&
350cfca06d7SDimitry Andric            !isReadOnly(GVS) && !isWriteOnly(GVS) && GVS->refs().size();
351706b4fc4SDimitry Andric   };
352706b4fc4SDimitry Andric   auto *GVS = cast<GlobalVarSummary>(S->getBaseObject());
353706b4fc4SDimitry Andric 
354706b4fc4SDimitry Andric   // Global variable with non-trivial initializer can be imported
355706b4fc4SDimitry Andric   // if it's readonly. This gives us extra opportunities for constant
356706b4fc4SDimitry Andric   // folding and converting indirect calls to direct calls. We don't
357706b4fc4SDimitry Andric   // analyze GV references during attribute propagation, because we
358706b4fc4SDimitry Andric   // don't know yet if it is readonly or not.
359706b4fc4SDimitry Andric   return !GlobalValue::isInterposableLinkage(S->linkage()) &&
360706b4fc4SDimitry Andric          !S->notEligibleToImport() &&
361706b4fc4SDimitry Andric          (!AnalyzeRefs || !HasRefsPreventingImport(GVS));
362706b4fc4SDimitry Andric }
363706b4fc4SDimitry Andric 
364eb11fae6SDimitry Andric // TODO: write a graphviz dumper for SCCs (see ModuleSummaryIndex::exportToDot)
365eb11fae6SDimitry Andric // then delete this function and update its tests
366eb11fae6SDimitry Andric LLVM_DUMP_METHOD
dumpSCCs(raw_ostream & O)367eb11fae6SDimitry Andric void ModuleSummaryIndex::dumpSCCs(raw_ostream &O) {
368eb11fae6SDimitry Andric   for (scc_iterator<ModuleSummaryIndex *> I =
369eb11fae6SDimitry Andric            scc_begin<ModuleSummaryIndex *>(this);
370eb11fae6SDimitry Andric        !I.isAtEnd(); ++I) {
371eb11fae6SDimitry Andric     O << "SCC (" << utostr(I->size()) << " node" << (I->size() == 1 ? "" : "s")
372eb11fae6SDimitry Andric       << ") {\n";
373706b4fc4SDimitry Andric     for (const ValueInfo &V : *I) {
374eb11fae6SDimitry Andric       FunctionSummary *F = nullptr;
375eb11fae6SDimitry Andric       if (V.getSummaryList().size())
376eb11fae6SDimitry Andric         F = cast<FunctionSummary>(V.getSummaryList().front().get());
377eb11fae6SDimitry Andric       O << " " << (F == nullptr ? "External" : "") << " " << utostr(V.getGUID())
378cfca06d7SDimitry Andric         << (I.hasCycle() ? " (has cycle)" : "") << "\n";
379eb11fae6SDimitry Andric     }
380eb11fae6SDimitry Andric     O << "}\n";
381eb11fae6SDimitry Andric   }
382eb11fae6SDimitry Andric }
383eb11fae6SDimitry Andric 
384eb11fae6SDimitry Andric namespace {
385eb11fae6SDimitry Andric struct Attributes {
386eb11fae6SDimitry Andric   void add(const Twine &Name, const Twine &Value,
387eb11fae6SDimitry Andric            const Twine &Comment = Twine());
388d8e91e46SDimitry Andric   void addComment(const Twine &Comment);
389eb11fae6SDimitry Andric   std::string getAsString() const;
390eb11fae6SDimitry Andric 
391eb11fae6SDimitry Andric   std::vector<std::string> Attrs;
392eb11fae6SDimitry Andric   std::string Comments;
393eb11fae6SDimitry Andric };
394eb11fae6SDimitry Andric 
395eb11fae6SDimitry Andric struct Edge {
396eb11fae6SDimitry Andric   uint64_t SrcMod;
397eb11fae6SDimitry Andric   int Hotness;
398eb11fae6SDimitry Andric   GlobalValue::GUID Src;
399eb11fae6SDimitry Andric   GlobalValue::GUID Dst;
400eb11fae6SDimitry Andric };
401eb11fae6SDimitry Andric }
402eb11fae6SDimitry Andric 
add(const Twine & Name,const Twine & Value,const Twine & Comment)403eb11fae6SDimitry Andric void Attributes::add(const Twine &Name, const Twine &Value,
404eb11fae6SDimitry Andric                      const Twine &Comment) {
405eb11fae6SDimitry Andric   std::string A = Name.str();
406eb11fae6SDimitry Andric   A += "=\"";
407eb11fae6SDimitry Andric   A += Value.str();
408eb11fae6SDimitry Andric   A += "\"";
409eb11fae6SDimitry Andric   Attrs.push_back(A);
410d8e91e46SDimitry Andric   addComment(Comment);
411d8e91e46SDimitry Andric }
412d8e91e46SDimitry Andric 
addComment(const Twine & Comment)413d8e91e46SDimitry Andric void Attributes::addComment(const Twine &Comment) {
414eb11fae6SDimitry Andric   if (!Comment.isTriviallyEmpty()) {
415eb11fae6SDimitry Andric     if (Comments.empty())
416eb11fae6SDimitry Andric       Comments = " // ";
417eb11fae6SDimitry Andric     else
418eb11fae6SDimitry Andric       Comments += ", ";
419eb11fae6SDimitry Andric     Comments += Comment.str();
420eb11fae6SDimitry Andric   }
421eb11fae6SDimitry Andric }
422eb11fae6SDimitry Andric 
getAsString() const423eb11fae6SDimitry Andric std::string Attributes::getAsString() const {
424eb11fae6SDimitry Andric   if (Attrs.empty())
425eb11fae6SDimitry Andric     return "";
426eb11fae6SDimitry Andric 
427eb11fae6SDimitry Andric   std::string Ret = "[";
428eb11fae6SDimitry Andric   for (auto &A : Attrs)
429eb11fae6SDimitry Andric     Ret += A + ",";
430eb11fae6SDimitry Andric   Ret.pop_back();
431eb11fae6SDimitry Andric   Ret += "];";
432eb11fae6SDimitry Andric   Ret += Comments;
433eb11fae6SDimitry Andric   return Ret;
434eb11fae6SDimitry Andric }
435eb11fae6SDimitry Andric 
linkageToString(GlobalValue::LinkageTypes LT)436eb11fae6SDimitry Andric static std::string linkageToString(GlobalValue::LinkageTypes LT) {
437eb11fae6SDimitry Andric   switch (LT) {
438eb11fae6SDimitry Andric   case GlobalValue::ExternalLinkage:
439eb11fae6SDimitry Andric     return "extern";
440eb11fae6SDimitry Andric   case GlobalValue::AvailableExternallyLinkage:
441eb11fae6SDimitry Andric     return "av_ext";
442eb11fae6SDimitry Andric   case GlobalValue::LinkOnceAnyLinkage:
443eb11fae6SDimitry Andric     return "linkonce";
444eb11fae6SDimitry Andric   case GlobalValue::LinkOnceODRLinkage:
445eb11fae6SDimitry Andric     return "linkonce_odr";
446eb11fae6SDimitry Andric   case GlobalValue::WeakAnyLinkage:
447eb11fae6SDimitry Andric     return "weak";
448eb11fae6SDimitry Andric   case GlobalValue::WeakODRLinkage:
449eb11fae6SDimitry Andric     return "weak_odr";
450eb11fae6SDimitry Andric   case GlobalValue::AppendingLinkage:
451eb11fae6SDimitry Andric     return "appending";
452eb11fae6SDimitry Andric   case GlobalValue::InternalLinkage:
453eb11fae6SDimitry Andric     return "internal";
454eb11fae6SDimitry Andric   case GlobalValue::PrivateLinkage:
455eb11fae6SDimitry Andric     return "private";
456eb11fae6SDimitry Andric   case GlobalValue::ExternalWeakLinkage:
457eb11fae6SDimitry Andric     return "extern_weak";
458eb11fae6SDimitry Andric   case GlobalValue::CommonLinkage:
459eb11fae6SDimitry Andric     return "common";
460eb11fae6SDimitry Andric   }
461eb11fae6SDimitry Andric 
462eb11fae6SDimitry Andric   return "<unknown>";
463eb11fae6SDimitry Andric }
464eb11fae6SDimitry Andric 
fflagsToString(FunctionSummary::FFlags F)465eb11fae6SDimitry Andric static std::string fflagsToString(FunctionSummary::FFlags F) {
466eb11fae6SDimitry Andric   auto FlagValue = [](unsigned V) { return V ? '1' : '0'; };
46777fc4c14SDimitry Andric   char FlagRep[] = {FlagValue(F.ReadNone),
46877fc4c14SDimitry Andric                     FlagValue(F.ReadOnly),
46977fc4c14SDimitry Andric                     FlagValue(F.NoRecurse),
47077fc4c14SDimitry Andric                     FlagValue(F.ReturnDoesNotAlias),
47177fc4c14SDimitry Andric                     FlagValue(F.NoInline),
47277fc4c14SDimitry Andric                     FlagValue(F.AlwaysInline),
47377fc4c14SDimitry Andric                     FlagValue(F.NoUnwind),
47477fc4c14SDimitry Andric                     FlagValue(F.MayThrow),
47577fc4c14SDimitry Andric                     FlagValue(F.HasUnknownCall),
47677fc4c14SDimitry Andric                     FlagValue(F.MustBeUnreachable),
47777fc4c14SDimitry Andric                     0};
478eb11fae6SDimitry Andric 
479eb11fae6SDimitry Andric   return FlagRep;
480eb11fae6SDimitry Andric }
481eb11fae6SDimitry Andric 
482eb11fae6SDimitry Andric // Get string representation of function instruction count and flags.
getSummaryAttributes(GlobalValueSummary * GVS)483eb11fae6SDimitry Andric static std::string getSummaryAttributes(GlobalValueSummary* GVS) {
484eb11fae6SDimitry Andric   auto *FS = dyn_cast_or_null<FunctionSummary>(GVS);
485eb11fae6SDimitry Andric   if (!FS)
486eb11fae6SDimitry Andric     return "";
487eb11fae6SDimitry Andric 
488eb11fae6SDimitry Andric   return std::string("inst: ") + std::to_string(FS->instCount()) +
489eb11fae6SDimitry Andric          ", ffl: " + fflagsToString(FS->fflags());
490eb11fae6SDimitry Andric }
491eb11fae6SDimitry Andric 
getNodeVisualName(GlobalValue::GUID Id)492d8e91e46SDimitry Andric static std::string getNodeVisualName(GlobalValue::GUID Id) {
493d8e91e46SDimitry Andric   return std::string("@") + std::to_string(Id);
494d8e91e46SDimitry Andric }
495d8e91e46SDimitry Andric 
getNodeVisualName(const ValueInfo & VI)496eb11fae6SDimitry Andric static std::string getNodeVisualName(const ValueInfo &VI) {
497d8e91e46SDimitry Andric   return VI.name().empty() ? getNodeVisualName(VI.getGUID()) : VI.name().str();
498eb11fae6SDimitry Andric }
499eb11fae6SDimitry Andric 
getNodeLabel(const ValueInfo & VI,GlobalValueSummary * GVS)500eb11fae6SDimitry Andric static std::string getNodeLabel(const ValueInfo &VI, GlobalValueSummary *GVS) {
501eb11fae6SDimitry Andric   if (isa<AliasSummary>(GVS))
502eb11fae6SDimitry Andric     return getNodeVisualName(VI);
503eb11fae6SDimitry Andric 
504eb11fae6SDimitry Andric   std::string Attrs = getSummaryAttributes(GVS);
505eb11fae6SDimitry Andric   std::string Label =
506eb11fae6SDimitry Andric       getNodeVisualName(VI) + "|" + linkageToString(GVS->linkage());
507eb11fae6SDimitry Andric   if (!Attrs.empty())
508eb11fae6SDimitry Andric     Label += std::string(" (") + Attrs + ")";
509eb11fae6SDimitry Andric   Label += "}";
510eb11fae6SDimitry Andric 
511eb11fae6SDimitry Andric   return Label;
512eb11fae6SDimitry Andric }
513eb11fae6SDimitry Andric 
514eb11fae6SDimitry Andric // Write definition of external node, which doesn't have any
515eb11fae6SDimitry Andric // specific module associated with it. Typically this is function
516eb11fae6SDimitry Andric // or variable defined in native object or library.
defineExternalNode(raw_ostream & OS,const char * Pfx,const ValueInfo & VI,GlobalValue::GUID Id)517eb11fae6SDimitry Andric static void defineExternalNode(raw_ostream &OS, const char *Pfx,
518d8e91e46SDimitry Andric                                const ValueInfo &VI, GlobalValue::GUID Id) {
519d8e91e46SDimitry Andric   auto StrId = std::to_string(Id);
520d8e91e46SDimitry Andric   OS << "  " << StrId << " [label=\"";
521d8e91e46SDimitry Andric 
522d8e91e46SDimitry Andric   if (VI) {
523d8e91e46SDimitry Andric     OS << getNodeVisualName(VI);
524d8e91e46SDimitry Andric   } else {
525d8e91e46SDimitry Andric     OS << getNodeVisualName(Id);
526d8e91e46SDimitry Andric   }
527d8e91e46SDimitry Andric   OS << "\"]; // defined externally\n";
528d8e91e46SDimitry Andric }
529d8e91e46SDimitry Andric 
hasReadOnlyFlag(const GlobalValueSummary * S)530d8e91e46SDimitry Andric static bool hasReadOnlyFlag(const GlobalValueSummary *S) {
531d8e91e46SDimitry Andric   if (auto *GVS = dyn_cast<GlobalVarSummary>(S))
532e6d15924SDimitry Andric     return GVS->maybeReadOnly();
533e6d15924SDimitry Andric   return false;
534e6d15924SDimitry Andric }
535e6d15924SDimitry Andric 
hasWriteOnlyFlag(const GlobalValueSummary * S)536e6d15924SDimitry Andric static bool hasWriteOnlyFlag(const GlobalValueSummary *S) {
537e6d15924SDimitry Andric   if (auto *GVS = dyn_cast<GlobalVarSummary>(S))
538e6d15924SDimitry Andric     return GVS->maybeWriteOnly();
539d8e91e46SDimitry Andric   return false;
540eb11fae6SDimitry Andric }
541eb11fae6SDimitry Andric 
hasConstantFlag(const GlobalValueSummary * S)542cfca06d7SDimitry Andric static bool hasConstantFlag(const GlobalValueSummary *S) {
543cfca06d7SDimitry Andric   if (auto *GVS = dyn_cast<GlobalVarSummary>(S))
544cfca06d7SDimitry Andric     return GVS->isConstant();
545cfca06d7SDimitry Andric   return false;
546cfca06d7SDimitry Andric }
547cfca06d7SDimitry Andric 
exportToDot(raw_ostream & OS,const DenseSet<GlobalValue::GUID> & GUIDPreservedSymbols) const548706b4fc4SDimitry Andric void ModuleSummaryIndex::exportToDot(
549706b4fc4SDimitry Andric     raw_ostream &OS,
550706b4fc4SDimitry Andric     const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) const {
551eb11fae6SDimitry Andric   std::vector<Edge> CrossModuleEdges;
552eb11fae6SDimitry Andric   DenseMap<GlobalValue::GUID, std::vector<uint64_t>> NodeMap;
553e6d15924SDimitry Andric   using GVSOrderedMapTy = std::map<GlobalValue::GUID, GlobalValueSummary *>;
554e6d15924SDimitry Andric   std::map<StringRef, GVSOrderedMapTy> ModuleToDefinedGVS;
555eb11fae6SDimitry Andric   collectDefinedGVSummariesPerModule(ModuleToDefinedGVS);
556eb11fae6SDimitry Andric 
557b1c73532SDimitry Andric   // Assign an id to each module path for use in graph labels. Since the
558b1c73532SDimitry Andric   // StringMap iteration order isn't guaranteed, order by path string before
559b1c73532SDimitry Andric   // assigning ids.
560b1c73532SDimitry Andric   std::vector<StringRef> ModulePaths;
561b1c73532SDimitry Andric   for (auto &[ModPath, _] : modulePaths())
562b1c73532SDimitry Andric     ModulePaths.push_back(ModPath);
563b1c73532SDimitry Andric   llvm::sort(ModulePaths);
564b1c73532SDimitry Andric   DenseMap<StringRef, uint64_t> ModuleIdMap;
565b1c73532SDimitry Andric   for (auto &ModPath : ModulePaths)
566b1c73532SDimitry Andric     ModuleIdMap.try_emplace(ModPath, ModuleIdMap.size());
567b1c73532SDimitry Andric 
568eb11fae6SDimitry Andric   // Get node identifier in form MXXX_<GUID>. The MXXX prefix is required,
569eb11fae6SDimitry Andric   // because we may have multiple linkonce functions summaries.
570eb11fae6SDimitry Andric   auto NodeId = [](uint64_t ModId, GlobalValue::GUID Id) {
571eb11fae6SDimitry Andric     return ModId == (uint64_t)-1 ? std::to_string(Id)
572eb11fae6SDimitry Andric                                  : std::string("M") + std::to_string(ModId) +
573eb11fae6SDimitry Andric                                        "_" + std::to_string(Id);
574eb11fae6SDimitry Andric   };
575eb11fae6SDimitry Andric 
576d8e91e46SDimitry Andric   auto DrawEdge = [&](const char *Pfx, uint64_t SrcMod, GlobalValue::GUID SrcId,
577d8e91e46SDimitry Andric                       uint64_t DstMod, GlobalValue::GUID DstId,
578d8e91e46SDimitry Andric                       int TypeOrHotness) {
579d8e91e46SDimitry Andric     // 0 - alias
580d8e91e46SDimitry Andric     // 1 - reference
581d8e91e46SDimitry Andric     // 2 - constant reference
582e6d15924SDimitry Andric     // 3 - writeonly reference
583e6d15924SDimitry Andric     // Other value: (hotness - 4).
584e6d15924SDimitry Andric     TypeOrHotness += 4;
585eb11fae6SDimitry Andric     static const char *EdgeAttrs[] = {
586eb11fae6SDimitry Andric         " [style=dotted]; // alias",
587eb11fae6SDimitry Andric         " [style=dashed]; // ref",
588d8e91e46SDimitry Andric         " [style=dashed,color=forestgreen]; // const-ref",
589e6d15924SDimitry Andric         " [style=dashed,color=violetred]; // writeOnly-ref",
590eb11fae6SDimitry Andric         " // call (hotness : Unknown)",
591eb11fae6SDimitry Andric         " [color=blue]; // call (hotness : Cold)",
592eb11fae6SDimitry Andric         " // call (hotness : None)",
593eb11fae6SDimitry Andric         " [color=brown]; // call (hotness : Hot)",
594eb11fae6SDimitry Andric         " [style=bold,color=red]; // call (hotness : Critical)"};
595eb11fae6SDimitry Andric 
596e3b55780SDimitry Andric     assert(static_cast<size_t>(TypeOrHotness) < std::size(EdgeAttrs));
597eb11fae6SDimitry Andric     OS << Pfx << NodeId(SrcMod, SrcId) << " -> " << NodeId(DstMod, DstId)
598eb11fae6SDimitry Andric        << EdgeAttrs[TypeOrHotness] << "\n";
599eb11fae6SDimitry Andric   };
600eb11fae6SDimitry Andric 
601eb11fae6SDimitry Andric   OS << "digraph Summary {\n";
602eb11fae6SDimitry Andric   for (auto &ModIt : ModuleToDefinedGVS) {
603b1c73532SDimitry Andric     // Will be empty for a just built per-module index, which doesn't setup a
604b1c73532SDimitry Andric     // module paths table. In that case use 0 as the module id.
605b1c73532SDimitry Andric     assert(ModuleIdMap.count(ModIt.first) || ModuleIdMap.empty());
606b1c73532SDimitry Andric     auto ModId = ModuleIdMap.empty() ? 0 : ModuleIdMap[ModIt.first];
607e6d15924SDimitry Andric     OS << "  // Module: " << ModIt.first << "\n";
608eb11fae6SDimitry Andric     OS << "  subgraph cluster_" << std::to_string(ModId) << " {\n";
609eb11fae6SDimitry Andric     OS << "    style = filled;\n";
610eb11fae6SDimitry Andric     OS << "    color = lightgrey;\n";
611e6d15924SDimitry Andric     OS << "    label = \"" << sys::path::filename(ModIt.first) << "\";\n";
612eb11fae6SDimitry Andric     OS << "    node [style=filled,fillcolor=lightblue];\n";
613eb11fae6SDimitry Andric 
614eb11fae6SDimitry Andric     auto &GVSMap = ModIt.second;
615eb11fae6SDimitry Andric     auto Draw = [&](GlobalValue::GUID IdFrom, GlobalValue::GUID IdTo, int Hotness) {
616eb11fae6SDimitry Andric       if (!GVSMap.count(IdTo)) {
617eb11fae6SDimitry Andric         CrossModuleEdges.push_back({ModId, Hotness, IdFrom, IdTo});
618eb11fae6SDimitry Andric         return;
619eb11fae6SDimitry Andric       }
620eb11fae6SDimitry Andric       DrawEdge("    ", ModId, IdFrom, ModId, IdTo, Hotness);
621eb11fae6SDimitry Andric     };
622eb11fae6SDimitry Andric 
623eb11fae6SDimitry Andric     for (auto &SummaryIt : GVSMap) {
624eb11fae6SDimitry Andric       NodeMap[SummaryIt.first].push_back(ModId);
625eb11fae6SDimitry Andric       auto Flags = SummaryIt.second->flags();
626eb11fae6SDimitry Andric       Attributes A;
627eb11fae6SDimitry Andric       if (isa<FunctionSummary>(SummaryIt.second)) {
628eb11fae6SDimitry Andric         A.add("shape", "record", "function");
629eb11fae6SDimitry Andric       } else if (isa<AliasSummary>(SummaryIt.second)) {
630eb11fae6SDimitry Andric         A.add("style", "dotted,filled", "alias");
631eb11fae6SDimitry Andric         A.add("shape", "box");
632eb11fae6SDimitry Andric       } else {
633eb11fae6SDimitry Andric         A.add("shape", "Mrecord", "variable");
634d8e91e46SDimitry Andric         if (Flags.Live && hasReadOnlyFlag(SummaryIt.second))
635d8e91e46SDimitry Andric           A.addComment("immutable");
636e6d15924SDimitry Andric         if (Flags.Live && hasWriteOnlyFlag(SummaryIt.second))
637e6d15924SDimitry Andric           A.addComment("writeOnly");
638cfca06d7SDimitry Andric         if (Flags.Live && hasConstantFlag(SummaryIt.second))
639cfca06d7SDimitry Andric           A.addComment("constant");
640eb11fae6SDimitry Andric       }
641344a3780SDimitry Andric       if (Flags.Visibility)
642344a3780SDimitry Andric         A.addComment("visibility");
643e6d15924SDimitry Andric       if (Flags.DSOLocal)
644e6d15924SDimitry Andric         A.addComment("dsoLocal");
645e6d15924SDimitry Andric       if (Flags.CanAutoHide)
646e6d15924SDimitry Andric         A.addComment("canAutoHide");
647ac9a064cSDimitry Andric       if (Flags.ImportType == GlobalValueSummary::ImportKind::Definition)
648ac9a064cSDimitry Andric         A.addComment("definition");
649ac9a064cSDimitry Andric       else if (Flags.ImportType == GlobalValueSummary::ImportKind::Declaration)
650ac9a064cSDimitry Andric         A.addComment("declaration");
651706b4fc4SDimitry Andric       if (GUIDPreservedSymbols.count(SummaryIt.first))
652706b4fc4SDimitry Andric         A.addComment("preserved");
653eb11fae6SDimitry Andric 
654eb11fae6SDimitry Andric       auto VI = getValueInfo(SummaryIt.first);
655eb11fae6SDimitry Andric       A.add("label", getNodeLabel(VI, SummaryIt.second));
656eb11fae6SDimitry Andric       if (!Flags.Live)
657eb11fae6SDimitry Andric         A.add("fillcolor", "red", "dead");
658eb11fae6SDimitry Andric       else if (Flags.NotEligibleToImport)
659eb11fae6SDimitry Andric         A.add("fillcolor", "yellow", "not eligible to import");
660eb11fae6SDimitry Andric 
661eb11fae6SDimitry Andric       OS << "    " << NodeId(ModId, SummaryIt.first) << " " << A.getAsString()
662eb11fae6SDimitry Andric          << "\n";
663eb11fae6SDimitry Andric     }
664eb11fae6SDimitry Andric     OS << "    // Edges:\n";
665eb11fae6SDimitry Andric 
666eb11fae6SDimitry Andric     for (auto &SummaryIt : GVSMap) {
667eb11fae6SDimitry Andric       auto *GVS = SummaryIt.second;
668eb11fae6SDimitry Andric       for (auto &R : GVS->refs())
669e6d15924SDimitry Andric         Draw(SummaryIt.first, R.getGUID(),
670e6d15924SDimitry Andric              R.isWriteOnly() ? -1 : (R.isReadOnly() ? -2 : -3));
671eb11fae6SDimitry Andric 
672eb11fae6SDimitry Andric       if (auto *AS = dyn_cast_or_null<AliasSummary>(SummaryIt.second)) {
673e6d15924SDimitry Andric         Draw(SummaryIt.first, AS->getAliaseeGUID(), -4);
674eb11fae6SDimitry Andric         continue;
675eb11fae6SDimitry Andric       }
676eb11fae6SDimitry Andric 
677eb11fae6SDimitry Andric       if (auto *FS = dyn_cast_or_null<FunctionSummary>(SummaryIt.second))
678eb11fae6SDimitry Andric         for (auto &CGEdge : FS->calls())
679eb11fae6SDimitry Andric           Draw(SummaryIt.first, CGEdge.first.getGUID(),
680eb11fae6SDimitry Andric                static_cast<int>(CGEdge.second.Hotness));
681eb11fae6SDimitry Andric     }
682eb11fae6SDimitry Andric     OS << "  }\n";
683eb11fae6SDimitry Andric   }
684eb11fae6SDimitry Andric 
685eb11fae6SDimitry Andric   OS << "  // Cross-module edges:\n";
686eb11fae6SDimitry Andric   for (auto &E : CrossModuleEdges) {
687eb11fae6SDimitry Andric     auto &ModList = NodeMap[E.Dst];
688eb11fae6SDimitry Andric     if (ModList.empty()) {
689d8e91e46SDimitry Andric       defineExternalNode(OS, "  ", getValueInfo(E.Dst), E.Dst);
690eb11fae6SDimitry Andric       // Add fake module to the list to draw an edge to an external node
691eb11fae6SDimitry Andric       // in the loop below.
692eb11fae6SDimitry Andric       ModList.push_back(-1);
693eb11fae6SDimitry Andric     }
694eb11fae6SDimitry Andric     for (auto DstMod : ModList)
695eb11fae6SDimitry Andric       // The edge representing call or ref is drawn to every module where target
696eb11fae6SDimitry Andric       // symbol is defined. When target is a linkonce symbol there can be
697eb11fae6SDimitry Andric       // multiple edges representing a single call or ref, both intra-module and
698eb11fae6SDimitry Andric       // cross-module. As we've already drawn all intra-module edges before we
699eb11fae6SDimitry Andric       // skip it here.
700eb11fae6SDimitry Andric       if (DstMod != E.SrcMod)
701eb11fae6SDimitry Andric         DrawEdge("  ", E.SrcMod, E.Src, DstMod, E.Dst, E.Hotness);
702eb11fae6SDimitry Andric   }
703eb11fae6SDimitry Andric 
704eb11fae6SDimitry Andric   OS << "}";
705eb11fae6SDimitry Andric }
706