forked from OSchip/llvm-project
[ThinLTO] Add GraphTraits for FunctionSummaries
Add GraphTraits definitions to the FunctionSummary and ModuleSummaryIndex classes. These GraphTraits will be used to construct find SCC's in ThinLTO analysis passes. Second attempt, since last patch caused stage2 build to fail (now using function_ref rather than std::function). llvm-svn: 325448
This commit is contained in:
parent
386b8ddd5f
commit
35878ee7a4
|
@ -162,6 +162,24 @@ struct ValueInfo {
|
|||
bool isDSOLocal() const;
|
||||
};
|
||||
|
||||
inline bool operator==(const ValueInfo &A, const ValueInfo &B) {
|
||||
assert(A.getRef() && B.getRef() &&
|
||||
"Need ValueInfo with non-null Ref to compare GUIDs");
|
||||
return A.getRef() == B.getRef();
|
||||
}
|
||||
|
||||
inline bool operator!=(const ValueInfo &A, const ValueInfo &B) {
|
||||
assert(A.getRef() && B.getRef() &&
|
||||
"Need ValueInfo with non-null Ref to compare GUIDs");
|
||||
return A.getGUID() != B.getGUID();
|
||||
}
|
||||
|
||||
inline bool operator<(const ValueInfo &A, const ValueInfo &B) {
|
||||
assert(A.getRef() && B.getRef() &&
|
||||
"Need ValueInfo with non-null Ref to compare GUIDs");
|
||||
return A.getGUID() < B.getGUID();
|
||||
}
|
||||
|
||||
template <> struct DenseMapInfo<ValueInfo> {
|
||||
static inline ValueInfo getEmptyKey() {
|
||||
return ValueInfo(false, (GlobalValueSummaryMapTy::value_type *)-8);
|
||||
|
@ -397,6 +415,25 @@ public:
|
|||
unsigned ReturnDoesNotAlias : 1;
|
||||
};
|
||||
|
||||
/// Create an empty FunctionSummary (with specified call edges).
|
||||
/// Used to represent external nodes and the dummy root node.
|
||||
static FunctionSummary
|
||||
makeDummyFunctionSummary(std::vector<FunctionSummary::EdgeTy> Edges) {
|
||||
return FunctionSummary(
|
||||
FunctionSummary::GVFlags(
|
||||
GlobalValue::LinkageTypes::AvailableExternallyLinkage,
|
||||
/*NotEligibleToImport=*/true, /*Live=*/true, /*IsLocal=*/false),
|
||||
0, FunctionSummary::FFlags{}, std::vector<ValueInfo>(),
|
||||
std::move(Edges), std::vector<GlobalValue::GUID>(),
|
||||
std::vector<FunctionSummary::VFuncId>(),
|
||||
std::vector<FunctionSummary::VFuncId>(),
|
||||
std::vector<FunctionSummary::ConstVCall>(),
|
||||
std::vector<FunctionSummary::ConstVCall>());
|
||||
}
|
||||
|
||||
/// A dummy node to reference external functions that aren't in the index
|
||||
static FunctionSummary ExternalNode;
|
||||
|
||||
private:
|
||||
/// Number of instructions (ignoring debug instructions, e.g.) computed
|
||||
/// during the initial compile step when the summary index is first built.
|
||||
|
@ -516,6 +553,8 @@ public:
|
|||
TIdInfo = llvm::make_unique<TypeIdInfo>();
|
||||
TIdInfo->TypeTests.push_back(Guid);
|
||||
}
|
||||
|
||||
friend struct GraphTraits<ValueInfo>;
|
||||
};
|
||||
|
||||
template <> struct DenseMapInfo<FunctionSummary::VFuncId> {
|
||||
|
@ -718,6 +757,65 @@ public:
|
|||
const_gvsummary_iterator end() const { return GlobalValueMap.end(); }
|
||||
size_t size() const { return GlobalValueMap.size(); }
|
||||
|
||||
// Calculate the callgraph root
|
||||
FunctionSummary calculateCallGraphRoot() {
|
||||
// Functions that have a parent will be marked in FunctionHasParent pair.
|
||||
// Once we've marked all functions, the functions in the map that are false
|
||||
// have no parent (so they're the roots)
|
||||
std::map<ValueInfo, bool> FunctionHasParent;
|
||||
function_ref<void(ValueInfo)> discoverNodes = [&](ValueInfo V) {
|
||||
if (!V.getSummaryList().size())
|
||||
return; // skip external functions that don't have summaries
|
||||
|
||||
// Mark discovered if we haven't yet
|
||||
auto S = FunctionHasParent.emplace(V, false);
|
||||
|
||||
// Stop if we've already discovered this node
|
||||
if (!S.second)
|
||||
return;
|
||||
|
||||
FunctionSummary *F =
|
||||
dyn_cast<FunctionSummary>(V.getSummaryList().front().get());
|
||||
assert(F != nullptr && "Expected FunctionSummary node");
|
||||
|
||||
for (auto &C : F->calls()) {
|
||||
// Insert node if necessary
|
||||
auto S = FunctionHasParent.emplace(C.first, true);
|
||||
|
||||
// Skip nodes that we're sure have parents
|
||||
if (!S.second && S.first->second)
|
||||
continue;
|
||||
|
||||
if (S.second)
|
||||
discoverNodes(C.first);
|
||||
else
|
||||
S.first->second = true;
|
||||
}
|
||||
};
|
||||
|
||||
for (auto &S : *this) {
|
||||
// Skip external functions
|
||||
if (!S.second.SummaryList.size() ||
|
||||
!isa<FunctionSummary>(S.second.SummaryList.front().get()))
|
||||
continue;
|
||||
discoverNodes(ValueInfo(IsAnalysis, &S));
|
||||
}
|
||||
|
||||
std::vector<FunctionSummary::EdgeTy> 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{}));
|
||||
}
|
||||
if (Edges.empty()) {
|
||||
// Failed to find root - return an empty node
|
||||
return FunctionSummary::makeDummyFunctionSummary({});
|
||||
}
|
||||
auto CallGraphRoot = FunctionSummary::makeDummyFunctionSummary(Edges);
|
||||
return CallGraphRoot;
|
||||
}
|
||||
|
||||
bool withGlobalValueDeadStripping() const {
|
||||
return WithGlobalValueDeadStripping;
|
||||
}
|
||||
|
@ -748,7 +846,7 @@ public:
|
|||
return ValueInfo(IsAnalysis, getOrInsertValuePtr(GUID));
|
||||
}
|
||||
|
||||
/// Return a ValueInfo for \p GUID setting value \p Name.
|
||||
/// Return a ValueInfo for \p GUID setting value \p Name.
|
||||
ValueInfo getOrInsertValueInfo(GlobalValue::GUID GUID, StringRef Name) {
|
||||
assert(!IsAnalysis);
|
||||
auto VP = getOrInsertValuePtr(GUID);
|
||||
|
@ -923,6 +1021,56 @@ public:
|
|||
|
||||
/// Export summary to dot file for GraphViz.
|
||||
void exportToDot(raw_ostream& OS) const;
|
||||
|
||||
/// Print out strongly connected components for debugging.
|
||||
void dumpSCCs(raw_ostream &OS);
|
||||
};
|
||||
|
||||
/// GraphTraits definition to build SCC for the index
|
||||
template <> struct GraphTraits<ValueInfo> {
|
||||
typedef ValueInfo NodeRef;
|
||||
|
||||
static NodeRef valueInfoFromEdge(FunctionSummary::EdgeTy &P) {
|
||||
return P.first;
|
||||
}
|
||||
using ChildIteratorType =
|
||||
mapped_iterator<std::vector<FunctionSummary::EdgeTy>::iterator,
|
||||
decltype(&valueInfoFromEdge)>;
|
||||
|
||||
static NodeRef getEntryNode(ValueInfo V) { return V; }
|
||||
|
||||
static ChildIteratorType child_begin(NodeRef N) {
|
||||
if (!N.getSummaryList().size()) // handle external function
|
||||
return ChildIteratorType(
|
||||
FunctionSummary::ExternalNode.CallGraphEdgeList.begin(),
|
||||
&valueInfoFromEdge);
|
||||
FunctionSummary *F =
|
||||
cast<FunctionSummary>(N.getSummaryList().front()->getBaseObject());
|
||||
return ChildIteratorType(F->CallGraphEdgeList.begin(), &valueInfoFromEdge);
|
||||
}
|
||||
|
||||
static ChildIteratorType child_end(NodeRef N) {
|
||||
if (!N.getSummaryList().size()) // handle external function
|
||||
return ChildIteratorType(
|
||||
FunctionSummary::ExternalNode.CallGraphEdgeList.end(),
|
||||
&valueInfoFromEdge);
|
||||
FunctionSummary *F =
|
||||
cast<FunctionSummary>(N.getSummaryList().front()->getBaseObject());
|
||||
return ChildIteratorType(F->CallGraphEdgeList.end(), &valueInfoFromEdge);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct GraphTraits<ModuleSummaryIndex *> : public GraphTraits<ValueInfo> {
|
||||
static NodeRef getEntryNode(ModuleSummaryIndex *I) {
|
||||
std::unique_ptr<GlobalValueSummary> Root =
|
||||
make_unique<FunctionSummary>(I->calculateCallGraphRoot());
|
||||
GlobalValueSummaryInfo G(I->isPerformingAnalysis());
|
||||
G.SummaryList.push_back(std::move(Root));
|
||||
static auto P =
|
||||
GlobalValueSummaryMapTy::value_type(GlobalValue::GUID(0), std::move(G));
|
||||
return ValueInfo(I->isPerformingAnalysis(), &P);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
|
|
@ -13,10 +13,14 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/IR/ModuleSummaryIndex.h"
|
||||
#include "llvm/ADT/SCCIterator.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
FunctionSummary FunctionSummary::ExternalNode =
|
||||
FunctionSummary::makeDummyFunctionSummary({});
|
||||
bool ValueInfo::isDSOLocal() const {
|
||||
// Need to check all summaries are local in case of hash collisions.
|
||||
return getSummaryList().size() &&
|
||||
|
@ -80,6 +84,26 @@ bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO: write a graphviz dumper for SCCs (see ModuleSummaryIndex::exportToDot)
|
||||
// then delete this function and update its tests
|
||||
LLVM_DUMP_METHOD
|
||||
void ModuleSummaryIndex::dumpSCCs(raw_ostream &O) {
|
||||
for (scc_iterator<ModuleSummaryIndex *> I =
|
||||
scc_begin<ModuleSummaryIndex *>(this);
|
||||
!I.isAtEnd(); ++I) {
|
||||
O << "SCC (" << utostr(I->size()) << " node" << (I->size() == 1 ? "" : "s")
|
||||
<< ") {\n";
|
||||
for (const ValueInfo V : *I) {
|
||||
FunctionSummary *F = nullptr;
|
||||
if (V.getSummaryList().size())
|
||||
F = cast<FunctionSummary>(V.getSummaryList().front().get());
|
||||
O << " " << (F == nullptr ? "External" : "") << " " << utostr(V.getGUID())
|
||||
<< (I.hasLoop() ? " (has loop)" : "") << "\n";
|
||||
}
|
||||
O << "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct Attributes {
|
||||
void add(const Twine &Name, const Twine &Value,
|
||||
|
|
|
@ -50,6 +50,10 @@ using namespace object;
|
|||
|
||||
#define DEBUG_TYPE "lto"
|
||||
|
||||
static cl::opt<bool>
|
||||
DumpThinCGSCCs("dump-thin-cg-sccs", cl::init(false), cl::Hidden,
|
||||
cl::desc("Dump the SCCs in the ThinLTO index's callgraph"));
|
||||
|
||||
// The values are (type identifier, summary) pairs.
|
||||
typedef DenseMap<
|
||||
GlobalValue::GUID,
|
||||
|
@ -1141,6 +1145,9 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache) {
|
|||
ThinLTO.ModuleMap.size());
|
||||
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
|
||||
|
||||
if (DumpThinCGSCCs)
|
||||
ThinLTO.CombinedIndex.dumpSCCs(outs());
|
||||
|
||||
if (Conf.OptLevel > 0)
|
||||
ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
|
||||
ImportLists, ExportLists);
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/Bitcode/BitcodeReader.h"
|
||||
#include "llvm/IR/AutoUpgrade.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
; RUN: opt -module-summary %s -o %t1.bc
|
||||
; RUN: llvm-lto2 run -print-summary-global-ids -dump-thin-cg-sccs %t1.bc -o %t.index.bc \
|
||||
; RUN: -r %t1.bc,external,px -r %t1.bc,l2,pl -r %t1.bc,l1,pl \
|
||||
; RUN: -r %t1.bc,simple,pl -r %t1.bc,root,pl 2>&1 | FileCheck %s
|
||||
|
||||
; CHECK: 5224464028922159466{{.*}} is external
|
||||
; CHECK: 765152853862302398{{.*}} is l2
|
||||
; CHECK: 17000277804057984823{{.*}} is l1
|
||||
; CHECK: 15440740835768581517{{.*}} is simple
|
||||
; CHECK: 5800840261926955363{{.*}} is root
|
||||
|
||||
; CHECK: SCC (2 nodes) {
|
||||
; CHECK-NEXT: {{^}} 17000277804057984823 (has loop)
|
||||
; CHECK-NEXT: {{^}} 765152853862302398 (has loop)
|
||||
; CHECK-NEXT: }
|
||||
|
||||
; CHECK: SCC (1 node) {
|
||||
; CHECK-NEXT: {{^}} 15440740835768581517{{$}}
|
||||
; CHECK-NEXT: }
|
||||
|
||||
; CHECK: SCC (1 node) {
|
||||
; CHECK-NEXT: External 5224464028922159466{{$}}
|
||||
; CHECK-NEXT: }
|
||||
|
||||
; CHECK: SCC (1 node) {
|
||||
; CHECK-NEXT: {{^}} 5800840261926955363{{$}}
|
||||
; CHECK-NEXT: }
|
||||
|
||||
; Dummy call graph root that points at all roots of the callgraph.
|
||||
; CHECK: SCC (1 node) {
|
||||
; CHECK-NEXT: {{^}} 0{{$}}
|
||||
; CHECK-NEXT: }
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
declare void @external()
|
||||
|
||||
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()
|
||||
call void @external()
|
||||
ret void
|
||||
}
|
Loading…
Reference in New Issue