ModuleSummaryIndex.cpp 17 KB

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