126ab5772STeresa Johnson //===-- ModuleSummaryIndex.cpp - Module Summary Index ---------------------===// 226ab5772STeresa Johnson // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 626ab5772STeresa Johnson // 726ab5772STeresa Johnson //===----------------------------------------------------------------------===// 826ab5772STeresa Johnson // 926ab5772STeresa Johnson // This file implements the module index and summary classes for the 1026ab5772STeresa Johnson // IR library. 1126ab5772STeresa Johnson // 1226ab5772STeresa Johnson //===----------------------------------------------------------------------===// 1326ab5772STeresa Johnson 1426ab5772STeresa Johnson #include "llvm/IR/ModuleSummaryIndex.h" 15b040fcc6SCharles Saternos #include "llvm/ADT/SCCIterator.h" 168c1915ccSTeresa Johnson #include "llvm/ADT/Statistic.h" 1726ab5772STeresa Johnson #include "llvm/ADT/StringMap.h" 1828d8a49fSEugene Leviant #include "llvm/Support/Path.h" 19b040fcc6SCharles Saternos #include "llvm/Support/raw_ostream.h" 2026ab5772STeresa Johnson using namespace llvm; 2126ab5772STeresa Johnson 228c1915ccSTeresa Johnson #define DEBUG_TYPE "module-summary-index" 238c1915ccSTeresa Johnson 248c1915ccSTeresa Johnson STATISTIC(ReadOnlyLiveGVars, 258c1915ccSTeresa Johnson "Number of live global variables marked read only"); 263aef3528SEugene Leviant STATISTIC(WriteOnlyLiveGVars, 273aef3528SEugene Leviant "Number of live global variables marked write only"); 288c1915ccSTeresa Johnson 29b040fcc6SCharles Saternos FunctionSummary FunctionSummary::ExternalNode = 30b040fcc6SCharles Saternos FunctionSummary::makeDummyFunctionSummary({}); 3137b80122STeresa Johnson 32b4edfb9aSPeter Collingbourne bool ValueInfo::isDSOLocal() const { 33b4edfb9aSPeter Collingbourne // Need to check all summaries are local in case of hash collisions. 34b4edfb9aSPeter Collingbourne return getSummaryList().size() && 35b4edfb9aSPeter Collingbourne llvm::all_of(getSummaryList(), 36b4edfb9aSPeter Collingbourne [](const std::unique_ptr<GlobalValueSummary> &Summary) { 37b4edfb9aSPeter Collingbourne return Summary->isDSOLocal(); 38b4edfb9aSPeter Collingbourne }); 39b4edfb9aSPeter Collingbourne } 40b4edfb9aSPeter Collingbourne 4137b80122STeresa Johnson bool ValueInfo::canAutoHide() const { 4237b80122STeresa Johnson // Can only auto hide if all copies are eligible to auto hide. 4337b80122STeresa Johnson return getSummaryList().size() && 4437b80122STeresa Johnson llvm::all_of(getSummaryList(), 4537b80122STeresa Johnson [](const std::unique_ptr<GlobalValueSummary> &Summary) { 4637b80122STeresa Johnson return Summary->canAutoHide(); 4737b80122STeresa Johnson }); 4837b80122STeresa Johnson } 4937b80122STeresa Johnson 503aef3528SEugene Leviant // Gets the number of readonly and writeonly refs in RefEdgeList 513aef3528SEugene Leviant std::pair<unsigned, unsigned> FunctionSummary::specialRefCounts() const { 523aef3528SEugene Leviant // Here we take advantage of having all readonly and writeonly references 53bf46e741SEugene Leviant // located in the end of the RefEdgeList. 54bf46e741SEugene Leviant auto Refs = refs(); 553aef3528SEugene Leviant unsigned RORefCnt = 0, WORefCnt = 0; 563aef3528SEugene Leviant int I; 573aef3528SEugene Leviant for (I = Refs.size() - 1; I >= 0 && Refs[I].isWriteOnly(); --I) 583aef3528SEugene Leviant WORefCnt++; 593aef3528SEugene Leviant for (; I >= 0 && Refs[I].isReadOnly(); --I) 603aef3528SEugene Leviant RORefCnt++; 613aef3528SEugene Leviant return {RORefCnt, WORefCnt}; 62bf46e741SEugene Leviant } 63bf46e741SEugene Leviant 64c86af334STeresa Johnson // Collect for the given module the list of function it defines 65c86af334STeresa Johnson // (GUID -> Summary). 66c86af334STeresa Johnson void ModuleSummaryIndex::collectDefinedFunctionsForModule( 67c851d216STeresa Johnson StringRef ModulePath, GVSummaryMapTy &GVSummaryMap) const { 68c86af334STeresa Johnson for (auto &GlobalList : *this) { 69c86af334STeresa Johnson auto GUID = GlobalList.first; 709667b91bSPeter Collingbourne for (auto &GlobSummary : GlobalList.second.SummaryList) { 7128e457bcSTeresa Johnson auto *Summary = dyn_cast_or_null<FunctionSummary>(GlobSummary.get()); 72c86af334STeresa Johnson if (!Summary) 73c86af334STeresa Johnson // Ignore global variable, focus on functions 74c86af334STeresa Johnson continue; 75c86af334STeresa Johnson // Ignore summaries from other modules. 76c86af334STeresa Johnson if (Summary->modulePath() != ModulePath) 77c86af334STeresa Johnson continue; 7828e457bcSTeresa Johnson GVSummaryMap[GUID] = Summary; 79c86af334STeresa Johnson } 80c86af334STeresa Johnson } 81c86af334STeresa Johnson } 82c86af334STeresa Johnson 8328e457bcSTeresa Johnson GlobalValueSummary * 8428e457bcSTeresa Johnson ModuleSummaryIndex::getGlobalValueSummary(uint64_t ValueGUID, 85fb7c7644STeresa Johnson bool PerModuleIndex) const { 869667b91bSPeter Collingbourne auto VI = getValueInfo(ValueGUID); 879667b91bSPeter Collingbourne assert(VI && "GlobalValue not found in index"); 889667b91bSPeter Collingbourne assert((!PerModuleIndex || VI.getSummaryList().size() == 1) && 89fb7c7644STeresa Johnson "Expected a single entry per global value in per-module index"); 909667b91bSPeter Collingbourne auto &Summary = VI.getSummaryList()[0]; 9128e457bcSTeresa Johnson return Summary.get(); 92fb7c7644STeresa Johnson } 93dbd2fed6SPeter Collingbourne 94dbd2fed6SPeter Collingbourne bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID) const { 95dbd2fed6SPeter Collingbourne auto VI = getValueInfo(GUID); 96dbd2fed6SPeter Collingbourne if (!VI) 974d4ee93dSEvgeniy Stepanov return true; 984d4ee93dSEvgeniy Stepanov const auto &SummaryList = VI.getSummaryList(); 994d4ee93dSEvgeniy Stepanov if (SummaryList.empty()) 1004d4ee93dSEvgeniy Stepanov return true; 1014d4ee93dSEvgeniy Stepanov for (auto &I : SummaryList) 102dbd2fed6SPeter Collingbourne if (isGlobalValueLive(I.get())) 103dbd2fed6SPeter Collingbourne return true; 104dbd2fed6SPeter Collingbourne return false; 105dbd2fed6SPeter Collingbourne } 10628d8a49fSEugene Leviant 1073aef3528SEugene Leviant static void propagateAttributesToRefs(GlobalValueSummary *S) { 1083aef3528SEugene Leviant // If reference is not readonly or writeonly then referenced summary is not 1093aef3528SEugene Leviant // read/writeonly either. Note that: 110bf46e741SEugene Leviant // - All references from GlobalVarSummary are conservatively considered as 1113aef3528SEugene Leviant // not readonly or writeonly. Tracking them properly requires more complex 1123aef3528SEugene Leviant // analysis then we have now. 113bf46e741SEugene Leviant // 114bf46e741SEugene Leviant // - AliasSummary objects have no refs at all so this function is a no-op 115bf46e741SEugene Leviant // for them. 116bf46e741SEugene Leviant for (auto &VI : S->refs()) { 1173aef3528SEugene Leviant assert(VI.getAccessSpecifier() == 0 || isa<FunctionSummary>(S)); 118e91f86f0SEugene Leviant for (auto &Ref : VI.getSummaryList()) 1193aef3528SEugene Leviant // If references to alias is not read/writeonly then aliasee 1203aef3528SEugene Leviant // is not read/writeonly 1213aef3528SEugene Leviant if (auto *GVS = dyn_cast<GlobalVarSummary>(Ref->getBaseObject())) { 1223aef3528SEugene Leviant if (!VI.isReadOnly()) 123e91f86f0SEugene Leviant GVS->setReadOnly(false); 1243aef3528SEugene Leviant if (!VI.isWriteOnly()) 1253aef3528SEugene Leviant GVS->setWriteOnly(false); 1263aef3528SEugene Leviant } 127bf46e741SEugene Leviant } 128bf46e741SEugene Leviant } 129bf46e741SEugene Leviant 1303aef3528SEugene Leviant // Do the access attribute propagation in combined index. 1313aef3528SEugene Leviant // The goal of attribute propagation is internalization of readonly (RO) 1323aef3528SEugene Leviant // or writeonly (WO) variables. To determine which variables are RO or WO 1333aef3528SEugene Leviant // and which are not we take following steps: 1343aef3528SEugene Leviant // - During analysis we speculatively assign readonly and writeonly 1353aef3528SEugene Leviant // attribute to all variables which can be internalized. When computing 1363aef3528SEugene Leviant // function summary we also assign readonly or writeonly attribute to a 1373aef3528SEugene Leviant // reference if function doesn't modify referenced variable (readonly) 1383aef3528SEugene Leviant // or doesn't read it (writeonly). 139bf46e741SEugene Leviant // 1403aef3528SEugene Leviant // - After computing dead symbols in combined index we do the attribute 1413aef3528SEugene Leviant // propagation. During this step we: 1423aef3528SEugene Leviant // a. clear RO and WO attributes from variables which are preserved or 1433aef3528SEugene Leviant // can't be imported 1443aef3528SEugene Leviant // b. clear RO and WO attributes from variables referenced by any global 1453aef3528SEugene Leviant // variable initializer 1463aef3528SEugene Leviant // c. clear RO attribute from variable referenced by a function when 1473aef3528SEugene Leviant // reference is not readonly 1483aef3528SEugene Leviant // d. clear WO attribute from variable referenced by a function when 1493aef3528SEugene Leviant // reference is not writeonly 1503aef3528SEugene Leviant // 1513aef3528SEugene Leviant // Because of (c, d) we don't internalize variables read by function A 1523aef3528SEugene Leviant // and modified by function B. 153bf46e741SEugene Leviant // 154bf46e741SEugene Leviant // Internalization itself happens in the backend after import is finished 1553aef3528SEugene Leviant // See internalizeGVsAfterImport. 1563aef3528SEugene Leviant void ModuleSummaryIndex::propagateAttributes( 157bf46e741SEugene Leviant const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) { 158bf46e741SEugene Leviant for (auto &P : *this) 159bf46e741SEugene Leviant for (auto &S : P.second.SummaryList) { 160bf46e741SEugene Leviant if (!isGlobalValueLive(S.get())) 161bf46e741SEugene Leviant // We don't examine references from dead objects 162bf46e741SEugene Leviant continue; 163bf46e741SEugene Leviant 1643aef3528SEugene Leviant // Global variable can't be marked read/writeonly if it is not eligible 1653aef3528SEugene Leviant // to import since we need to ensure that all external references get 1663aef3528SEugene Leviant // a local (imported) copy. It also can't be marked read/writeonly if 1673aef3528SEugene Leviant // it or any alias (since alias points to the same memory) are preserved 1683aef3528SEugene Leviant // or notEligibleToImport, since either of those means there could be 1693aef3528SEugene Leviant // writes (or reads in case of writeonly) that are not visible (because 1703aef3528SEugene Leviant // preserved means it could have external to DSO writes or reads, and 1713aef3528SEugene Leviant // notEligibleToImport means it could have writes or reads via inline 1723aef3528SEugene Leviant // assembly leading it to be in the @llvm.*used). 173bf46e741SEugene Leviant if (auto *GVS = dyn_cast<GlobalVarSummary>(S->getBaseObject())) 174bf46e741SEugene Leviant // Here we intentionally pass S.get() not GVS, because S could be 175dde58938Sevgeny // an alias. We don't analyze references here, because we have to 176dde58938Sevgeny // know exactly if GV is readonly to do so. 177dde58938Sevgeny if (!canImportGlobalVar(S.get(), /* AnalyzeRefs */ false) || 1783aef3528SEugene Leviant GUIDPreservedSymbols.count(P.first)) { 179bf46e741SEugene Leviant GVS->setReadOnly(false); 1803aef3528SEugene Leviant GVS->setWriteOnly(false); 1813aef3528SEugene Leviant } 1823aef3528SEugene Leviant propagateAttributesToRefs(S.get()); 183bf46e741SEugene Leviant } 1845b9bb25cSTeresa Johnson if (llvm::AreStatisticsEnabled()) 1858c1915ccSTeresa Johnson for (auto &P : *this) 1868c1915ccSTeresa Johnson if (P.second.SummaryList.size()) 1878c1915ccSTeresa Johnson if (auto *GVS = dyn_cast<GlobalVarSummary>( 1888c1915ccSTeresa Johnson P.second.SummaryList[0]->getBaseObject())) 1893aef3528SEugene Leviant if (isGlobalValueLive(GVS)) { 1903aef3528SEugene Leviant if (GVS->maybeReadOnly()) 1918c1915ccSTeresa Johnson ReadOnlyLiveGVars++; 1923aef3528SEugene Leviant if (GVS->maybeWriteOnly()) 1933aef3528SEugene Leviant WriteOnlyLiveGVars++; 1943aef3528SEugene Leviant } 195bf46e741SEugene Leviant } 196bf46e741SEugene Leviant 197dde58938Sevgeny bool ModuleSummaryIndex::canImportGlobalVar(GlobalValueSummary *S, 198dde58938Sevgeny bool AnalyzeRefs) const { 199dde58938Sevgeny auto HasRefsPreventingImport = [this](const GlobalVarSummary *GVS) { 2007f92d66fSevgeny // We don't analyze GV references during attribute propagation, so 2017f92d66fSevgeny // GV with non-trivial initializer can be marked either read or 2027f92d66fSevgeny // write-only. 2037f92d66fSevgeny // Importing definiton of readonly GV with non-trivial initializer 2047f92d66fSevgeny // allows us doing some extra optimizations (like converting indirect 2057f92d66fSevgeny // calls to direct). 2067f92d66fSevgeny // Definition of writeonly GV with non-trivial initializer should also 2077f92d66fSevgeny // be imported. Not doing so will result in: 2087f92d66fSevgeny // a) GV internalization in source module (because it's writeonly) 2097f92d66fSevgeny // b) Importing of GV declaration to destination module as a result 2107f92d66fSevgeny // of promotion. 2117f92d66fSevgeny // c) Link error (external declaration with internal definition). 2127f92d66fSevgeny // However we do not promote objects referenced by writeonly GV 2137f92d66fSevgeny // initializer by means of converting it to 'zeroinitializer' 2147f92d66fSevgeny return !isReadOnly(GVS) && !isWriteOnly(GVS) && GVS->refs().size(); 215dde58938Sevgeny }; 216dde58938Sevgeny auto *GVS = cast<GlobalVarSummary>(S->getBaseObject()); 217dde58938Sevgeny 218dde58938Sevgeny // Global variable with non-trivial initializer can be imported 219dde58938Sevgeny // if it's readonly. This gives us extra opportunities for constant 220dde58938Sevgeny // folding and converting indirect calls to direct calls. We don't 221dde58938Sevgeny // analyze GV references during attribute propagation, because we 222dde58938Sevgeny // don't know yet if it is readonly or not. 223dde58938Sevgeny return !GlobalValue::isInterposableLinkage(S->linkage()) && 224dde58938Sevgeny !S->notEligibleToImport() && 225dde58938Sevgeny (!AnalyzeRefs || !HasRefsPreventingImport(GVS)); 226dde58938Sevgeny } 227dde58938Sevgeny 228b040fcc6SCharles Saternos // TODO: write a graphviz dumper for SCCs (see ModuleSummaryIndex::exportToDot) 229b040fcc6SCharles Saternos // then delete this function and update its tests 230b040fcc6SCharles Saternos LLVM_DUMP_METHOD 231b040fcc6SCharles Saternos void ModuleSummaryIndex::dumpSCCs(raw_ostream &O) { 232b040fcc6SCharles Saternos for (scc_iterator<ModuleSummaryIndex *> I = 233b040fcc6SCharles Saternos scc_begin<ModuleSummaryIndex *>(this); 234b040fcc6SCharles Saternos !I.isAtEnd(); ++I) { 235b040fcc6SCharles Saternos O << "SCC (" << utostr(I->size()) << " node" << (I->size() == 1 ? "" : "s") 236b040fcc6SCharles Saternos << ") {\n"; 237b040fcc6SCharles Saternos for (const ValueInfo V : *I) { 238b040fcc6SCharles Saternos FunctionSummary *F = nullptr; 239b040fcc6SCharles Saternos if (V.getSummaryList().size()) 240b040fcc6SCharles Saternos F = cast<FunctionSummary>(V.getSummaryList().front().get()); 241b040fcc6SCharles Saternos O << " " << (F == nullptr ? "External" : "") << " " << utostr(V.getGUID()) 242b040fcc6SCharles Saternos << (I.hasLoop() ? " (has loop)" : "") << "\n"; 243b040fcc6SCharles Saternos } 244b040fcc6SCharles Saternos O << "}\n"; 245b040fcc6SCharles Saternos } 246b040fcc6SCharles Saternos } 247b040fcc6SCharles Saternos 24828d8a49fSEugene Leviant namespace { 24928d8a49fSEugene Leviant struct Attributes { 25028d8a49fSEugene Leviant void add(const Twine &Name, const Twine &Value, 25128d8a49fSEugene Leviant const Twine &Comment = Twine()); 252bf46e741SEugene Leviant void addComment(const Twine &Comment); 25328d8a49fSEugene Leviant std::string getAsString() const; 25428d8a49fSEugene Leviant 25528d8a49fSEugene Leviant std::vector<std::string> Attrs; 25628d8a49fSEugene Leviant std::string Comments; 25728d8a49fSEugene Leviant }; 25828d8a49fSEugene Leviant 25928d8a49fSEugene Leviant struct Edge { 26028d8a49fSEugene Leviant uint64_t SrcMod; 26128d8a49fSEugene Leviant int Hotness; 26228d8a49fSEugene Leviant GlobalValue::GUID Src; 26328d8a49fSEugene Leviant GlobalValue::GUID Dst; 26428d8a49fSEugene Leviant }; 26528d8a49fSEugene Leviant } 26628d8a49fSEugene Leviant 26728d8a49fSEugene Leviant void Attributes::add(const Twine &Name, const Twine &Value, 26828d8a49fSEugene Leviant const Twine &Comment) { 26928d8a49fSEugene Leviant std::string A = Name.str(); 27028d8a49fSEugene Leviant A += "=\""; 27128d8a49fSEugene Leviant A += Value.str(); 27228d8a49fSEugene Leviant A += "\""; 27328d8a49fSEugene Leviant Attrs.push_back(A); 274bf46e741SEugene Leviant addComment(Comment); 275bf46e741SEugene Leviant } 276bf46e741SEugene Leviant 277bf46e741SEugene Leviant void Attributes::addComment(const Twine &Comment) { 27828d8a49fSEugene Leviant if (!Comment.isTriviallyEmpty()) { 27928d8a49fSEugene Leviant if (Comments.empty()) 28028d8a49fSEugene Leviant Comments = " // "; 28128d8a49fSEugene Leviant else 28228d8a49fSEugene Leviant Comments += ", "; 28328d8a49fSEugene Leviant Comments += Comment.str(); 28428d8a49fSEugene Leviant } 28528d8a49fSEugene Leviant } 28628d8a49fSEugene Leviant 28728d8a49fSEugene Leviant std::string Attributes::getAsString() const { 28828d8a49fSEugene Leviant if (Attrs.empty()) 28928d8a49fSEugene Leviant return ""; 29028d8a49fSEugene Leviant 29128d8a49fSEugene Leviant std::string Ret = "["; 29228d8a49fSEugene Leviant for (auto &A : Attrs) 29328d8a49fSEugene Leviant Ret += A + ","; 29428d8a49fSEugene Leviant Ret.pop_back(); 29528d8a49fSEugene Leviant Ret += "];"; 29628d8a49fSEugene Leviant Ret += Comments; 29728d8a49fSEugene Leviant return Ret; 29828d8a49fSEugene Leviant } 29928d8a49fSEugene Leviant 30028d8a49fSEugene Leviant static std::string linkageToString(GlobalValue::LinkageTypes LT) { 30128d8a49fSEugene Leviant switch (LT) { 30228d8a49fSEugene Leviant case GlobalValue::ExternalLinkage: 30328d8a49fSEugene Leviant return "extern"; 30428d8a49fSEugene Leviant case GlobalValue::AvailableExternallyLinkage: 30528d8a49fSEugene Leviant return "av_ext"; 30628d8a49fSEugene Leviant case GlobalValue::LinkOnceAnyLinkage: 30728d8a49fSEugene Leviant return "linkonce"; 30828d8a49fSEugene Leviant case GlobalValue::LinkOnceODRLinkage: 30928d8a49fSEugene Leviant return "linkonce_odr"; 31028d8a49fSEugene Leviant case GlobalValue::WeakAnyLinkage: 31128d8a49fSEugene Leviant return "weak"; 31228d8a49fSEugene Leviant case GlobalValue::WeakODRLinkage: 31328d8a49fSEugene Leviant return "weak_odr"; 31428d8a49fSEugene Leviant case GlobalValue::AppendingLinkage: 31528d8a49fSEugene Leviant return "appending"; 31628d8a49fSEugene Leviant case GlobalValue::InternalLinkage: 31728d8a49fSEugene Leviant return "internal"; 31828d8a49fSEugene Leviant case GlobalValue::PrivateLinkage: 31928d8a49fSEugene Leviant return "private"; 32028d8a49fSEugene Leviant case GlobalValue::ExternalWeakLinkage: 32128d8a49fSEugene Leviant return "extern_weak"; 32228d8a49fSEugene Leviant case GlobalValue::CommonLinkage: 32328d8a49fSEugene Leviant return "common"; 32428d8a49fSEugene Leviant } 32528d8a49fSEugene Leviant 32628d8a49fSEugene Leviant return "<unknown>"; 32728d8a49fSEugene Leviant } 32828d8a49fSEugene Leviant 32928d8a49fSEugene Leviant static std::string fflagsToString(FunctionSummary::FFlags F) { 33028d8a49fSEugene Leviant auto FlagValue = [](unsigned V) { return V ? '1' : '0'; }; 33128d8a49fSEugene Leviant char FlagRep[] = {FlagValue(F.ReadNone), FlagValue(F.ReadOnly), 332cb397461STeresa Johnson FlagValue(F.NoRecurse), FlagValue(F.ReturnDoesNotAlias), 333*b11391bbSTeresa Johnson FlagValue(F.NoInline), FlagValue(F.AlwaysInline), 0}; 33428d8a49fSEugene Leviant 33528d8a49fSEugene Leviant return FlagRep; 33628d8a49fSEugene Leviant } 33728d8a49fSEugene Leviant 33828d8a49fSEugene Leviant // Get string representation of function instruction count and flags. 33928d8a49fSEugene Leviant static std::string getSummaryAttributes(GlobalValueSummary* GVS) { 34028d8a49fSEugene Leviant auto *FS = dyn_cast_or_null<FunctionSummary>(GVS); 34128d8a49fSEugene Leviant if (!FS) 34228d8a49fSEugene Leviant return ""; 34328d8a49fSEugene Leviant 34428d8a49fSEugene Leviant return std::string("inst: ") + std::to_string(FS->instCount()) + 34528d8a49fSEugene Leviant ", ffl: " + fflagsToString(FS->fflags()); 34628d8a49fSEugene Leviant } 34728d8a49fSEugene Leviant 3487a92bc3eSTeresa Johnson static std::string getNodeVisualName(GlobalValue::GUID Id) { 3497a92bc3eSTeresa Johnson return std::string("@") + std::to_string(Id); 3507a92bc3eSTeresa Johnson } 3517a92bc3eSTeresa Johnson 35228d8a49fSEugene Leviant static std::string getNodeVisualName(const ValueInfo &VI) { 3537a92bc3eSTeresa Johnson return VI.name().empty() ? getNodeVisualName(VI.getGUID()) : VI.name().str(); 35428d8a49fSEugene Leviant } 35528d8a49fSEugene Leviant 35628d8a49fSEugene Leviant static std::string getNodeLabel(const ValueInfo &VI, GlobalValueSummary *GVS) { 35728d8a49fSEugene Leviant if (isa<AliasSummary>(GVS)) 35828d8a49fSEugene Leviant return getNodeVisualName(VI); 35928d8a49fSEugene Leviant 36028d8a49fSEugene Leviant std::string Attrs = getSummaryAttributes(GVS); 36128d8a49fSEugene Leviant std::string Label = 36228d8a49fSEugene Leviant getNodeVisualName(VI) + "|" + linkageToString(GVS->linkage()); 36328d8a49fSEugene Leviant if (!Attrs.empty()) 36428d8a49fSEugene Leviant Label += std::string(" (") + Attrs + ")"; 36528d8a49fSEugene Leviant Label += "}"; 36628d8a49fSEugene Leviant 36728d8a49fSEugene Leviant return Label; 36828d8a49fSEugene Leviant } 36928d8a49fSEugene Leviant 37028d8a49fSEugene Leviant // Write definition of external node, which doesn't have any 37128d8a49fSEugene Leviant // specific module associated with it. Typically this is function 37228d8a49fSEugene Leviant // or variable defined in native object or library. 37328d8a49fSEugene Leviant static void defineExternalNode(raw_ostream &OS, const char *Pfx, 3747a92bc3eSTeresa Johnson const ValueInfo &VI, GlobalValue::GUID Id) { 3757a92bc3eSTeresa Johnson auto StrId = std::to_string(Id); 3767a92bc3eSTeresa Johnson OS << " " << StrId << " [label=\""; 3777a92bc3eSTeresa Johnson 3787a92bc3eSTeresa Johnson if (VI) { 3797a92bc3eSTeresa Johnson OS << getNodeVisualName(VI); 3807a92bc3eSTeresa Johnson } else { 3817a92bc3eSTeresa Johnson OS << getNodeVisualName(Id); 3827a92bc3eSTeresa Johnson } 3837a92bc3eSTeresa Johnson OS << "\"]; // defined externally\n"; 38428d8a49fSEugene Leviant } 38528d8a49fSEugene Leviant 386bf46e741SEugene Leviant static bool hasReadOnlyFlag(const GlobalValueSummary *S) { 387bf46e741SEugene Leviant if (auto *GVS = dyn_cast<GlobalVarSummary>(S)) 3883aef3528SEugene Leviant return GVS->maybeReadOnly(); 3893aef3528SEugene Leviant return false; 3903aef3528SEugene Leviant } 3913aef3528SEugene Leviant 3923aef3528SEugene Leviant static bool hasWriteOnlyFlag(const GlobalValueSummary *S) { 3933aef3528SEugene Leviant if (auto *GVS = dyn_cast<GlobalVarSummary>(S)) 3943aef3528SEugene Leviant return GVS->maybeWriteOnly(); 395bf46e741SEugene Leviant return false; 396bf46e741SEugene Leviant } 397bf46e741SEugene Leviant 39828d8a49fSEugene Leviant void ModuleSummaryIndex::exportToDot(raw_ostream &OS) const { 39928d8a49fSEugene Leviant std::vector<Edge> CrossModuleEdges; 40028d8a49fSEugene Leviant DenseMap<GlobalValue::GUID, std::vector<uint64_t>> NodeMap; 40124b3d258SEugene Leviant using GVSOrderedMapTy = std::map<GlobalValue::GUID, GlobalValueSummary *>; 40224b3d258SEugene Leviant std::map<StringRef, GVSOrderedMapTy> ModuleToDefinedGVS; 40328d8a49fSEugene Leviant collectDefinedGVSummariesPerModule(ModuleToDefinedGVS); 40428d8a49fSEugene Leviant 40528d8a49fSEugene Leviant // Get node identifier in form MXXX_<GUID>. The MXXX prefix is required, 40628d8a49fSEugene Leviant // because we may have multiple linkonce functions summaries. 40728d8a49fSEugene Leviant auto NodeId = [](uint64_t ModId, GlobalValue::GUID Id) { 40828d8a49fSEugene Leviant return ModId == (uint64_t)-1 ? std::to_string(Id) 40928d8a49fSEugene Leviant : std::string("M") + std::to_string(ModId) + 41028d8a49fSEugene Leviant "_" + std::to_string(Id); 41128d8a49fSEugene Leviant }; 41228d8a49fSEugene Leviant 4131f54500aSEugene Leviant auto DrawEdge = [&](const char *Pfx, uint64_t SrcMod, GlobalValue::GUID SrcId, 414bf46e741SEugene Leviant uint64_t DstMod, GlobalValue::GUID DstId, 415bf46e741SEugene Leviant int TypeOrHotness) { 416bf46e741SEugene Leviant // 0 - alias 417bf46e741SEugene Leviant // 1 - reference 418bf46e741SEugene Leviant // 2 - constant reference 4193aef3528SEugene Leviant // 3 - writeonly reference 4203aef3528SEugene Leviant // Other value: (hotness - 4). 4213aef3528SEugene Leviant TypeOrHotness += 4; 42228d8a49fSEugene Leviant static const char *EdgeAttrs[] = { 42328d8a49fSEugene Leviant " [style=dotted]; // alias", 42428d8a49fSEugene Leviant " [style=dashed]; // ref", 425bf46e741SEugene Leviant " [style=dashed,color=forestgreen]; // const-ref", 4263aef3528SEugene Leviant " [style=dashed,color=violetred]; // writeOnly-ref", 42728d8a49fSEugene Leviant " // call (hotness : Unknown)", 42828d8a49fSEugene Leviant " [color=blue]; // call (hotness : Cold)", 42928d8a49fSEugene Leviant " // call (hotness : None)", 43028d8a49fSEugene Leviant " [color=brown]; // call (hotness : Hot)", 43128d8a49fSEugene Leviant " [style=bold,color=red]; // call (hotness : Critical)"}; 43228d8a49fSEugene Leviant 43328d8a49fSEugene Leviant assert(static_cast<size_t>(TypeOrHotness) < 43428d8a49fSEugene Leviant sizeof(EdgeAttrs) / sizeof(EdgeAttrs[0])); 43528d8a49fSEugene Leviant OS << Pfx << NodeId(SrcMod, SrcId) << " -> " << NodeId(DstMod, DstId) 43628d8a49fSEugene Leviant << EdgeAttrs[TypeOrHotness] << "\n"; 43728d8a49fSEugene Leviant }; 43828d8a49fSEugene Leviant 43928d8a49fSEugene Leviant OS << "digraph Summary {\n"; 44028d8a49fSEugene Leviant for (auto &ModIt : ModuleToDefinedGVS) { 44124b3d258SEugene Leviant auto ModId = getModuleId(ModIt.first); 44224b3d258SEugene Leviant OS << " // Module: " << ModIt.first << "\n"; 44328d8a49fSEugene Leviant OS << " subgraph cluster_" << std::to_string(ModId) << " {\n"; 44428d8a49fSEugene Leviant OS << " style = filled;\n"; 44528d8a49fSEugene Leviant OS << " color = lightgrey;\n"; 44624b3d258SEugene Leviant OS << " label = \"" << sys::path::filename(ModIt.first) << "\";\n"; 44728d8a49fSEugene Leviant OS << " node [style=filled,fillcolor=lightblue];\n"; 44828d8a49fSEugene Leviant 44928d8a49fSEugene Leviant auto &GVSMap = ModIt.second; 45028d8a49fSEugene Leviant auto Draw = [&](GlobalValue::GUID IdFrom, GlobalValue::GUID IdTo, int Hotness) { 45128d8a49fSEugene Leviant if (!GVSMap.count(IdTo)) { 45228d8a49fSEugene Leviant CrossModuleEdges.push_back({ModId, Hotness, IdFrom, IdTo}); 45328d8a49fSEugene Leviant return; 45428d8a49fSEugene Leviant } 45528d8a49fSEugene Leviant DrawEdge(" ", ModId, IdFrom, ModId, IdTo, Hotness); 45628d8a49fSEugene Leviant }; 45728d8a49fSEugene Leviant 45828d8a49fSEugene Leviant for (auto &SummaryIt : GVSMap) { 45928d8a49fSEugene Leviant NodeMap[SummaryIt.first].push_back(ModId); 46028d8a49fSEugene Leviant auto Flags = SummaryIt.second->flags(); 46128d8a49fSEugene Leviant Attributes A; 46228d8a49fSEugene Leviant if (isa<FunctionSummary>(SummaryIt.second)) { 46328d8a49fSEugene Leviant A.add("shape", "record", "function"); 46428d8a49fSEugene Leviant } else if (isa<AliasSummary>(SummaryIt.second)) { 46528d8a49fSEugene Leviant A.add("style", "dotted,filled", "alias"); 46628d8a49fSEugene Leviant A.add("shape", "box"); 46728d8a49fSEugene Leviant } else { 46828d8a49fSEugene Leviant A.add("shape", "Mrecord", "variable"); 469bf46e741SEugene Leviant if (Flags.Live && hasReadOnlyFlag(SummaryIt.second)) 470bf46e741SEugene Leviant A.addComment("immutable"); 4713aef3528SEugene Leviant if (Flags.Live && hasWriteOnlyFlag(SummaryIt.second)) 4723aef3528SEugene Leviant A.addComment("writeOnly"); 47328d8a49fSEugene Leviant } 47437b80122STeresa Johnson if (Flags.DSOLocal) 47537b80122STeresa Johnson A.addComment("dsoLocal"); 47637b80122STeresa Johnson if (Flags.CanAutoHide) 47737b80122STeresa Johnson A.addComment("canAutoHide"); 47828d8a49fSEugene Leviant 47928d8a49fSEugene Leviant auto VI = getValueInfo(SummaryIt.first); 48028d8a49fSEugene Leviant A.add("label", getNodeLabel(VI, SummaryIt.second)); 48128d8a49fSEugene Leviant if (!Flags.Live) 48228d8a49fSEugene Leviant A.add("fillcolor", "red", "dead"); 48328d8a49fSEugene Leviant else if (Flags.NotEligibleToImport) 48428d8a49fSEugene Leviant A.add("fillcolor", "yellow", "not eligible to import"); 48528d8a49fSEugene Leviant 48628d8a49fSEugene Leviant OS << " " << NodeId(ModId, SummaryIt.first) << " " << A.getAsString() 48728d8a49fSEugene Leviant << "\n"; 48828d8a49fSEugene Leviant } 48928d8a49fSEugene Leviant OS << " // Edges:\n"; 49028d8a49fSEugene Leviant 49128d8a49fSEugene Leviant for (auto &SummaryIt : GVSMap) { 49228d8a49fSEugene Leviant auto *GVS = SummaryIt.second; 49328d8a49fSEugene Leviant for (auto &R : GVS->refs()) 4943aef3528SEugene Leviant Draw(SummaryIt.first, R.getGUID(), 4953aef3528SEugene Leviant R.isWriteOnly() ? -1 : (R.isReadOnly() ? -2 : -3)); 49628d8a49fSEugene Leviant 49728d8a49fSEugene Leviant if (auto *AS = dyn_cast_or_null<AliasSummary>(SummaryIt.second)) { 4983aef3528SEugene Leviant Draw(SummaryIt.first, AS->getAliaseeGUID(), -4); 49928d8a49fSEugene Leviant continue; 50028d8a49fSEugene Leviant } 50128d8a49fSEugene Leviant 50228d8a49fSEugene Leviant if (auto *FS = dyn_cast_or_null<FunctionSummary>(SummaryIt.second)) 50328d8a49fSEugene Leviant for (auto &CGEdge : FS->calls()) 50428d8a49fSEugene Leviant Draw(SummaryIt.first, CGEdge.first.getGUID(), 50528d8a49fSEugene Leviant static_cast<int>(CGEdge.second.Hotness)); 50628d8a49fSEugene Leviant } 50728d8a49fSEugene Leviant OS << " }\n"; 50828d8a49fSEugene Leviant } 50928d8a49fSEugene Leviant 51028d8a49fSEugene Leviant OS << " // Cross-module edges:\n"; 51128d8a49fSEugene Leviant for (auto &E : CrossModuleEdges) { 51228d8a49fSEugene Leviant auto &ModList = NodeMap[E.Dst]; 51328d8a49fSEugene Leviant if (ModList.empty()) { 5147a92bc3eSTeresa Johnson defineExternalNode(OS, " ", getValueInfo(E.Dst), E.Dst); 51528d8a49fSEugene Leviant // Add fake module to the list to draw an edge to an external node 51628d8a49fSEugene Leviant // in the loop below. 51728d8a49fSEugene Leviant ModList.push_back(-1); 51828d8a49fSEugene Leviant } 51928d8a49fSEugene Leviant for (auto DstMod : ModList) 52028d8a49fSEugene Leviant // The edge representing call or ref is drawn to every module where target 52128d8a49fSEugene Leviant // symbol is defined. When target is a linkonce symbol there can be 52228d8a49fSEugene Leviant // multiple edges representing a single call or ref, both intra-module and 52328d8a49fSEugene Leviant // cross-module. As we've already drawn all intra-module edges before we 52428d8a49fSEugene Leviant // skip it here. 52528d8a49fSEugene Leviant if (DstMod != E.SrcMod) 52628d8a49fSEugene Leviant DrawEdge(" ", E.SrcMod, E.Src, DstMod, E.Dst, E.Hotness); 52728d8a49fSEugene Leviant } 52828d8a49fSEugene Leviant 52928d8a49fSEugene Leviant OS << "}"; 53028d8a49fSEugene Leviant } 531