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