126ab5772STeresa Johnson //===-- ModuleSummaryIndex.cpp - Module Summary Index ---------------------===// 226ab5772STeresa Johnson // 326ab5772STeresa Johnson // The LLVM Compiler Infrastructure 426ab5772STeresa Johnson // 526ab5772STeresa Johnson // This file is distributed under the University of Illinois Open Source 626ab5772STeresa Johnson // License. See LICENSE.TXT for details. 726ab5772STeresa Johnson // 826ab5772STeresa Johnson //===----------------------------------------------------------------------===// 926ab5772STeresa Johnson // 1026ab5772STeresa Johnson // This file implements the module index and summary classes for the 1126ab5772STeresa Johnson // IR library. 1226ab5772STeresa Johnson // 1326ab5772STeresa Johnson //===----------------------------------------------------------------------===// 1426ab5772STeresa Johnson 1526ab5772STeresa Johnson #include "llvm/IR/ModuleSummaryIndex.h" 16b040fcc6SCharles Saternos #include "llvm/ADT/SCCIterator.h" 17*8c1915ccSTeresa Johnson #include "llvm/ADT/Statistic.h" 1826ab5772STeresa Johnson #include "llvm/ADT/StringMap.h" 1928d8a49fSEugene Leviant #include "llvm/Support/Path.h" 20b040fcc6SCharles Saternos #include "llvm/Support/raw_ostream.h" 2126ab5772STeresa Johnson using namespace llvm; 2226ab5772STeresa Johnson 23*8c1915ccSTeresa Johnson #define DEBUG_TYPE "module-summary-index" 24*8c1915ccSTeresa Johnson 25*8c1915ccSTeresa Johnson STATISTIC(ReadOnlyLiveGVars, 26*8c1915ccSTeresa Johnson "Number of live global variables marked read only"); 27*8c1915ccSTeresa Johnson 28b040fcc6SCharles Saternos FunctionSummary FunctionSummary::ExternalNode = 29b040fcc6SCharles Saternos FunctionSummary::makeDummyFunctionSummary({}); 30b4edfb9aSPeter Collingbourne bool ValueInfo::isDSOLocal() const { 31b4edfb9aSPeter Collingbourne // Need to check all summaries are local in case of hash collisions. 32b4edfb9aSPeter Collingbourne return getSummaryList().size() && 33b4edfb9aSPeter Collingbourne llvm::all_of(getSummaryList(), 34b4edfb9aSPeter Collingbourne [](const std::unique_ptr<GlobalValueSummary> &Summary) { 35b4edfb9aSPeter Collingbourne return Summary->isDSOLocal(); 36b4edfb9aSPeter Collingbourne }); 37b4edfb9aSPeter Collingbourne } 38b4edfb9aSPeter Collingbourne 39bf46e741SEugene Leviant // Gets the number of immutable refs in RefEdgeList 40bf46e741SEugene Leviant unsigned FunctionSummary::immutableRefCount() const { 41bf46e741SEugene Leviant // Here we take advantage of having all readonly references 42bf46e741SEugene Leviant // located in the end of the RefEdgeList. 43bf46e741SEugene Leviant auto Refs = refs(); 44bf46e741SEugene Leviant unsigned ImmutableRefCnt = 0; 45bf46e741SEugene Leviant for (int I = Refs.size() - 1; I >= 0 && Refs[I].isReadOnly(); --I) 46bf46e741SEugene Leviant ImmutableRefCnt++; 47bf46e741SEugene Leviant return ImmutableRefCnt; 48bf46e741SEugene Leviant } 49bf46e741SEugene Leviant 50c86af334STeresa Johnson // Collect for the given module the list of function it defines 51c86af334STeresa Johnson // (GUID -> Summary). 52c86af334STeresa Johnson void ModuleSummaryIndex::collectDefinedFunctionsForModule( 53c851d216STeresa Johnson StringRef ModulePath, GVSummaryMapTy &GVSummaryMap) const { 54c86af334STeresa Johnson for (auto &GlobalList : *this) { 55c86af334STeresa Johnson auto GUID = GlobalList.first; 569667b91bSPeter Collingbourne for (auto &GlobSummary : GlobalList.second.SummaryList) { 5728e457bcSTeresa Johnson auto *Summary = dyn_cast_or_null<FunctionSummary>(GlobSummary.get()); 58c86af334STeresa Johnson if (!Summary) 59c86af334STeresa Johnson // Ignore global variable, focus on functions 60c86af334STeresa Johnson continue; 61c86af334STeresa Johnson // Ignore summaries from other modules. 62c86af334STeresa Johnson if (Summary->modulePath() != ModulePath) 63c86af334STeresa Johnson continue; 6428e457bcSTeresa Johnson GVSummaryMap[GUID] = Summary; 65c86af334STeresa Johnson } 66c86af334STeresa Johnson } 67c86af334STeresa Johnson } 68c86af334STeresa Johnson 691aafabf7SMehdi Amini // Collect for each module the list of function it defines (GUID -> Summary). 701aafabf7SMehdi Amini void ModuleSummaryIndex::collectDefinedGVSummariesPerModule( 71c851d216STeresa Johnson StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries) const { 721aafabf7SMehdi Amini for (auto &GlobalList : *this) { 731aafabf7SMehdi Amini auto GUID = GlobalList.first; 749667b91bSPeter Collingbourne for (auto &Summary : GlobalList.second.SummaryList) { 7528e457bcSTeresa Johnson ModuleToDefinedGVSummaries[Summary->modulePath()][GUID] = Summary.get(); 761aafabf7SMehdi Amini } 771aafabf7SMehdi Amini } 781aafabf7SMehdi Amini } 791aafabf7SMehdi Amini 8028e457bcSTeresa Johnson GlobalValueSummary * 8128e457bcSTeresa Johnson ModuleSummaryIndex::getGlobalValueSummary(uint64_t ValueGUID, 82fb7c7644STeresa Johnson bool PerModuleIndex) const { 839667b91bSPeter Collingbourne auto VI = getValueInfo(ValueGUID); 849667b91bSPeter Collingbourne assert(VI && "GlobalValue not found in index"); 859667b91bSPeter Collingbourne assert((!PerModuleIndex || VI.getSummaryList().size() == 1) && 86fb7c7644STeresa Johnson "Expected a single entry per global value in per-module index"); 879667b91bSPeter Collingbourne auto &Summary = VI.getSummaryList()[0]; 8828e457bcSTeresa Johnson return Summary.get(); 89fb7c7644STeresa Johnson } 90dbd2fed6SPeter Collingbourne 91dbd2fed6SPeter Collingbourne bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID) const { 92dbd2fed6SPeter Collingbourne auto VI = getValueInfo(GUID); 93dbd2fed6SPeter Collingbourne if (!VI) 944d4ee93dSEvgeniy Stepanov return true; 954d4ee93dSEvgeniy Stepanov const auto &SummaryList = VI.getSummaryList(); 964d4ee93dSEvgeniy Stepanov if (SummaryList.empty()) 974d4ee93dSEvgeniy Stepanov return true; 984d4ee93dSEvgeniy Stepanov for (auto &I : SummaryList) 99dbd2fed6SPeter Collingbourne if (isGlobalValueLive(I.get())) 100dbd2fed6SPeter Collingbourne return true; 101dbd2fed6SPeter Collingbourne return false; 102dbd2fed6SPeter Collingbourne } 10328d8a49fSEugene Leviant 104bf46e741SEugene Leviant static void propagateConstantsToRefs(GlobalValueSummary *S) { 105bf46e741SEugene Leviant // If reference is not readonly then referenced summary is not 106bf46e741SEugene Leviant // readonly either. Note that: 107bf46e741SEugene Leviant // - All references from GlobalVarSummary are conservatively considered as 108bf46e741SEugene Leviant // not readonly. Tracking them properly requires more complex analysis 109bf46e741SEugene Leviant // then we have now. 110bf46e741SEugene Leviant // 111bf46e741SEugene Leviant // - AliasSummary objects have no refs at all so this function is a no-op 112bf46e741SEugene Leviant // for them. 113bf46e741SEugene Leviant for (auto &VI : S->refs()) { 114bf46e741SEugene Leviant if (VI.isReadOnly()) { 115bf46e741SEugene Leviant // We only mark refs as readonly when computing function summaries on 116bf46e741SEugene Leviant // analysis phase. 117bf46e741SEugene Leviant assert(isa<FunctionSummary>(S)); 118bf46e741SEugene Leviant continue; 119bf46e741SEugene Leviant } 120bf46e741SEugene Leviant for (auto &Ref : VI.getSummaryList()) 121bf46e741SEugene Leviant // If references to alias is not readonly then aliasee is not readonly 122bf46e741SEugene Leviant if (auto *GVS = dyn_cast<GlobalVarSummary>(Ref->getBaseObject())) 123bf46e741SEugene Leviant GVS->setReadOnly(false); 124bf46e741SEugene Leviant } 125bf46e741SEugene Leviant } 126bf46e741SEugene Leviant 127bf46e741SEugene Leviant // Do the constant propagation in combined index. 128bf46e741SEugene Leviant // The goal of constant propagation is internalization of readonly 129bf46e741SEugene Leviant // variables. To determine which variables are readonly and which 130bf46e741SEugene Leviant // are not we take following steps: 131bf46e741SEugene Leviant // - During analysis we speculatively assign readonly attribute to 132bf46e741SEugene Leviant // all variables which can be internalized. When computing function 133bf46e741SEugene Leviant // summary we also assign readonly attribute to a reference if 134bf46e741SEugene Leviant // function doesn't modify referenced variable. 135bf46e741SEugene Leviant // 136bf46e741SEugene Leviant // - After computing dead symbols in combined index we do the constant 137bf46e741SEugene Leviant // propagation. During this step we clear readonly attribute from 138bf46e741SEugene Leviant // all variables which: 139bf46e741SEugene Leviant // a. are dead, preserved or can't be imported 140bf46e741SEugene Leviant // b. referenced by any global variable initializer 141bf46e741SEugene Leviant // c. referenced by a function and reference is not readonly 142bf46e741SEugene Leviant // 143bf46e741SEugene Leviant // Internalization itself happens in the backend after import is finished 144bf46e741SEugene Leviant // See internalizeImmutableGVs. 145bf46e741SEugene Leviant void ModuleSummaryIndex::propagateConstants( 146bf46e741SEugene Leviant const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) { 147bf46e741SEugene Leviant for (auto &P : *this) 148bf46e741SEugene Leviant for (auto &S : P.second.SummaryList) { 149bf46e741SEugene Leviant if (!isGlobalValueLive(S.get())) 150bf46e741SEugene Leviant // We don't examine references from dead objects 151bf46e741SEugene Leviant continue; 152bf46e741SEugene Leviant 153bf46e741SEugene Leviant // Global variable can't be marked read only if it is not eligible 154bf46e741SEugene Leviant // to import since we need to ensure that all external references 155bf46e741SEugene Leviant // get a local (imported) copy. It also can't be marked read only 156bf46e741SEugene Leviant // if it or any alias (since alias points to the same memory) are 157bf46e741SEugene Leviant // preserved or notEligibleToImport, since either of those means 158bf46e741SEugene Leviant // there could be writes that are not visible (because preserved 159bf46e741SEugene Leviant // means it could have external to DSO writes, and notEligibleToImport 160bf46e741SEugene Leviant // means it could have writes via inline assembly leading it to be 161bf46e741SEugene Leviant // in the @llvm.*used). 162bf46e741SEugene Leviant if (auto *GVS = dyn_cast<GlobalVarSummary>(S->getBaseObject())) 163bf46e741SEugene Leviant // Here we intentionally pass S.get() not GVS, because S could be 164bf46e741SEugene Leviant // an alias. 165bf46e741SEugene Leviant if (!canImportGlobalVar(S.get()) || GUIDPreservedSymbols.count(P.first)) 166bf46e741SEugene Leviant GVS->setReadOnly(false); 167bf46e741SEugene Leviant propagateConstantsToRefs(S.get()); 168bf46e741SEugene Leviant } 169*8c1915ccSTeresa Johnson #if LLVM_ENABLE_STATS 170*8c1915ccSTeresa Johnson for (auto &P : *this) 171*8c1915ccSTeresa Johnson if (P.second.SummaryList.size()) 172*8c1915ccSTeresa Johnson if (auto *GVS = dyn_cast<GlobalVarSummary>( 173*8c1915ccSTeresa Johnson P.second.SummaryList[0]->getBaseObject())) 174*8c1915ccSTeresa Johnson if (isGlobalValueLive(GVS) && GVS->isReadOnly()) 175*8c1915ccSTeresa Johnson ReadOnlyLiveGVars++; 176*8c1915ccSTeresa Johnson #endif 177bf46e741SEugene Leviant } 178bf46e741SEugene Leviant 179b040fcc6SCharles Saternos // TODO: write a graphviz dumper for SCCs (see ModuleSummaryIndex::exportToDot) 180b040fcc6SCharles Saternos // then delete this function and update its tests 181b040fcc6SCharles Saternos LLVM_DUMP_METHOD 182b040fcc6SCharles Saternos void ModuleSummaryIndex::dumpSCCs(raw_ostream &O) { 183b040fcc6SCharles Saternos for (scc_iterator<ModuleSummaryIndex *> I = 184b040fcc6SCharles Saternos scc_begin<ModuleSummaryIndex *>(this); 185b040fcc6SCharles Saternos !I.isAtEnd(); ++I) { 186b040fcc6SCharles Saternos O << "SCC (" << utostr(I->size()) << " node" << (I->size() == 1 ? "" : "s") 187b040fcc6SCharles Saternos << ") {\n"; 188b040fcc6SCharles Saternos for (const ValueInfo V : *I) { 189b040fcc6SCharles Saternos FunctionSummary *F = nullptr; 190b040fcc6SCharles Saternos if (V.getSummaryList().size()) 191b040fcc6SCharles Saternos F = cast<FunctionSummary>(V.getSummaryList().front().get()); 192b040fcc6SCharles Saternos O << " " << (F == nullptr ? "External" : "") << " " << utostr(V.getGUID()) 193b040fcc6SCharles Saternos << (I.hasLoop() ? " (has loop)" : "") << "\n"; 194b040fcc6SCharles Saternos } 195b040fcc6SCharles Saternos O << "}\n"; 196b040fcc6SCharles Saternos } 197b040fcc6SCharles Saternos } 198b040fcc6SCharles Saternos 19928d8a49fSEugene Leviant namespace { 20028d8a49fSEugene Leviant struct Attributes { 20128d8a49fSEugene Leviant void add(const Twine &Name, const Twine &Value, 20228d8a49fSEugene Leviant const Twine &Comment = Twine()); 203bf46e741SEugene Leviant void addComment(const Twine &Comment); 20428d8a49fSEugene Leviant std::string getAsString() const; 20528d8a49fSEugene Leviant 20628d8a49fSEugene Leviant std::vector<std::string> Attrs; 20728d8a49fSEugene Leviant std::string Comments; 20828d8a49fSEugene Leviant }; 20928d8a49fSEugene Leviant 21028d8a49fSEugene Leviant struct Edge { 21128d8a49fSEugene Leviant uint64_t SrcMod; 21228d8a49fSEugene Leviant int Hotness; 21328d8a49fSEugene Leviant GlobalValue::GUID Src; 21428d8a49fSEugene Leviant GlobalValue::GUID Dst; 21528d8a49fSEugene Leviant }; 21628d8a49fSEugene Leviant } 21728d8a49fSEugene Leviant 21828d8a49fSEugene Leviant void Attributes::add(const Twine &Name, const Twine &Value, 21928d8a49fSEugene Leviant const Twine &Comment) { 22028d8a49fSEugene Leviant std::string A = Name.str(); 22128d8a49fSEugene Leviant A += "=\""; 22228d8a49fSEugene Leviant A += Value.str(); 22328d8a49fSEugene Leviant A += "\""; 22428d8a49fSEugene Leviant Attrs.push_back(A); 225bf46e741SEugene Leviant addComment(Comment); 226bf46e741SEugene Leviant } 227bf46e741SEugene Leviant 228bf46e741SEugene Leviant void Attributes::addComment(const Twine &Comment) { 22928d8a49fSEugene Leviant if (!Comment.isTriviallyEmpty()) { 23028d8a49fSEugene Leviant if (Comments.empty()) 23128d8a49fSEugene Leviant Comments = " // "; 23228d8a49fSEugene Leviant else 23328d8a49fSEugene Leviant Comments += ", "; 23428d8a49fSEugene Leviant Comments += Comment.str(); 23528d8a49fSEugene Leviant } 23628d8a49fSEugene Leviant } 23728d8a49fSEugene Leviant 23828d8a49fSEugene Leviant std::string Attributes::getAsString() const { 23928d8a49fSEugene Leviant if (Attrs.empty()) 24028d8a49fSEugene Leviant return ""; 24128d8a49fSEugene Leviant 24228d8a49fSEugene Leviant std::string Ret = "["; 24328d8a49fSEugene Leviant for (auto &A : Attrs) 24428d8a49fSEugene Leviant Ret += A + ","; 24528d8a49fSEugene Leviant Ret.pop_back(); 24628d8a49fSEugene Leviant Ret += "];"; 24728d8a49fSEugene Leviant Ret += Comments; 24828d8a49fSEugene Leviant return Ret; 24928d8a49fSEugene Leviant } 25028d8a49fSEugene Leviant 25128d8a49fSEugene Leviant static std::string linkageToString(GlobalValue::LinkageTypes LT) { 25228d8a49fSEugene Leviant switch (LT) { 25328d8a49fSEugene Leviant case GlobalValue::ExternalLinkage: 25428d8a49fSEugene Leviant return "extern"; 25528d8a49fSEugene Leviant case GlobalValue::AvailableExternallyLinkage: 25628d8a49fSEugene Leviant return "av_ext"; 25728d8a49fSEugene Leviant case GlobalValue::LinkOnceAnyLinkage: 25828d8a49fSEugene Leviant return "linkonce"; 25928d8a49fSEugene Leviant case GlobalValue::LinkOnceODRLinkage: 26028d8a49fSEugene Leviant return "linkonce_odr"; 26128d8a49fSEugene Leviant case GlobalValue::WeakAnyLinkage: 26228d8a49fSEugene Leviant return "weak"; 26328d8a49fSEugene Leviant case GlobalValue::WeakODRLinkage: 26428d8a49fSEugene Leviant return "weak_odr"; 26528d8a49fSEugene Leviant case GlobalValue::AppendingLinkage: 26628d8a49fSEugene Leviant return "appending"; 26728d8a49fSEugene Leviant case GlobalValue::InternalLinkage: 26828d8a49fSEugene Leviant return "internal"; 26928d8a49fSEugene Leviant case GlobalValue::PrivateLinkage: 27028d8a49fSEugene Leviant return "private"; 27128d8a49fSEugene Leviant case GlobalValue::ExternalWeakLinkage: 27228d8a49fSEugene Leviant return "extern_weak"; 27328d8a49fSEugene Leviant case GlobalValue::CommonLinkage: 27428d8a49fSEugene Leviant return "common"; 27528d8a49fSEugene Leviant } 27628d8a49fSEugene Leviant 27728d8a49fSEugene Leviant return "<unknown>"; 27828d8a49fSEugene Leviant } 27928d8a49fSEugene Leviant 28028d8a49fSEugene Leviant static std::string fflagsToString(FunctionSummary::FFlags F) { 28128d8a49fSEugene Leviant auto FlagValue = [](unsigned V) { return V ? '1' : '0'; }; 28228d8a49fSEugene Leviant char FlagRep[] = {FlagValue(F.ReadNone), FlagValue(F.ReadOnly), 283cb397461STeresa Johnson FlagValue(F.NoRecurse), FlagValue(F.ReturnDoesNotAlias), 284cb397461STeresa Johnson FlagValue(F.NoInline), 0}; 28528d8a49fSEugene Leviant 28628d8a49fSEugene Leviant return FlagRep; 28728d8a49fSEugene Leviant } 28828d8a49fSEugene Leviant 28928d8a49fSEugene Leviant // Get string representation of function instruction count and flags. 29028d8a49fSEugene Leviant static std::string getSummaryAttributes(GlobalValueSummary* GVS) { 29128d8a49fSEugene Leviant auto *FS = dyn_cast_or_null<FunctionSummary>(GVS); 29228d8a49fSEugene Leviant if (!FS) 29328d8a49fSEugene Leviant return ""; 29428d8a49fSEugene Leviant 29528d8a49fSEugene Leviant return std::string("inst: ") + std::to_string(FS->instCount()) + 29628d8a49fSEugene Leviant ", ffl: " + fflagsToString(FS->fflags()); 29728d8a49fSEugene Leviant } 29828d8a49fSEugene Leviant 2997a92bc3eSTeresa Johnson static std::string getNodeVisualName(GlobalValue::GUID Id) { 3007a92bc3eSTeresa Johnson return std::string("@") + std::to_string(Id); 3017a92bc3eSTeresa Johnson } 3027a92bc3eSTeresa Johnson 30328d8a49fSEugene Leviant static std::string getNodeVisualName(const ValueInfo &VI) { 3047a92bc3eSTeresa Johnson return VI.name().empty() ? getNodeVisualName(VI.getGUID()) : VI.name().str(); 30528d8a49fSEugene Leviant } 30628d8a49fSEugene Leviant 30728d8a49fSEugene Leviant static std::string getNodeLabel(const ValueInfo &VI, GlobalValueSummary *GVS) { 30828d8a49fSEugene Leviant if (isa<AliasSummary>(GVS)) 30928d8a49fSEugene Leviant return getNodeVisualName(VI); 31028d8a49fSEugene Leviant 31128d8a49fSEugene Leviant std::string Attrs = getSummaryAttributes(GVS); 31228d8a49fSEugene Leviant std::string Label = 31328d8a49fSEugene Leviant getNodeVisualName(VI) + "|" + linkageToString(GVS->linkage()); 31428d8a49fSEugene Leviant if (!Attrs.empty()) 31528d8a49fSEugene Leviant Label += std::string(" (") + Attrs + ")"; 31628d8a49fSEugene Leviant Label += "}"; 31728d8a49fSEugene Leviant 31828d8a49fSEugene Leviant return Label; 31928d8a49fSEugene Leviant } 32028d8a49fSEugene Leviant 32128d8a49fSEugene Leviant // Write definition of external node, which doesn't have any 32228d8a49fSEugene Leviant // specific module associated with it. Typically this is function 32328d8a49fSEugene Leviant // or variable defined in native object or library. 32428d8a49fSEugene Leviant static void defineExternalNode(raw_ostream &OS, const char *Pfx, 3257a92bc3eSTeresa Johnson const ValueInfo &VI, GlobalValue::GUID Id) { 3267a92bc3eSTeresa Johnson auto StrId = std::to_string(Id); 3277a92bc3eSTeresa Johnson OS << " " << StrId << " [label=\""; 3287a92bc3eSTeresa Johnson 3297a92bc3eSTeresa Johnson if (VI) { 3307a92bc3eSTeresa Johnson OS << getNodeVisualName(VI); 3317a92bc3eSTeresa Johnson } else { 3327a92bc3eSTeresa Johnson OS << getNodeVisualName(Id); 3337a92bc3eSTeresa Johnson } 3347a92bc3eSTeresa Johnson OS << "\"]; // defined externally\n"; 33528d8a49fSEugene Leviant } 33628d8a49fSEugene Leviant 337bf46e741SEugene Leviant static bool hasReadOnlyFlag(const GlobalValueSummary *S) { 338bf46e741SEugene Leviant if (auto *GVS = dyn_cast<GlobalVarSummary>(S)) 339bf46e741SEugene Leviant return GVS->isReadOnly(); 340bf46e741SEugene Leviant return false; 341bf46e741SEugene Leviant } 342bf46e741SEugene Leviant 34328d8a49fSEugene Leviant void ModuleSummaryIndex::exportToDot(raw_ostream &OS) const { 34428d8a49fSEugene Leviant std::vector<Edge> CrossModuleEdges; 34528d8a49fSEugene Leviant DenseMap<GlobalValue::GUID, std::vector<uint64_t>> NodeMap; 34628d8a49fSEugene Leviant StringMap<GVSummaryMapTy> ModuleToDefinedGVS; 34728d8a49fSEugene Leviant collectDefinedGVSummariesPerModule(ModuleToDefinedGVS); 34828d8a49fSEugene Leviant 34928d8a49fSEugene Leviant // Get node identifier in form MXXX_<GUID>. The MXXX prefix is required, 35028d8a49fSEugene Leviant // because we may have multiple linkonce functions summaries. 35128d8a49fSEugene Leviant auto NodeId = [](uint64_t ModId, GlobalValue::GUID Id) { 35228d8a49fSEugene Leviant return ModId == (uint64_t)-1 ? std::to_string(Id) 35328d8a49fSEugene Leviant : std::string("M") + std::to_string(ModId) + 35428d8a49fSEugene Leviant "_" + std::to_string(Id); 35528d8a49fSEugene Leviant }; 35628d8a49fSEugene Leviant 3571f54500aSEugene Leviant auto DrawEdge = [&](const char *Pfx, uint64_t SrcMod, GlobalValue::GUID SrcId, 358bf46e741SEugene Leviant uint64_t DstMod, GlobalValue::GUID DstId, 359bf46e741SEugene Leviant int TypeOrHotness) { 360bf46e741SEugene Leviant // 0 - alias 361bf46e741SEugene Leviant // 1 - reference 362bf46e741SEugene Leviant // 2 - constant reference 363bf46e741SEugene Leviant // Other value: (hotness - 3). 364bf46e741SEugene Leviant TypeOrHotness += 3; 36528d8a49fSEugene Leviant static const char *EdgeAttrs[] = { 36628d8a49fSEugene Leviant " [style=dotted]; // alias", 36728d8a49fSEugene Leviant " [style=dashed]; // ref", 368bf46e741SEugene Leviant " [style=dashed,color=forestgreen]; // const-ref", 36928d8a49fSEugene Leviant " // call (hotness : Unknown)", 37028d8a49fSEugene Leviant " [color=blue]; // call (hotness : Cold)", 37128d8a49fSEugene Leviant " // call (hotness : None)", 37228d8a49fSEugene Leviant " [color=brown]; // call (hotness : Hot)", 37328d8a49fSEugene Leviant " [style=bold,color=red]; // call (hotness : Critical)"}; 37428d8a49fSEugene Leviant 37528d8a49fSEugene Leviant assert(static_cast<size_t>(TypeOrHotness) < 37628d8a49fSEugene Leviant sizeof(EdgeAttrs) / sizeof(EdgeAttrs[0])); 37728d8a49fSEugene Leviant OS << Pfx << NodeId(SrcMod, SrcId) << " -> " << NodeId(DstMod, DstId) 37828d8a49fSEugene Leviant << EdgeAttrs[TypeOrHotness] << "\n"; 37928d8a49fSEugene Leviant }; 38028d8a49fSEugene Leviant 38128d8a49fSEugene Leviant OS << "digraph Summary {\n"; 38228d8a49fSEugene Leviant for (auto &ModIt : ModuleToDefinedGVS) { 38328d8a49fSEugene Leviant auto ModId = getModuleId(ModIt.first()); 38428d8a49fSEugene Leviant OS << " // Module: " << ModIt.first() << "\n"; 38528d8a49fSEugene Leviant OS << " subgraph cluster_" << std::to_string(ModId) << " {\n"; 38628d8a49fSEugene Leviant OS << " style = filled;\n"; 38728d8a49fSEugene Leviant OS << " color = lightgrey;\n"; 38828d8a49fSEugene Leviant OS << " label = \"" << sys::path::filename(ModIt.first()) << "\";\n"; 38928d8a49fSEugene Leviant OS << " node [style=filled,fillcolor=lightblue];\n"; 39028d8a49fSEugene Leviant 39128d8a49fSEugene Leviant auto &GVSMap = ModIt.second; 39228d8a49fSEugene Leviant auto Draw = [&](GlobalValue::GUID IdFrom, GlobalValue::GUID IdTo, int Hotness) { 39328d8a49fSEugene Leviant if (!GVSMap.count(IdTo)) { 39428d8a49fSEugene Leviant CrossModuleEdges.push_back({ModId, Hotness, IdFrom, IdTo}); 39528d8a49fSEugene Leviant return; 39628d8a49fSEugene Leviant } 39728d8a49fSEugene Leviant DrawEdge(" ", ModId, IdFrom, ModId, IdTo, Hotness); 39828d8a49fSEugene Leviant }; 39928d8a49fSEugene Leviant 40028d8a49fSEugene Leviant for (auto &SummaryIt : GVSMap) { 40128d8a49fSEugene Leviant NodeMap[SummaryIt.first].push_back(ModId); 40228d8a49fSEugene Leviant auto Flags = SummaryIt.second->flags(); 40328d8a49fSEugene Leviant Attributes A; 40428d8a49fSEugene Leviant if (isa<FunctionSummary>(SummaryIt.second)) { 40528d8a49fSEugene Leviant A.add("shape", "record", "function"); 40628d8a49fSEugene Leviant } else if (isa<AliasSummary>(SummaryIt.second)) { 40728d8a49fSEugene Leviant A.add("style", "dotted,filled", "alias"); 40828d8a49fSEugene Leviant A.add("shape", "box"); 40928d8a49fSEugene Leviant } else { 41028d8a49fSEugene Leviant A.add("shape", "Mrecord", "variable"); 411bf46e741SEugene Leviant if (Flags.Live && hasReadOnlyFlag(SummaryIt.second)) 412bf46e741SEugene Leviant A.addComment("immutable"); 41328d8a49fSEugene Leviant } 41428d8a49fSEugene Leviant 41528d8a49fSEugene Leviant auto VI = getValueInfo(SummaryIt.first); 41628d8a49fSEugene Leviant A.add("label", getNodeLabel(VI, SummaryIt.second)); 41728d8a49fSEugene Leviant if (!Flags.Live) 41828d8a49fSEugene Leviant A.add("fillcolor", "red", "dead"); 41928d8a49fSEugene Leviant else if (Flags.NotEligibleToImport) 42028d8a49fSEugene Leviant A.add("fillcolor", "yellow", "not eligible to import"); 42128d8a49fSEugene Leviant 42228d8a49fSEugene Leviant OS << " " << NodeId(ModId, SummaryIt.first) << " " << A.getAsString() 42328d8a49fSEugene Leviant << "\n"; 42428d8a49fSEugene Leviant } 42528d8a49fSEugene Leviant OS << " // Edges:\n"; 42628d8a49fSEugene Leviant 42728d8a49fSEugene Leviant for (auto &SummaryIt : GVSMap) { 42828d8a49fSEugene Leviant auto *GVS = SummaryIt.second; 42928d8a49fSEugene Leviant for (auto &R : GVS->refs()) 430bf46e741SEugene Leviant Draw(SummaryIt.first, R.getGUID(), R.isReadOnly() ? -1 : -2); 43128d8a49fSEugene Leviant 43228d8a49fSEugene Leviant if (auto *AS = dyn_cast_or_null<AliasSummary>(SummaryIt.second)) { 4337a92bc3eSTeresa Johnson GlobalValue::GUID AliaseeId; 4347a92bc3eSTeresa Johnson if (AS->hasAliaseeGUID()) 4357a92bc3eSTeresa Johnson AliaseeId = AS->getAliaseeGUID(); 4367a92bc3eSTeresa Johnson else { 43728d8a49fSEugene Leviant auto AliaseeOrigId = AS->getAliasee().getOriginalName(); 4387a92bc3eSTeresa Johnson AliaseeId = getGUIDFromOriginalID(AliaseeOrigId); 4397a92bc3eSTeresa Johnson if (!AliaseeId) 4407a92bc3eSTeresa Johnson AliaseeId = AliaseeOrigId; 4417a92bc3eSTeresa Johnson } 44228d8a49fSEugene Leviant 443bf46e741SEugene Leviant Draw(SummaryIt.first, AliaseeId, -3); 44428d8a49fSEugene Leviant continue; 44528d8a49fSEugene Leviant } 44628d8a49fSEugene Leviant 44728d8a49fSEugene Leviant if (auto *FS = dyn_cast_or_null<FunctionSummary>(SummaryIt.second)) 44828d8a49fSEugene Leviant for (auto &CGEdge : FS->calls()) 44928d8a49fSEugene Leviant Draw(SummaryIt.first, CGEdge.first.getGUID(), 45028d8a49fSEugene Leviant static_cast<int>(CGEdge.second.Hotness)); 45128d8a49fSEugene Leviant } 45228d8a49fSEugene Leviant OS << " }\n"; 45328d8a49fSEugene Leviant } 45428d8a49fSEugene Leviant 45528d8a49fSEugene Leviant OS << " // Cross-module edges:\n"; 45628d8a49fSEugene Leviant for (auto &E : CrossModuleEdges) { 45728d8a49fSEugene Leviant auto &ModList = NodeMap[E.Dst]; 45828d8a49fSEugene Leviant if (ModList.empty()) { 4597a92bc3eSTeresa Johnson defineExternalNode(OS, " ", getValueInfo(E.Dst), E.Dst); 46028d8a49fSEugene Leviant // Add fake module to the list to draw an edge to an external node 46128d8a49fSEugene Leviant // in the loop below. 46228d8a49fSEugene Leviant ModList.push_back(-1); 46328d8a49fSEugene Leviant } 46428d8a49fSEugene Leviant for (auto DstMod : ModList) 46528d8a49fSEugene Leviant // The edge representing call or ref is drawn to every module where target 46628d8a49fSEugene Leviant // symbol is defined. When target is a linkonce symbol there can be 46728d8a49fSEugene Leviant // multiple edges representing a single call or ref, both intra-module and 46828d8a49fSEugene Leviant // cross-module. As we've already drawn all intra-module edges before we 46928d8a49fSEugene Leviant // skip it here. 47028d8a49fSEugene Leviant if (DstMod != E.SrcMod) 47128d8a49fSEugene Leviant DrawEdge(" ", E.SrcMod, E.Src, DstMod, E.Dst, E.Hotness); 47228d8a49fSEugene Leviant } 47328d8a49fSEugene Leviant 47428d8a49fSEugene Leviant OS << "}"; 47528d8a49fSEugene Leviant } 476