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" 1854a3c2a8STeresa Johnson #include "llvm/Support/CommandLine.h" 1928d8a49fSEugene Leviant #include "llvm/Support/Path.h" 20b040fcc6SCharles Saternos #include "llvm/Support/raw_ostream.h" 2126ab5772STeresa Johnson using namespace llvm; 2226ab5772STeresa Johnson 238c1915ccSTeresa Johnson #define DEBUG_TYPE "module-summary-index" 248c1915ccSTeresa Johnson 258c1915ccSTeresa Johnson STATISTIC(ReadOnlyLiveGVars, 268c1915ccSTeresa Johnson "Number of live global variables marked read only"); 273aef3528SEugene Leviant STATISTIC(WriteOnlyLiveGVars, 283aef3528SEugene Leviant "Number of live global variables marked write only"); 298c1915ccSTeresa Johnson 3054a3c2a8STeresa Johnson static cl::opt<bool> PropagateAttrs("propagate-attrs", cl::init(true), 3154a3c2a8STeresa Johnson cl::Hidden, 3254a3c2a8STeresa Johnson cl::desc("Propagate attributes in index")); 3354a3c2a8STeresa Johnson 34c45bb326STeresa Johnson static cl::opt<bool> ImportConstantsWithRefs( 35*2102ef8aSTeresa Johnson "import-constants-with-refs", cl::init(true), cl::Hidden, 36c45bb326STeresa Johnson cl::desc("Import constant global variables with references")); 37c45bb326STeresa Johnson 38b040fcc6SCharles Saternos FunctionSummary FunctionSummary::ExternalNode = 39b040fcc6SCharles Saternos FunctionSummary::makeDummyFunctionSummary({}); 4037b80122STeresa Johnson 41b4edfb9aSPeter Collingbourne bool ValueInfo::isDSOLocal() const { 42b4edfb9aSPeter Collingbourne // Need to check all summaries are local in case of hash collisions. 43b4edfb9aSPeter Collingbourne return getSummaryList().size() && 44b4edfb9aSPeter Collingbourne llvm::all_of(getSummaryList(), 45b4edfb9aSPeter Collingbourne [](const std::unique_ptr<GlobalValueSummary> &Summary) { 46b4edfb9aSPeter Collingbourne return Summary->isDSOLocal(); 47b4edfb9aSPeter Collingbourne }); 48b4edfb9aSPeter Collingbourne } 49b4edfb9aSPeter Collingbourne 5037b80122STeresa Johnson bool ValueInfo::canAutoHide() const { 5137b80122STeresa Johnson // Can only auto hide if all copies are eligible to auto hide. 5237b80122STeresa Johnson return getSummaryList().size() && 5337b80122STeresa Johnson llvm::all_of(getSummaryList(), 5437b80122STeresa Johnson [](const std::unique_ptr<GlobalValueSummary> &Summary) { 5537b80122STeresa Johnson return Summary->canAutoHide(); 5637b80122STeresa Johnson }); 5737b80122STeresa Johnson } 5837b80122STeresa Johnson 593aef3528SEugene Leviant // Gets the number of readonly and writeonly refs in RefEdgeList 603aef3528SEugene Leviant std::pair<unsigned, unsigned> FunctionSummary::specialRefCounts() const { 613aef3528SEugene Leviant // Here we take advantage of having all readonly and writeonly references 62bf46e741SEugene Leviant // located in the end of the RefEdgeList. 63bf46e741SEugene Leviant auto Refs = refs(); 643aef3528SEugene Leviant unsigned RORefCnt = 0, WORefCnt = 0; 653aef3528SEugene Leviant int I; 663aef3528SEugene Leviant for (I = Refs.size() - 1; I >= 0 && Refs[I].isWriteOnly(); --I) 673aef3528SEugene Leviant WORefCnt++; 683aef3528SEugene Leviant for (; I >= 0 && Refs[I].isReadOnly(); --I) 693aef3528SEugene Leviant RORefCnt++; 703aef3528SEugene Leviant return {RORefCnt, WORefCnt}; 71bf46e741SEugene Leviant } 72bf46e741SEugene Leviant 736a1b5128SAndrew Browne constexpr uint64_t ModuleSummaryIndex::BitcodeSummaryVersion; 746a1b5128SAndrew Browne 75c86af334STeresa Johnson // Collect for the given module the list of function it defines 76c86af334STeresa Johnson // (GUID -> Summary). 77c86af334STeresa Johnson void ModuleSummaryIndex::collectDefinedFunctionsForModule( 78c851d216STeresa Johnson StringRef ModulePath, GVSummaryMapTy &GVSummaryMap) const { 79c86af334STeresa Johnson for (auto &GlobalList : *this) { 80c86af334STeresa Johnson auto GUID = GlobalList.first; 819667b91bSPeter Collingbourne for (auto &GlobSummary : GlobalList.second.SummaryList) { 8228e457bcSTeresa Johnson auto *Summary = dyn_cast_or_null<FunctionSummary>(GlobSummary.get()); 83c86af334STeresa Johnson if (!Summary) 84c86af334STeresa Johnson // Ignore global variable, focus on functions 85c86af334STeresa Johnson continue; 86c86af334STeresa Johnson // Ignore summaries from other modules. 87c86af334STeresa Johnson if (Summary->modulePath() != ModulePath) 88c86af334STeresa Johnson continue; 8928e457bcSTeresa Johnson GVSummaryMap[GUID] = Summary; 90c86af334STeresa Johnson } 91c86af334STeresa Johnson } 92c86af334STeresa Johnson } 93c86af334STeresa Johnson 9428e457bcSTeresa Johnson GlobalValueSummary * 9528e457bcSTeresa Johnson ModuleSummaryIndex::getGlobalValueSummary(uint64_t ValueGUID, 96fb7c7644STeresa Johnson bool PerModuleIndex) const { 979667b91bSPeter Collingbourne auto VI = getValueInfo(ValueGUID); 989667b91bSPeter Collingbourne assert(VI && "GlobalValue not found in index"); 999667b91bSPeter Collingbourne assert((!PerModuleIndex || VI.getSummaryList().size() == 1) && 100fb7c7644STeresa Johnson "Expected a single entry per global value in per-module index"); 1019667b91bSPeter Collingbourne auto &Summary = VI.getSummaryList()[0]; 10228e457bcSTeresa Johnson return Summary.get(); 103fb7c7644STeresa Johnson } 104dbd2fed6SPeter Collingbourne 105dbd2fed6SPeter Collingbourne bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID) const { 106dbd2fed6SPeter Collingbourne auto VI = getValueInfo(GUID); 107dbd2fed6SPeter Collingbourne if (!VI) 1084d4ee93dSEvgeniy Stepanov return true; 1094d4ee93dSEvgeniy Stepanov const auto &SummaryList = VI.getSummaryList(); 1104d4ee93dSEvgeniy Stepanov if (SummaryList.empty()) 1114d4ee93dSEvgeniy Stepanov return true; 1124d4ee93dSEvgeniy Stepanov for (auto &I : SummaryList) 113dbd2fed6SPeter Collingbourne if (isGlobalValueLive(I.get())) 114dbd2fed6SPeter Collingbourne return true; 115dbd2fed6SPeter Collingbourne return false; 116dbd2fed6SPeter Collingbourne } 11728d8a49fSEugene Leviant 1183aef3528SEugene Leviant static void propagateAttributesToRefs(GlobalValueSummary *S) { 1193aef3528SEugene Leviant // If reference is not readonly or writeonly then referenced summary is not 1203aef3528SEugene Leviant // read/writeonly either. Note that: 121bf46e741SEugene Leviant // - All references from GlobalVarSummary are conservatively considered as 1223aef3528SEugene Leviant // not readonly or writeonly. Tracking them properly requires more complex 1233aef3528SEugene Leviant // analysis then we have now. 124bf46e741SEugene Leviant // 125bf46e741SEugene Leviant // - AliasSummary objects have no refs at all so this function is a no-op 126bf46e741SEugene Leviant // for them. 127bf46e741SEugene Leviant for (auto &VI : S->refs()) { 1283aef3528SEugene Leviant assert(VI.getAccessSpecifier() == 0 || isa<FunctionSummary>(S)); 129e91f86f0SEugene Leviant for (auto &Ref : VI.getSummaryList()) 1303aef3528SEugene Leviant // If references to alias is not read/writeonly then aliasee 1313aef3528SEugene Leviant // is not read/writeonly 1323aef3528SEugene Leviant if (auto *GVS = dyn_cast<GlobalVarSummary>(Ref->getBaseObject())) { 1333aef3528SEugene Leviant if (!VI.isReadOnly()) 134e91f86f0SEugene Leviant GVS->setReadOnly(false); 1353aef3528SEugene Leviant if (!VI.isWriteOnly()) 1363aef3528SEugene Leviant GVS->setWriteOnly(false); 1373aef3528SEugene Leviant } 138bf46e741SEugene Leviant } 139bf46e741SEugene Leviant } 140bf46e741SEugene Leviant 1413aef3528SEugene Leviant // Do the access attribute propagation in combined index. 1423aef3528SEugene Leviant // The goal of attribute propagation is internalization of readonly (RO) 1433aef3528SEugene Leviant // or writeonly (WO) variables. To determine which variables are RO or WO 1443aef3528SEugene Leviant // and which are not we take following steps: 1453aef3528SEugene Leviant // - During analysis we speculatively assign readonly and writeonly 1463aef3528SEugene Leviant // attribute to all variables which can be internalized. When computing 1473aef3528SEugene Leviant // function summary we also assign readonly or writeonly attribute to a 1483aef3528SEugene Leviant // reference if function doesn't modify referenced variable (readonly) 1493aef3528SEugene Leviant // or doesn't read it (writeonly). 150bf46e741SEugene Leviant // 1513aef3528SEugene Leviant // - After computing dead symbols in combined index we do the attribute 1523aef3528SEugene Leviant // propagation. During this step we: 1533aef3528SEugene Leviant // a. clear RO and WO attributes from variables which are preserved or 1543aef3528SEugene Leviant // can't be imported 1553aef3528SEugene Leviant // b. clear RO and WO attributes from variables referenced by any global 1563aef3528SEugene Leviant // variable initializer 1573aef3528SEugene Leviant // c. clear RO attribute from variable referenced by a function when 1583aef3528SEugene Leviant // reference is not readonly 1593aef3528SEugene Leviant // d. clear WO attribute from variable referenced by a function when 1603aef3528SEugene Leviant // reference is not writeonly 1613aef3528SEugene Leviant // 1623aef3528SEugene Leviant // Because of (c, d) we don't internalize variables read by function A 1633aef3528SEugene Leviant // and modified by function B. 164bf46e741SEugene Leviant // 165bf46e741SEugene Leviant // Internalization itself happens in the backend after import is finished 1663aef3528SEugene Leviant // See internalizeGVsAfterImport. 1673aef3528SEugene Leviant void ModuleSummaryIndex::propagateAttributes( 168bf46e741SEugene Leviant const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) { 16954a3c2a8STeresa Johnson if (!PropagateAttrs) 17054a3c2a8STeresa Johnson return; 171bf46e741SEugene Leviant for (auto &P : *this) 172bf46e741SEugene Leviant for (auto &S : P.second.SummaryList) { 173bf46e741SEugene Leviant if (!isGlobalValueLive(S.get())) 174bf46e741SEugene Leviant // We don't examine references from dead objects 175bf46e741SEugene Leviant continue; 176bf46e741SEugene Leviant 1773aef3528SEugene Leviant // Global variable can't be marked read/writeonly if it is not eligible 1783aef3528SEugene Leviant // to import since we need to ensure that all external references get 1793aef3528SEugene Leviant // a local (imported) copy. It also can't be marked read/writeonly if 1803aef3528SEugene Leviant // it or any alias (since alias points to the same memory) are preserved 1813aef3528SEugene Leviant // or notEligibleToImport, since either of those means there could be 1823aef3528SEugene Leviant // writes (or reads in case of writeonly) that are not visible (because 1833aef3528SEugene Leviant // preserved means it could have external to DSO writes or reads, and 1843aef3528SEugene Leviant // notEligibleToImport means it could have writes or reads via inline 1853aef3528SEugene Leviant // assembly leading it to be in the @llvm.*used). 186bf46e741SEugene Leviant if (auto *GVS = dyn_cast<GlobalVarSummary>(S->getBaseObject())) 187bf46e741SEugene Leviant // Here we intentionally pass S.get() not GVS, because S could be 188dde58938Sevgeny // an alias. We don't analyze references here, because we have to 189dde58938Sevgeny // know exactly if GV is readonly to do so. 190dde58938Sevgeny if (!canImportGlobalVar(S.get(), /* AnalyzeRefs */ false) || 1913aef3528SEugene Leviant GUIDPreservedSymbols.count(P.first)) { 192bf46e741SEugene Leviant GVS->setReadOnly(false); 1933aef3528SEugene Leviant GVS->setWriteOnly(false); 1943aef3528SEugene Leviant } 1953aef3528SEugene Leviant propagateAttributesToRefs(S.get()); 196bf46e741SEugene Leviant } 19754a3c2a8STeresa Johnson setWithAttributePropagation(); 1985b9bb25cSTeresa Johnson if (llvm::AreStatisticsEnabled()) 1998c1915ccSTeresa Johnson for (auto &P : *this) 2008c1915ccSTeresa Johnson if (P.second.SummaryList.size()) 2018c1915ccSTeresa Johnson if (auto *GVS = dyn_cast<GlobalVarSummary>( 2028c1915ccSTeresa Johnson P.second.SummaryList[0]->getBaseObject())) 2033aef3528SEugene Leviant if (isGlobalValueLive(GVS)) { 2043aef3528SEugene Leviant if (GVS->maybeReadOnly()) 2058c1915ccSTeresa Johnson ReadOnlyLiveGVars++; 2063aef3528SEugene Leviant if (GVS->maybeWriteOnly()) 2073aef3528SEugene Leviant WriteOnlyLiveGVars++; 2083aef3528SEugene Leviant } 209bf46e741SEugene Leviant } 210bf46e741SEugene Leviant 211dde58938Sevgeny bool ModuleSummaryIndex::canImportGlobalVar(GlobalValueSummary *S, 212dde58938Sevgeny bool AnalyzeRefs) const { 213dde58938Sevgeny auto HasRefsPreventingImport = [this](const GlobalVarSummary *GVS) { 2147f92d66fSevgeny // We don't analyze GV references during attribute propagation, so 2157f92d66fSevgeny // GV with non-trivial initializer can be marked either read or 2167f92d66fSevgeny // write-only. 2177f92d66fSevgeny // Importing definiton of readonly GV with non-trivial initializer 2187f92d66fSevgeny // allows us doing some extra optimizations (like converting indirect 2197f92d66fSevgeny // calls to direct). 2207f92d66fSevgeny // Definition of writeonly GV with non-trivial initializer should also 2217f92d66fSevgeny // be imported. Not doing so will result in: 2227f92d66fSevgeny // a) GV internalization in source module (because it's writeonly) 2237f92d66fSevgeny // b) Importing of GV declaration to destination module as a result 2247f92d66fSevgeny // of promotion. 2257f92d66fSevgeny // c) Link error (external declaration with internal definition). 2267f92d66fSevgeny // However we do not promote objects referenced by writeonly GV 2277f92d66fSevgeny // initializer by means of converting it to 'zeroinitializer' 228c45bb326STeresa Johnson return !(ImportConstantsWithRefs && GVS->isConstant()) && 229c45bb326STeresa Johnson !isReadOnly(GVS) && !isWriteOnly(GVS) && GVS->refs().size(); 230dde58938Sevgeny }; 231dde58938Sevgeny auto *GVS = cast<GlobalVarSummary>(S->getBaseObject()); 232dde58938Sevgeny 233dde58938Sevgeny // Global variable with non-trivial initializer can be imported 234dde58938Sevgeny // if it's readonly. This gives us extra opportunities for constant 235dde58938Sevgeny // folding and converting indirect calls to direct calls. We don't 236dde58938Sevgeny // analyze GV references during attribute propagation, because we 237dde58938Sevgeny // don't know yet if it is readonly or not. 238dde58938Sevgeny return !GlobalValue::isInterposableLinkage(S->linkage()) && 239dde58938Sevgeny !S->notEligibleToImport() && 240dde58938Sevgeny (!AnalyzeRefs || !HasRefsPreventingImport(GVS)); 241dde58938Sevgeny } 242dde58938Sevgeny 243b040fcc6SCharles Saternos // TODO: write a graphviz dumper for SCCs (see ModuleSummaryIndex::exportToDot) 244b040fcc6SCharles Saternos // then delete this function and update its tests 245b040fcc6SCharles Saternos LLVM_DUMP_METHOD 246b040fcc6SCharles Saternos void ModuleSummaryIndex::dumpSCCs(raw_ostream &O) { 247b040fcc6SCharles Saternos for (scc_iterator<ModuleSummaryIndex *> I = 248b040fcc6SCharles Saternos scc_begin<ModuleSummaryIndex *>(this); 249b040fcc6SCharles Saternos !I.isAtEnd(); ++I) { 250b040fcc6SCharles Saternos O << "SCC (" << utostr(I->size()) << " node" << (I->size() == 1 ? "" : "s") 251b040fcc6SCharles Saternos << ") {\n"; 2521a8ff896SMark de Wever for (const ValueInfo &V : *I) { 253b040fcc6SCharles Saternos FunctionSummary *F = nullptr; 254b040fcc6SCharles Saternos if (V.getSummaryList().size()) 255b040fcc6SCharles Saternos F = cast<FunctionSummary>(V.getSummaryList().front().get()); 256b040fcc6SCharles Saternos O << " " << (F == nullptr ? "External" : "") << " " << utostr(V.getGUID()) 257b040fcc6SCharles Saternos << (I.hasLoop() ? " (has loop)" : "") << "\n"; 258b040fcc6SCharles Saternos } 259b040fcc6SCharles Saternos O << "}\n"; 260b040fcc6SCharles Saternos } 261b040fcc6SCharles Saternos } 262b040fcc6SCharles Saternos 26328d8a49fSEugene Leviant namespace { 26428d8a49fSEugene Leviant struct Attributes { 26528d8a49fSEugene Leviant void add(const Twine &Name, const Twine &Value, 26628d8a49fSEugene Leviant const Twine &Comment = Twine()); 267bf46e741SEugene Leviant void addComment(const Twine &Comment); 26828d8a49fSEugene Leviant std::string getAsString() const; 26928d8a49fSEugene Leviant 27028d8a49fSEugene Leviant std::vector<std::string> Attrs; 27128d8a49fSEugene Leviant std::string Comments; 27228d8a49fSEugene Leviant }; 27328d8a49fSEugene Leviant 27428d8a49fSEugene Leviant struct Edge { 27528d8a49fSEugene Leviant uint64_t SrcMod; 27628d8a49fSEugene Leviant int Hotness; 27728d8a49fSEugene Leviant GlobalValue::GUID Src; 27828d8a49fSEugene Leviant GlobalValue::GUID Dst; 27928d8a49fSEugene Leviant }; 28028d8a49fSEugene Leviant } 28128d8a49fSEugene Leviant 28228d8a49fSEugene Leviant void Attributes::add(const Twine &Name, const Twine &Value, 28328d8a49fSEugene Leviant const Twine &Comment) { 28428d8a49fSEugene Leviant std::string A = Name.str(); 28528d8a49fSEugene Leviant A += "=\""; 28628d8a49fSEugene Leviant A += Value.str(); 28728d8a49fSEugene Leviant A += "\""; 28828d8a49fSEugene Leviant Attrs.push_back(A); 289bf46e741SEugene Leviant addComment(Comment); 290bf46e741SEugene Leviant } 291bf46e741SEugene Leviant 292bf46e741SEugene Leviant void Attributes::addComment(const Twine &Comment) { 29328d8a49fSEugene Leviant if (!Comment.isTriviallyEmpty()) { 29428d8a49fSEugene Leviant if (Comments.empty()) 29528d8a49fSEugene Leviant Comments = " // "; 29628d8a49fSEugene Leviant else 29728d8a49fSEugene Leviant Comments += ", "; 29828d8a49fSEugene Leviant Comments += Comment.str(); 29928d8a49fSEugene Leviant } 30028d8a49fSEugene Leviant } 30128d8a49fSEugene Leviant 30228d8a49fSEugene Leviant std::string Attributes::getAsString() const { 30328d8a49fSEugene Leviant if (Attrs.empty()) 30428d8a49fSEugene Leviant return ""; 30528d8a49fSEugene Leviant 30628d8a49fSEugene Leviant std::string Ret = "["; 30728d8a49fSEugene Leviant for (auto &A : Attrs) 30828d8a49fSEugene Leviant Ret += A + ","; 30928d8a49fSEugene Leviant Ret.pop_back(); 31028d8a49fSEugene Leviant Ret += "];"; 31128d8a49fSEugene Leviant Ret += Comments; 31228d8a49fSEugene Leviant return Ret; 31328d8a49fSEugene Leviant } 31428d8a49fSEugene Leviant 31528d8a49fSEugene Leviant static std::string linkageToString(GlobalValue::LinkageTypes LT) { 31628d8a49fSEugene Leviant switch (LT) { 31728d8a49fSEugene Leviant case GlobalValue::ExternalLinkage: 31828d8a49fSEugene Leviant return "extern"; 31928d8a49fSEugene Leviant case GlobalValue::AvailableExternallyLinkage: 32028d8a49fSEugene Leviant return "av_ext"; 32128d8a49fSEugene Leviant case GlobalValue::LinkOnceAnyLinkage: 32228d8a49fSEugene Leviant return "linkonce"; 32328d8a49fSEugene Leviant case GlobalValue::LinkOnceODRLinkage: 32428d8a49fSEugene Leviant return "linkonce_odr"; 32528d8a49fSEugene Leviant case GlobalValue::WeakAnyLinkage: 32628d8a49fSEugene Leviant return "weak"; 32728d8a49fSEugene Leviant case GlobalValue::WeakODRLinkage: 32828d8a49fSEugene Leviant return "weak_odr"; 32928d8a49fSEugene Leviant case GlobalValue::AppendingLinkage: 33028d8a49fSEugene Leviant return "appending"; 33128d8a49fSEugene Leviant case GlobalValue::InternalLinkage: 33228d8a49fSEugene Leviant return "internal"; 33328d8a49fSEugene Leviant case GlobalValue::PrivateLinkage: 33428d8a49fSEugene Leviant return "private"; 33528d8a49fSEugene Leviant case GlobalValue::ExternalWeakLinkage: 33628d8a49fSEugene Leviant return "extern_weak"; 33728d8a49fSEugene Leviant case GlobalValue::CommonLinkage: 33828d8a49fSEugene Leviant return "common"; 33928d8a49fSEugene Leviant } 34028d8a49fSEugene Leviant 34128d8a49fSEugene Leviant return "<unknown>"; 34228d8a49fSEugene Leviant } 34328d8a49fSEugene Leviant 34428d8a49fSEugene Leviant static std::string fflagsToString(FunctionSummary::FFlags F) { 34528d8a49fSEugene Leviant auto FlagValue = [](unsigned V) { return V ? '1' : '0'; }; 34628d8a49fSEugene Leviant char FlagRep[] = {FlagValue(F.ReadNone), FlagValue(F.ReadOnly), 347cb397461STeresa Johnson FlagValue(F.NoRecurse), FlagValue(F.ReturnDoesNotAlias), 348b11391bbSTeresa Johnson FlagValue(F.NoInline), FlagValue(F.AlwaysInline), 0}; 34928d8a49fSEugene Leviant 35028d8a49fSEugene Leviant return FlagRep; 35128d8a49fSEugene Leviant } 35228d8a49fSEugene Leviant 35328d8a49fSEugene Leviant // Get string representation of function instruction count and flags. 35428d8a49fSEugene Leviant static std::string getSummaryAttributes(GlobalValueSummary* GVS) { 35528d8a49fSEugene Leviant auto *FS = dyn_cast_or_null<FunctionSummary>(GVS); 35628d8a49fSEugene Leviant if (!FS) 35728d8a49fSEugene Leviant return ""; 35828d8a49fSEugene Leviant 35928d8a49fSEugene Leviant return std::string("inst: ") + std::to_string(FS->instCount()) + 36028d8a49fSEugene Leviant ", ffl: " + fflagsToString(FS->fflags()); 36128d8a49fSEugene Leviant } 36228d8a49fSEugene Leviant 3637a92bc3eSTeresa Johnson static std::string getNodeVisualName(GlobalValue::GUID Id) { 3647a92bc3eSTeresa Johnson return std::string("@") + std::to_string(Id); 3657a92bc3eSTeresa Johnson } 3667a92bc3eSTeresa Johnson 36728d8a49fSEugene Leviant static std::string getNodeVisualName(const ValueInfo &VI) { 3687a92bc3eSTeresa Johnson return VI.name().empty() ? getNodeVisualName(VI.getGUID()) : VI.name().str(); 36928d8a49fSEugene Leviant } 37028d8a49fSEugene Leviant 37128d8a49fSEugene Leviant static std::string getNodeLabel(const ValueInfo &VI, GlobalValueSummary *GVS) { 37228d8a49fSEugene Leviant if (isa<AliasSummary>(GVS)) 37328d8a49fSEugene Leviant return getNodeVisualName(VI); 37428d8a49fSEugene Leviant 37528d8a49fSEugene Leviant std::string Attrs = getSummaryAttributes(GVS); 37628d8a49fSEugene Leviant std::string Label = 37728d8a49fSEugene Leviant getNodeVisualName(VI) + "|" + linkageToString(GVS->linkage()); 37828d8a49fSEugene Leviant if (!Attrs.empty()) 37928d8a49fSEugene Leviant Label += std::string(" (") + Attrs + ")"; 38028d8a49fSEugene Leviant Label += "}"; 38128d8a49fSEugene Leviant 38228d8a49fSEugene Leviant return Label; 38328d8a49fSEugene Leviant } 38428d8a49fSEugene Leviant 38528d8a49fSEugene Leviant // Write definition of external node, which doesn't have any 38628d8a49fSEugene Leviant // specific module associated with it. Typically this is function 38728d8a49fSEugene Leviant // or variable defined in native object or library. 38828d8a49fSEugene Leviant static void defineExternalNode(raw_ostream &OS, const char *Pfx, 3897a92bc3eSTeresa Johnson const ValueInfo &VI, GlobalValue::GUID Id) { 3907a92bc3eSTeresa Johnson auto StrId = std::to_string(Id); 3917a92bc3eSTeresa Johnson OS << " " << StrId << " [label=\""; 3927a92bc3eSTeresa Johnson 3937a92bc3eSTeresa Johnson if (VI) { 3947a92bc3eSTeresa Johnson OS << getNodeVisualName(VI); 3957a92bc3eSTeresa Johnson } else { 3967a92bc3eSTeresa Johnson OS << getNodeVisualName(Id); 3977a92bc3eSTeresa Johnson } 3987a92bc3eSTeresa Johnson OS << "\"]; // defined externally\n"; 39928d8a49fSEugene Leviant } 40028d8a49fSEugene Leviant 401bf46e741SEugene Leviant static bool hasReadOnlyFlag(const GlobalValueSummary *S) { 402bf46e741SEugene Leviant if (auto *GVS = dyn_cast<GlobalVarSummary>(S)) 4033aef3528SEugene Leviant return GVS->maybeReadOnly(); 4043aef3528SEugene Leviant return false; 4053aef3528SEugene Leviant } 4063aef3528SEugene Leviant 4073aef3528SEugene Leviant static bool hasWriteOnlyFlag(const GlobalValueSummary *S) { 4083aef3528SEugene Leviant if (auto *GVS = dyn_cast<GlobalVarSummary>(S)) 4093aef3528SEugene Leviant return GVS->maybeWriteOnly(); 410bf46e741SEugene Leviant return false; 411bf46e741SEugene Leviant } 412bf46e741SEugene Leviant 41310cadee5Sevgeny static bool hasConstantFlag(const GlobalValueSummary *S) { 41410cadee5Sevgeny if (auto *GVS = dyn_cast<GlobalVarSummary>(S)) 41510cadee5Sevgeny return GVS->isConstant(); 41610cadee5Sevgeny return false; 41710cadee5Sevgeny } 41810cadee5Sevgeny 419ad364956Sevgeny void ModuleSummaryIndex::exportToDot( 420ad364956Sevgeny raw_ostream &OS, 421ad364956Sevgeny const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) const { 42228d8a49fSEugene Leviant std::vector<Edge> CrossModuleEdges; 42328d8a49fSEugene Leviant DenseMap<GlobalValue::GUID, std::vector<uint64_t>> NodeMap; 42424b3d258SEugene Leviant using GVSOrderedMapTy = std::map<GlobalValue::GUID, GlobalValueSummary *>; 42524b3d258SEugene Leviant std::map<StringRef, GVSOrderedMapTy> ModuleToDefinedGVS; 42628d8a49fSEugene Leviant collectDefinedGVSummariesPerModule(ModuleToDefinedGVS); 42728d8a49fSEugene Leviant 42828d8a49fSEugene Leviant // Get node identifier in form MXXX_<GUID>. The MXXX prefix is required, 42928d8a49fSEugene Leviant // because we may have multiple linkonce functions summaries. 43028d8a49fSEugene Leviant auto NodeId = [](uint64_t ModId, GlobalValue::GUID Id) { 43128d8a49fSEugene Leviant return ModId == (uint64_t)-1 ? std::to_string(Id) 43228d8a49fSEugene Leviant : std::string("M") + std::to_string(ModId) + 43328d8a49fSEugene Leviant "_" + std::to_string(Id); 43428d8a49fSEugene Leviant }; 43528d8a49fSEugene Leviant 4361f54500aSEugene Leviant auto DrawEdge = [&](const char *Pfx, uint64_t SrcMod, GlobalValue::GUID SrcId, 437bf46e741SEugene Leviant uint64_t DstMod, GlobalValue::GUID DstId, 438bf46e741SEugene Leviant int TypeOrHotness) { 439bf46e741SEugene Leviant // 0 - alias 440bf46e741SEugene Leviant // 1 - reference 441bf46e741SEugene Leviant // 2 - constant reference 4423aef3528SEugene Leviant // 3 - writeonly reference 4433aef3528SEugene Leviant // Other value: (hotness - 4). 4443aef3528SEugene Leviant TypeOrHotness += 4; 44528d8a49fSEugene Leviant static const char *EdgeAttrs[] = { 44628d8a49fSEugene Leviant " [style=dotted]; // alias", 44728d8a49fSEugene Leviant " [style=dashed]; // ref", 448bf46e741SEugene Leviant " [style=dashed,color=forestgreen]; // const-ref", 4493aef3528SEugene Leviant " [style=dashed,color=violetred]; // writeOnly-ref", 45028d8a49fSEugene Leviant " // call (hotness : Unknown)", 45128d8a49fSEugene Leviant " [color=blue]; // call (hotness : Cold)", 45228d8a49fSEugene Leviant " // call (hotness : None)", 45328d8a49fSEugene Leviant " [color=brown]; // call (hotness : Hot)", 45428d8a49fSEugene Leviant " [style=bold,color=red]; // call (hotness : Critical)"}; 45528d8a49fSEugene Leviant 45628d8a49fSEugene Leviant assert(static_cast<size_t>(TypeOrHotness) < 45728d8a49fSEugene Leviant sizeof(EdgeAttrs) / sizeof(EdgeAttrs[0])); 45828d8a49fSEugene Leviant OS << Pfx << NodeId(SrcMod, SrcId) << " -> " << NodeId(DstMod, DstId) 45928d8a49fSEugene Leviant << EdgeAttrs[TypeOrHotness] << "\n"; 46028d8a49fSEugene Leviant }; 46128d8a49fSEugene Leviant 46228d8a49fSEugene Leviant OS << "digraph Summary {\n"; 46328d8a49fSEugene Leviant for (auto &ModIt : ModuleToDefinedGVS) { 46424b3d258SEugene Leviant auto ModId = getModuleId(ModIt.first); 46524b3d258SEugene Leviant OS << " // Module: " << ModIt.first << "\n"; 46628d8a49fSEugene Leviant OS << " subgraph cluster_" << std::to_string(ModId) << " {\n"; 46728d8a49fSEugene Leviant OS << " style = filled;\n"; 46828d8a49fSEugene Leviant OS << " color = lightgrey;\n"; 46924b3d258SEugene Leviant OS << " label = \"" << sys::path::filename(ModIt.first) << "\";\n"; 47028d8a49fSEugene Leviant OS << " node [style=filled,fillcolor=lightblue];\n"; 47128d8a49fSEugene Leviant 47228d8a49fSEugene Leviant auto &GVSMap = ModIt.second; 47328d8a49fSEugene Leviant auto Draw = [&](GlobalValue::GUID IdFrom, GlobalValue::GUID IdTo, int Hotness) { 47428d8a49fSEugene Leviant if (!GVSMap.count(IdTo)) { 47528d8a49fSEugene Leviant CrossModuleEdges.push_back({ModId, Hotness, IdFrom, IdTo}); 47628d8a49fSEugene Leviant return; 47728d8a49fSEugene Leviant } 47828d8a49fSEugene Leviant DrawEdge(" ", ModId, IdFrom, ModId, IdTo, Hotness); 47928d8a49fSEugene Leviant }; 48028d8a49fSEugene Leviant 48128d8a49fSEugene Leviant for (auto &SummaryIt : GVSMap) { 48228d8a49fSEugene Leviant NodeMap[SummaryIt.first].push_back(ModId); 48328d8a49fSEugene Leviant auto Flags = SummaryIt.second->flags(); 48428d8a49fSEugene Leviant Attributes A; 48528d8a49fSEugene Leviant if (isa<FunctionSummary>(SummaryIt.second)) { 48628d8a49fSEugene Leviant A.add("shape", "record", "function"); 48728d8a49fSEugene Leviant } else if (isa<AliasSummary>(SummaryIt.second)) { 48828d8a49fSEugene Leviant A.add("style", "dotted,filled", "alias"); 48928d8a49fSEugene Leviant A.add("shape", "box"); 49028d8a49fSEugene Leviant } else { 49128d8a49fSEugene Leviant A.add("shape", "Mrecord", "variable"); 492bf46e741SEugene Leviant if (Flags.Live && hasReadOnlyFlag(SummaryIt.second)) 493bf46e741SEugene Leviant A.addComment("immutable"); 4943aef3528SEugene Leviant if (Flags.Live && hasWriteOnlyFlag(SummaryIt.second)) 4953aef3528SEugene Leviant A.addComment("writeOnly"); 49610cadee5Sevgeny if (Flags.Live && hasConstantFlag(SummaryIt.second)) 49710cadee5Sevgeny A.addComment("constant"); 49828d8a49fSEugene Leviant } 49937b80122STeresa Johnson if (Flags.DSOLocal) 50037b80122STeresa Johnson A.addComment("dsoLocal"); 50137b80122STeresa Johnson if (Flags.CanAutoHide) 50237b80122STeresa Johnson A.addComment("canAutoHide"); 503ad364956Sevgeny if (GUIDPreservedSymbols.count(SummaryIt.first)) 504ad364956Sevgeny A.addComment("preserved"); 50528d8a49fSEugene Leviant 50628d8a49fSEugene Leviant auto VI = getValueInfo(SummaryIt.first); 50728d8a49fSEugene Leviant A.add("label", getNodeLabel(VI, SummaryIt.second)); 50828d8a49fSEugene Leviant if (!Flags.Live) 50928d8a49fSEugene Leviant A.add("fillcolor", "red", "dead"); 51028d8a49fSEugene Leviant else if (Flags.NotEligibleToImport) 51128d8a49fSEugene Leviant A.add("fillcolor", "yellow", "not eligible to import"); 51228d8a49fSEugene Leviant 51328d8a49fSEugene Leviant OS << " " << NodeId(ModId, SummaryIt.first) << " " << A.getAsString() 51428d8a49fSEugene Leviant << "\n"; 51528d8a49fSEugene Leviant } 51628d8a49fSEugene Leviant OS << " // Edges:\n"; 51728d8a49fSEugene Leviant 51828d8a49fSEugene Leviant for (auto &SummaryIt : GVSMap) { 51928d8a49fSEugene Leviant auto *GVS = SummaryIt.second; 52028d8a49fSEugene Leviant for (auto &R : GVS->refs()) 5213aef3528SEugene Leviant Draw(SummaryIt.first, R.getGUID(), 5223aef3528SEugene Leviant R.isWriteOnly() ? -1 : (R.isReadOnly() ? -2 : -3)); 52328d8a49fSEugene Leviant 52428d8a49fSEugene Leviant if (auto *AS = dyn_cast_or_null<AliasSummary>(SummaryIt.second)) { 5253aef3528SEugene Leviant Draw(SummaryIt.first, AS->getAliaseeGUID(), -4); 52628d8a49fSEugene Leviant continue; 52728d8a49fSEugene Leviant } 52828d8a49fSEugene Leviant 52928d8a49fSEugene Leviant if (auto *FS = dyn_cast_or_null<FunctionSummary>(SummaryIt.second)) 53028d8a49fSEugene Leviant for (auto &CGEdge : FS->calls()) 53128d8a49fSEugene Leviant Draw(SummaryIt.first, CGEdge.first.getGUID(), 53228d8a49fSEugene Leviant static_cast<int>(CGEdge.second.Hotness)); 53328d8a49fSEugene Leviant } 53428d8a49fSEugene Leviant OS << " }\n"; 53528d8a49fSEugene Leviant } 53628d8a49fSEugene Leviant 53728d8a49fSEugene Leviant OS << " // Cross-module edges:\n"; 53828d8a49fSEugene Leviant for (auto &E : CrossModuleEdges) { 53928d8a49fSEugene Leviant auto &ModList = NodeMap[E.Dst]; 54028d8a49fSEugene Leviant if (ModList.empty()) { 5417a92bc3eSTeresa Johnson defineExternalNode(OS, " ", getValueInfo(E.Dst), E.Dst); 54228d8a49fSEugene Leviant // Add fake module to the list to draw an edge to an external node 54328d8a49fSEugene Leviant // in the loop below. 54428d8a49fSEugene Leviant ModList.push_back(-1); 54528d8a49fSEugene Leviant } 54628d8a49fSEugene Leviant for (auto DstMod : ModList) 54728d8a49fSEugene Leviant // The edge representing call or ref is drawn to every module where target 54828d8a49fSEugene Leviant // symbol is defined. When target is a linkonce symbol there can be 54928d8a49fSEugene Leviant // multiple edges representing a single call or ref, both intra-module and 55028d8a49fSEugene Leviant // cross-module. As we've already drawn all intra-module edges before we 55128d8a49fSEugene Leviant // skip it here. 55228d8a49fSEugene Leviant if (DstMod != E.SrcMod) 55328d8a49fSEugene Leviant DrawEdge(" ", E.SrcMod, E.Src, DstMod, E.Dst, E.Hotness); 55428d8a49fSEugene Leviant } 55528d8a49fSEugene Leviant 55628d8a49fSEugene Leviant OS << "}"; 55728d8a49fSEugene Leviant } 558