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