1 //===-- OutlinedHashTree.cpp ----------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // An OutlinedHashTree is a Trie that contains sequences of stable hash values
10 // of instructions that have been outlined. This OutlinedHashTree can be used
11 // to understand the outlined instruction sequences collected across modules.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/CGData/OutlinedHashTree.h"
17 #define DEBUG_TYPE "outlined-hash-tree"
21 void OutlinedHashTree::walkGraph(NodeCallbackFn CallbackNode
,
22 EdgeCallbackFn CallbackEdge
,
23 bool SortedWalk
) const {
24 SmallVector
<const HashNode
*> Stack
;
25 Stack
.emplace_back(getRoot());
27 while (!Stack
.empty()) {
28 const auto *Current
= Stack
.pop_back_val();
30 CallbackNode(Current
);
32 auto HandleNext
= [&](const HashNode
*Next
) {
34 CallbackEdge(Current
, Next
);
35 Stack
.emplace_back(Next
);
38 SmallVector
<std::pair
<stable_hash
, const HashNode
*>> SortedSuccessors
;
39 for (const auto &[Hash
, Successor
] : Current
->Successors
)
40 SortedSuccessors
.emplace_back(Hash
, Successor
.get());
41 llvm::sort(SortedSuccessors
);
42 for (const auto &P
: SortedSuccessors
)
45 for (const auto &P
: Current
->Successors
)
46 HandleNext(P
.second
.get());
51 size_t OutlinedHashTree::size(bool GetTerminalCountOnly
) const {
53 walkGraph([&Size
, GetTerminalCountOnly
](const HashNode
*N
) {
54 Size
+= (N
&& (!GetTerminalCountOnly
|| N
->Terminals
));
59 size_t OutlinedHashTree::depth() const {
61 DenseMap
<const HashNode
*, size_t> DepthMap
;
62 walkGraph([&Size
, &DepthMap
](
63 const HashNode
*N
) { Size
= std::max(Size
, DepthMap
[N
]); },
64 [&DepthMap
](const HashNode
*Src
, const HashNode
*Dst
) {
65 size_t Depth
= DepthMap
[Src
];
66 DepthMap
[Dst
] = Depth
+ 1;
71 void OutlinedHashTree::insert(const HashSequencePair
&SequencePair
) {
72 auto &[Sequence
, Count
] = SequencePair
;
73 HashNode
*Current
= getRoot();
75 for (stable_hash StableHash
: Sequence
) {
76 auto I
= Current
->Successors
.find(StableHash
);
77 if (I
== Current
->Successors
.end()) {
78 std::unique_ptr
<HashNode
> Next
= std::make_unique
<HashNode
>();
79 HashNode
*NextPtr
= Next
.get();
80 NextPtr
->Hash
= StableHash
;
81 Current
->Successors
.emplace(StableHash
, std::move(Next
));
84 Current
= I
->second
.get();
87 Current
->Terminals
= Current
->Terminals
.value_or(0) + Count
;
90 void OutlinedHashTree::merge(const OutlinedHashTree
*Tree
) {
91 HashNode
*Dst
= getRoot();
92 const HashNode
*Src
= Tree
->getRoot();
93 SmallVector
<std::pair
<HashNode
*, const HashNode
*>> Stack
;
94 Stack
.emplace_back(Dst
, Src
);
96 while (!Stack
.empty()) {
97 auto [DstNode
, SrcNode
] = Stack
.pop_back_val();
100 if (SrcNode
->Terminals
)
101 DstNode
->Terminals
= DstNode
->Terminals
.value_or(0) + *SrcNode
->Terminals
;
102 for (auto &[Hash
, NextSrcNode
] : SrcNode
->Successors
) {
103 HashNode
*NextDstNode
;
104 auto I
= DstNode
->Successors
.find(Hash
);
105 if (I
== DstNode
->Successors
.end()) {
106 auto NextDst
= std::make_unique
<HashNode
>();
107 NextDstNode
= NextDst
.get();
108 NextDstNode
->Hash
= Hash
;
109 DstNode
->Successors
.emplace(Hash
, std::move(NextDst
));
111 NextDstNode
= I
->second
.get();
113 Stack
.emplace_back(NextDstNode
, NextSrcNode
.get());
118 std::optional
<unsigned>
119 OutlinedHashTree::find(const HashSequence
&Sequence
) const {
120 const HashNode
*Current
= getRoot();
121 for (stable_hash StableHash
: Sequence
) {
122 const auto I
= Current
->Successors
.find(StableHash
);
123 if (I
== Current
->Successors
.end())
125 Current
= I
->second
.get();
127 return Current
->Terminals
;