1 //===-- ModuleSummaryIndex.cpp - Module Summary Index ---------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the module index and summary classes for the
13 //===----------------------------------------------------------------------===//
15 #include "llvm/IR/ModuleSummaryIndex.h"
16 #include "llvm/ADT/SCCIterator.h"
17 #include "llvm/ADT/StringMap.h"
18 #include "llvm/Support/Path.h"
19 #include "llvm/Support/raw_ostream.h"
22 FunctionSummary
FunctionSummary::ExternalNode
=
23 FunctionSummary::makeDummyFunctionSummary({});
24 bool ValueInfo::isDSOLocal() const {
25 // Need to check all summaries are local in case of hash collisions.
26 return getSummaryList().size() &&
27 llvm::all_of(getSummaryList(),
28 [](const std::unique_ptr
<GlobalValueSummary
> &Summary
) {
29 return Summary
->isDSOLocal();
33 // Collect for the given module the list of function it defines
35 void ModuleSummaryIndex::collectDefinedFunctionsForModule(
36 StringRef ModulePath
, GVSummaryMapTy
&GVSummaryMap
) const {
37 for (auto &GlobalList
: *this) {
38 auto GUID
= GlobalList
.first
;
39 for (auto &GlobSummary
: GlobalList
.second
.SummaryList
) {
40 auto *Summary
= dyn_cast_or_null
<FunctionSummary
>(GlobSummary
.get());
42 // Ignore global variable, focus on functions
44 // Ignore summaries from other modules.
45 if (Summary
->modulePath() != ModulePath
)
47 GVSummaryMap
[GUID
] = Summary
;
52 // Collect for each module the list of function it defines (GUID -> Summary).
53 void ModuleSummaryIndex::collectDefinedGVSummariesPerModule(
54 StringMap
<GVSummaryMapTy
> &ModuleToDefinedGVSummaries
) const {
55 for (auto &GlobalList
: *this) {
56 auto GUID
= GlobalList
.first
;
57 for (auto &Summary
: GlobalList
.second
.SummaryList
) {
58 ModuleToDefinedGVSummaries
[Summary
->modulePath()][GUID
] = Summary
.get();
64 ModuleSummaryIndex::getGlobalValueSummary(uint64_t ValueGUID
,
65 bool PerModuleIndex
) const {
66 auto VI
= getValueInfo(ValueGUID
);
67 assert(VI
&& "GlobalValue not found in index");
68 assert((!PerModuleIndex
|| VI
.getSummaryList().size() == 1) &&
69 "Expected a single entry per global value in per-module index");
70 auto &Summary
= VI
.getSummaryList()[0];
74 bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID
) const {
75 auto VI
= getValueInfo(GUID
);
78 const auto &SummaryList
= VI
.getSummaryList();
79 if (SummaryList
.empty())
81 for (auto &I
: SummaryList
)
82 if (isGlobalValueLive(I
.get()))
87 // TODO: write a graphviz dumper for SCCs (see ModuleSummaryIndex::exportToDot)
88 // then delete this function and update its tests
90 void ModuleSummaryIndex::dumpSCCs(raw_ostream
&O
) {
91 for (scc_iterator
<ModuleSummaryIndex
*> I
=
92 scc_begin
<ModuleSummaryIndex
*>(this);
94 O
<< "SCC (" << utostr(I
->size()) << " node" << (I
->size() == 1 ? "" : "s")
96 for (const ValueInfo V
: *I
) {
97 FunctionSummary
*F
= nullptr;
98 if (V
.getSummaryList().size())
99 F
= cast
<FunctionSummary
>(V
.getSummaryList().front().get());
100 O
<< " " << (F
== nullptr ? "External" : "") << " " << utostr(V
.getGUID())
101 << (I
.hasLoop() ? " (has loop)" : "") << "\n";
109 void add(const Twine
&Name
, const Twine
&Value
,
110 const Twine
&Comment
= Twine());
111 std::string
getAsString() const;
113 std::vector
<std::string
> Attrs
;
114 std::string Comments
;
120 GlobalValue::GUID Src
;
121 GlobalValue::GUID Dst
;
125 void Attributes::add(const Twine
&Name
, const Twine
&Value
,
126 const Twine
&Comment
) {
127 std::string A
= Name
.str();
132 if (!Comment
.isTriviallyEmpty()) {
133 if (Comments
.empty())
137 Comments
+= Comment
.str();
141 std::string
Attributes::getAsString() const {
145 std::string Ret
= "[";
146 for (auto &A
: Attrs
)
154 static std::string
linkageToString(GlobalValue::LinkageTypes LT
) {
156 case GlobalValue::ExternalLinkage
:
158 case GlobalValue::AvailableExternallyLinkage
:
160 case GlobalValue::LinkOnceAnyLinkage
:
162 case GlobalValue::LinkOnceODRLinkage
:
163 return "linkonce_odr";
164 case GlobalValue::WeakAnyLinkage
:
166 case GlobalValue::WeakODRLinkage
:
168 case GlobalValue::AppendingLinkage
:
170 case GlobalValue::InternalLinkage
:
172 case GlobalValue::PrivateLinkage
:
174 case GlobalValue::ExternalWeakLinkage
:
175 return "extern_weak";
176 case GlobalValue::CommonLinkage
:
183 static std::string
fflagsToString(FunctionSummary::FFlags F
) {
184 auto FlagValue
= [](unsigned V
) { return V
? '1' : '0'; };
185 char FlagRep
[] = {FlagValue(F
.ReadNone
), FlagValue(F
.ReadOnly
),
186 FlagValue(F
.NoRecurse
), FlagValue(F
.ReturnDoesNotAlias
), 0};
191 // Get string representation of function instruction count and flags.
192 static std::string
getSummaryAttributes(GlobalValueSummary
* GVS
) {
193 auto *FS
= dyn_cast_or_null
<FunctionSummary
>(GVS
);
197 return std::string("inst: ") + std::to_string(FS
->instCount()) +
198 ", ffl: " + fflagsToString(FS
->fflags());
201 static std::string
getNodeVisualName(const ValueInfo
&VI
) {
202 return VI
.name().empty() ? std::string("@") + std::to_string(VI
.getGUID())
206 static std::string
getNodeLabel(const ValueInfo
&VI
, GlobalValueSummary
*GVS
) {
207 if (isa
<AliasSummary
>(GVS
))
208 return getNodeVisualName(VI
);
210 std::string Attrs
= getSummaryAttributes(GVS
);
212 getNodeVisualName(VI
) + "|" + linkageToString(GVS
->linkage());
214 Label
+= std::string(" (") + Attrs
+ ")";
220 // Write definition of external node, which doesn't have any
221 // specific module associated with it. Typically this is function
222 // or variable defined in native object or library.
223 static void defineExternalNode(raw_ostream
&OS
, const char *Pfx
,
224 const ValueInfo
&VI
) {
225 auto StrId
= std::to_string(VI
.getGUID());
226 OS
<< " " << StrId
<< " [label=\"" << getNodeVisualName(VI
)
227 << "\"]; // defined externally\n";
230 void ModuleSummaryIndex::exportToDot(raw_ostream
& OS
) const {
231 std::vector
<Edge
> CrossModuleEdges
;
232 DenseMap
<GlobalValue::GUID
, std::vector
<uint64_t>> NodeMap
;
233 StringMap
<GVSummaryMapTy
> ModuleToDefinedGVS
;
234 collectDefinedGVSummariesPerModule(ModuleToDefinedGVS
);
236 // Get node identifier in form MXXX_<GUID>. The MXXX prefix is required,
237 // because we may have multiple linkonce functions summaries.
238 auto NodeId
= [](uint64_t ModId
, GlobalValue::GUID Id
) {
239 return ModId
== (uint64_t)-1 ? std::to_string(Id
)
240 : std::string("M") + std::to_string(ModId
) +
241 "_" + std::to_string(Id
);
244 auto DrawEdge
= [&](const char *Pfx
, int SrcMod
, GlobalValue::GUID SrcId
,
245 int DstMod
, GlobalValue::GUID DstId
, int TypeOrHotness
) {
246 // 0 corresponds to alias edge, 1 to ref edge, 2 to call with unknown
249 static const char *EdgeAttrs
[] = {
250 " [style=dotted]; // alias",
251 " [style=dashed]; // ref",
252 " // call (hotness : Unknown)",
253 " [color=blue]; // call (hotness : Cold)",
254 " // call (hotness : None)",
255 " [color=brown]; // call (hotness : Hot)",
256 " [style=bold,color=red]; // call (hotness : Critical)"};
258 assert(static_cast<size_t>(TypeOrHotness
) <
259 sizeof(EdgeAttrs
) / sizeof(EdgeAttrs
[0]));
260 OS
<< Pfx
<< NodeId(SrcMod
, SrcId
) << " -> " << NodeId(DstMod
, DstId
)
261 << EdgeAttrs
[TypeOrHotness
] << "\n";
264 OS
<< "digraph Summary {\n";
265 for (auto &ModIt
: ModuleToDefinedGVS
) {
266 auto ModId
= getModuleId(ModIt
.first());
267 OS
<< " // Module: " << ModIt
.first() << "\n";
268 OS
<< " subgraph cluster_" << std::to_string(ModId
) << " {\n";
269 OS
<< " style = filled;\n";
270 OS
<< " color = lightgrey;\n";
271 OS
<< " label = \"" << sys::path::filename(ModIt
.first()) << "\";\n";
272 OS
<< " node [style=filled,fillcolor=lightblue];\n";
274 auto &GVSMap
= ModIt
.second
;
275 auto Draw
= [&](GlobalValue::GUID IdFrom
, GlobalValue::GUID IdTo
, int Hotness
) {
276 if (!GVSMap
.count(IdTo
)) {
277 CrossModuleEdges
.push_back({ModId
, Hotness
, IdFrom
, IdTo
});
280 DrawEdge(" ", ModId
, IdFrom
, ModId
, IdTo
, Hotness
);
283 for (auto &SummaryIt
: GVSMap
) {
284 NodeMap
[SummaryIt
.first
].push_back(ModId
);
285 auto Flags
= SummaryIt
.second
->flags();
287 if (isa
<FunctionSummary
>(SummaryIt
.second
)) {
288 A
.add("shape", "record", "function");
289 } else if (isa
<AliasSummary
>(SummaryIt
.second
)) {
290 A
.add("style", "dotted,filled", "alias");
291 A
.add("shape", "box");
293 A
.add("shape", "Mrecord", "variable");
296 auto VI
= getValueInfo(SummaryIt
.first
);
297 A
.add("label", getNodeLabel(VI
, SummaryIt
.second
));
299 A
.add("fillcolor", "red", "dead");
300 else if (Flags
.NotEligibleToImport
)
301 A
.add("fillcolor", "yellow", "not eligible to import");
303 OS
<< " " << NodeId(ModId
, SummaryIt
.first
) << " " << A
.getAsString()
306 OS
<< " // Edges:\n";
308 for (auto &SummaryIt
: GVSMap
) {
309 auto *GVS
= SummaryIt
.second
;
310 for (auto &R
: GVS
->refs())
311 Draw(SummaryIt
.first
, R
.getGUID(), -1);
313 if (auto *AS
= dyn_cast_or_null
<AliasSummary
>(SummaryIt
.second
)) {
314 auto AliaseeOrigId
= AS
->getAliasee().getOriginalName();
315 auto AliaseeId
= getGUIDFromOriginalID(AliaseeOrigId
);
317 Draw(SummaryIt
.first
, AliaseeId
? AliaseeId
: AliaseeOrigId
, -2);
321 if (auto *FS
= dyn_cast_or_null
<FunctionSummary
>(SummaryIt
.second
))
322 for (auto &CGEdge
: FS
->calls())
323 Draw(SummaryIt
.first
, CGEdge
.first
.getGUID(),
324 static_cast<int>(CGEdge
.second
.Hotness
));
329 OS
<< " // Cross-module edges:\n";
330 for (auto &E
: CrossModuleEdges
) {
331 auto &ModList
= NodeMap
[E
.Dst
];
332 if (ModList
.empty()) {
333 defineExternalNode(OS
, " ", getValueInfo(E
.Dst
));
334 // Add fake module to the list to draw an edge to an external node
335 // in the loop below.
336 ModList
.push_back(-1);
338 for (auto DstMod
: ModList
)
339 // The edge representing call or ref is drawn to every module where target
340 // symbol is defined. When target is a linkonce symbol there can be
341 // multiple edges representing a single call or ref, both intra-module and
342 // cross-module. As we've already drawn all intra-module edges before we
344 if (DstMod
!= E
.SrcMod
)
345 DrawEdge(" ", E
.SrcMod
, E
.Src
, DstMod
, E
.Dst
, E
.Hotness
);