Index: include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- include/llvm/IR/ModuleSummaryIndex.h +++ include/llvm/IR/ModuleSummaryIndex.h @@ -106,6 +106,11 @@ } }; +inline bool operator<(const ValueInfo &A, const ValueInfo &B) { + assert(A.Ref && B.Ref); + return A.getGUID() < B.getGUID(); +} + template <> struct DenseMapInfo { static inline ValueInfo getEmptyKey() { return ValueInfo((GlobalValueSummaryMapTy::value_type *)-1); @@ -415,6 +420,42 @@ TIdInfo = llvm::make_unique(); TIdInfo->TypeTests.push_back(Guid); } + + friend struct GraphTraits; +}; + +/// GraphTraits definition to build SCC for the index +template <> struct GraphTraits { + typedef FunctionSummary *NodeRef; + + static NodeRef fsumFromEdge(FunctionSummary::EdgeTy &P) { + if (P.first.Ref && P.first.getSummaryList().size()) + return cast(P.first.getSummaryList().front().get()); + static auto ExternalCallee = llvm::make_unique( + FunctionSummary::GVFlags( + GlobalValue::LinkageTypes::AvailableExternallyLinkage, true, false), + 0, FunctionSummary::FFlags{}, std::vector(), + std::vector(), + std::vector(), + std::vector(), + std::vector(), + std::vector(), + std::vector()); + return ExternalCallee.get(); + } + using ChildIteratorType = + mapped_iterator::iterator, + decltype(&fsumFromEdge)>; + + static NodeRef getEntryNode(FunctionSummary *F) { return F; } + + static ChildIteratorType child_begin(NodeRef N) { + return ChildIteratorType(N->CallGraphEdgeList.begin(), &fsumFromEdge); + } + + static ChildIteratorType child_end(NodeRef N) { + return ChildIteratorType(N->CallGraphEdgeList.end(), &fsumFromEdge); + } }; template <> struct DenseMapInfo { @@ -566,6 +607,11 @@ /// considered live. bool WithGlobalValueDeadStripping = false; + /// The root of the callgraph that's in the index. Note that this is a dummy + /// node that points at every known lazily calulated root in the callgraph. + /// Call \m getCallGraphRoot to actually create this node. + std::unique_ptr CallGraphRoot; + std::set CfiFunctionDefs; std::set CfiFunctionDecls; @@ -584,6 +630,57 @@ const_gvsummary_iterator end() const { return GlobalValueMap.end(); } size_t size() const { return GlobalValueMap.size(); } + // Lazily get callgraph root + FunctionSummary *getCallGraphRoot() { + // Return already calculated root + if (CallGraphRoot) + return CallGraphRoot.get(); + + // Find callgraph root + std::map FunctionHasParent; + std::function discoverNodes = [&](ValueInfo V) { + if (!V.getSummaryList().size()) + return; // skip external functions that don't have summaries + FunctionHasParent.emplace(std::make_pair(V, false)); + for (auto &C : + cast(V.getSummaryList().front().get())->calls()) { + bool notDiscovered = + FunctionHasParent.find(C.first) == FunctionHasParent.end(); + if (notDiscovered) { + FunctionHasParent[C.first] = true; + discoverNodes(C.first); + } + } + }; + + for (auto &S : *this) { + if (!S.second.SummaryList.size() || + !isa(S.second.SummaryList.front().get())) + continue; + discoverNodes(getValueInfo(S.first)); + } + + std::vector Edges; + // create edges to all roots in the Index + for (auto &P : FunctionHasParent) { + if (P.second) + continue; // skip over non-root nodes + Edges.push_back(std::make_pair(P.first, CalleeInfo{})); + } + assert(Edges.size() && "Couldn't find any roots in index callgraph!"); + CallGraphRoot = llvm::make_unique( + FunctionSummary::GVFlags( + GlobalValue::LinkageTypes::AvailableExternallyLinkage, + /*NotEligibleToImport=*/true, /*Live=*/false), + 0, FunctionSummary::FFlags{}, std::vector(), + std::move(Edges), std::vector(), + std::vector(), + std::vector(), + std::vector(), + std::vector()); + return CallGraphRoot.get(); + } + bool withGlobalValueDeadStripping() const { return WithGlobalValueDeadStripping; } @@ -769,6 +866,16 @@ /// Summary). void collectDefinedGVSummariesPerModule( StringMap &ModuleToDefinedGVSummaries) const; + + void dumpSCCs(raw_ostream &O); +}; + +template <> +struct GraphTraits + : public GraphTraits { + static NodeRef getEntryNode(ModuleSummaryIndex *I) { + return I->getCallGraphRoot(); + } }; } // end namespace llvm Index: lib/IR/ModuleSummaryIndex.cpp =================================================================== --- lib/IR/ModuleSummaryIndex.cpp +++ lib/IR/ModuleSummaryIndex.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/ModuleSummaryIndex.h" +#include "llvm/ADT/SCCIterator.h" #include "llvm/ADT/StringMap.h" using namespace llvm; @@ -69,3 +70,16 @@ return true; return false; } + +void ModuleSummaryIndex::dumpSCCs(raw_ostream &O) { + for (scc_iterator I = + scc_begin(this); + !I.isAtEnd(); ++I) { + O << "SCC {\n"; + for (FunctionSummary *F : *I) { + O << " " << F->modulePath() << " " << utostr(F->getOriginalName()) + << "\n"; + } + O << "}\n"; + } +} Index: test/ThinLTO/X86/module_summary_graph_traits.ll =================================================================== --- /dev/null +++ test/ThinLTO/X86/module_summary_graph_traits.ll @@ -0,0 +1,38 @@ +; RUN: opt -module-summary %s -o %t1.bc +; RUN: llvm-lto2 dump-sccs %t1.bc | FileCheck %s + +; CHECK: SCC { +; CHECK-NEXT: tmp1.bc 17000277804057984823 +; CHECK-NEXT: tmp1.bc 765152853862302398 +; CHECK-NEXT: } + +; CHECK: SCC { +; CHECK-NEXT: tmp1.bc 15440740835768581517 +; CHECK-NEXT: } + +; CHECK: SCC { +; CHECK-NEXT: tmp1.bc 5800840261926955363 +; CHECK-NEXT: } + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @l2() { + call void @l1() + ret void +} + +define void @l1() { + call void @l2() + ret void +} + +define i32 @simple() { + ret i32 23 +} + +define void @root() { + call void @l1() + call i32 @simple() + ret void +} Index: tools/llvm-lto2/llvm-lto2.cpp =================================================================== --- tools/llvm-lto2/llvm-lto2.cpp +++ tools/llvm-lto2/llvm-lto2.cpp @@ -142,7 +142,7 @@ } static int usage() { - errs() << "Available subcommands: dump-symtab dump-summary run\n"; + errs() << "Available subcommands: dump-symtab dump-summary dump-sccs run\n"; return 1; } @@ -393,6 +393,16 @@ return 0; } +static int dumpSCCs(int argc, char **argv) { + for (StringRef F : make_range(argv + 1, argv + argc)) { + std::unique_ptr MB = check(MemoryBuffer::getFile(F), F); + std::unique_ptr Index = + check(getModuleSummaryIndex(*MB), F); + Index->dumpSCCs(outs()); + } + return 0; +} + int main(int argc, char **argv) { InitializeAllTargets(); InitializeAllTargetMCs(); @@ -412,6 +422,8 @@ return dumpSymtab(argc - 1, argv + 1); if (Subcommand == "dump-summary") return dumpSummary(argc - 1, argv + 1); + if (Subcommand == "dump-sccs") + return dumpSCCs(argc - 1, argv + 1); if (Subcommand == "run") return run(argc - 1, argv + 1); return usage();