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