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