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