xref: /src/contrib/llvm-project/llvm/lib/CodeGenData/OutlinedHashTree.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1ac9a064cSDimitry Andric //===-- OutlinedHashTree.cpp ----------------------------------------------===//
2ac9a064cSDimitry Andric //
3ac9a064cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ac9a064cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5ac9a064cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ac9a064cSDimitry Andric //
7ac9a064cSDimitry Andric //===----------------------------------------------------------------------===//
8ac9a064cSDimitry Andric //
9ac9a064cSDimitry Andric // An OutlinedHashTree is a Trie that contains sequences of stable hash values
10ac9a064cSDimitry Andric // of instructions that have been outlined. This OutlinedHashTree can be used
11ac9a064cSDimitry Andric // to understand the outlined instruction sequences collected across modules.
12ac9a064cSDimitry Andric //
13ac9a064cSDimitry Andric //===----------------------------------------------------------------------===//
14ac9a064cSDimitry Andric 
15ac9a064cSDimitry Andric #include "llvm/CodeGenData/OutlinedHashTree.h"
16ac9a064cSDimitry Andric 
17ac9a064cSDimitry Andric #define DEBUG_TYPE "outlined-hash-tree"
18ac9a064cSDimitry Andric 
19ac9a064cSDimitry Andric using namespace llvm;
20ac9a064cSDimitry Andric 
walkGraph(NodeCallbackFn CallbackNode,EdgeCallbackFn CallbackEdge,bool SortedWalk) const21ac9a064cSDimitry Andric void OutlinedHashTree::walkGraph(NodeCallbackFn CallbackNode,
22ac9a064cSDimitry Andric                                  EdgeCallbackFn CallbackEdge,
23ac9a064cSDimitry Andric                                  bool SortedWalk) const {
24ac9a064cSDimitry Andric   SmallVector<const HashNode *> Stack;
25ac9a064cSDimitry Andric   Stack.emplace_back(getRoot());
26ac9a064cSDimitry Andric 
27ac9a064cSDimitry Andric   while (!Stack.empty()) {
28ac9a064cSDimitry Andric     const auto *Current = Stack.pop_back_val();
29ac9a064cSDimitry Andric     if (CallbackNode)
30ac9a064cSDimitry Andric       CallbackNode(Current);
31ac9a064cSDimitry Andric 
32ac9a064cSDimitry Andric     auto HandleNext = [&](const HashNode *Next) {
33ac9a064cSDimitry Andric       if (CallbackEdge)
34ac9a064cSDimitry Andric         CallbackEdge(Current, Next);
35ac9a064cSDimitry Andric       Stack.emplace_back(Next);
36ac9a064cSDimitry Andric     };
37ac9a064cSDimitry Andric     if (SortedWalk) {
38ac9a064cSDimitry Andric       SmallVector<std::pair<stable_hash, const HashNode *>> SortedSuccessors;
39ac9a064cSDimitry Andric       for (const auto &[Hash, Successor] : Current->Successors)
40ac9a064cSDimitry Andric         SortedSuccessors.emplace_back(Hash, Successor.get());
41ac9a064cSDimitry Andric       llvm::sort(SortedSuccessors);
42ac9a064cSDimitry Andric       for (const auto &P : SortedSuccessors)
43ac9a064cSDimitry Andric         HandleNext(P.second);
44ac9a064cSDimitry Andric     } else {
45ac9a064cSDimitry Andric       for (const auto &P : Current->Successors)
46ac9a064cSDimitry Andric         HandleNext(P.second.get());
47ac9a064cSDimitry Andric     }
48ac9a064cSDimitry Andric   }
49ac9a064cSDimitry Andric }
50ac9a064cSDimitry Andric 
size(bool GetTerminalCountOnly) const51ac9a064cSDimitry Andric size_t OutlinedHashTree::size(bool GetTerminalCountOnly) const {
52ac9a064cSDimitry Andric   size_t Size = 0;
53ac9a064cSDimitry Andric   walkGraph([&Size, GetTerminalCountOnly](const HashNode *N) {
54ac9a064cSDimitry Andric     Size += (N && (!GetTerminalCountOnly || N->Terminals));
55ac9a064cSDimitry Andric   });
56ac9a064cSDimitry Andric   return Size;
57ac9a064cSDimitry Andric }
58ac9a064cSDimitry Andric 
depth() const59ac9a064cSDimitry Andric size_t OutlinedHashTree::depth() const {
60ac9a064cSDimitry Andric   size_t Size = 0;
61ac9a064cSDimitry Andric   DenseMap<const HashNode *, size_t> DepthMap;
62ac9a064cSDimitry Andric   walkGraph([&Size, &DepthMap](
63ac9a064cSDimitry Andric                 const HashNode *N) { Size = std::max(Size, DepthMap[N]); },
64ac9a064cSDimitry Andric             [&DepthMap](const HashNode *Src, const HashNode *Dst) {
65ac9a064cSDimitry Andric               size_t Depth = DepthMap[Src];
66ac9a064cSDimitry Andric               DepthMap[Dst] = Depth + 1;
67ac9a064cSDimitry Andric             });
68ac9a064cSDimitry Andric   return Size;
69ac9a064cSDimitry Andric }
70ac9a064cSDimitry Andric 
insert(const HashSequencePair & SequencePair)71ac9a064cSDimitry Andric void OutlinedHashTree::insert(const HashSequencePair &SequencePair) {
72ac9a064cSDimitry Andric   auto &[Sequence, Count] = SequencePair;
73ac9a064cSDimitry Andric   HashNode *Current = getRoot();
74ac9a064cSDimitry Andric 
75ac9a064cSDimitry Andric   for (stable_hash StableHash : Sequence) {
76ac9a064cSDimitry Andric     auto I = Current->Successors.find(StableHash);
77ac9a064cSDimitry Andric     if (I == Current->Successors.end()) {
78ac9a064cSDimitry Andric       std::unique_ptr<HashNode> Next = std::make_unique<HashNode>();
79ac9a064cSDimitry Andric       HashNode *NextPtr = Next.get();
80ac9a064cSDimitry Andric       NextPtr->Hash = StableHash;
81ac9a064cSDimitry Andric       Current->Successors.emplace(StableHash, std::move(Next));
82ac9a064cSDimitry Andric       Current = NextPtr;
83ac9a064cSDimitry Andric     } else
84ac9a064cSDimitry Andric       Current = I->second.get();
85ac9a064cSDimitry Andric   }
86ac9a064cSDimitry Andric   if (Count)
87ac9a064cSDimitry Andric     Current->Terminals = (Current->Terminals ? *Current->Terminals : 0) + Count;
88ac9a064cSDimitry Andric }
89ac9a064cSDimitry Andric 
merge(const OutlinedHashTree * Tree)90ac9a064cSDimitry Andric void OutlinedHashTree::merge(const OutlinedHashTree *Tree) {
91ac9a064cSDimitry Andric   HashNode *Dst = getRoot();
92ac9a064cSDimitry Andric   const HashNode *Src = Tree->getRoot();
93ac9a064cSDimitry Andric   SmallVector<std::pair<HashNode *, const HashNode *>> Stack;
94ac9a064cSDimitry Andric   Stack.emplace_back(Dst, Src);
95ac9a064cSDimitry Andric 
96ac9a064cSDimitry Andric   while (!Stack.empty()) {
97ac9a064cSDimitry Andric     auto [DstNode, SrcNode] = Stack.pop_back_val();
98ac9a064cSDimitry Andric     if (!SrcNode)
99ac9a064cSDimitry Andric       continue;
100ac9a064cSDimitry Andric     if (SrcNode->Terminals)
101ac9a064cSDimitry Andric       DstNode->Terminals =
102ac9a064cSDimitry Andric           (DstNode->Terminals ? *DstNode->Terminals : 0) + *SrcNode->Terminals;
103ac9a064cSDimitry Andric     for (auto &[Hash, NextSrcNode] : SrcNode->Successors) {
104ac9a064cSDimitry Andric       HashNode *NextDstNode;
105ac9a064cSDimitry Andric       auto I = DstNode->Successors.find(Hash);
106ac9a064cSDimitry Andric       if (I == DstNode->Successors.end()) {
107ac9a064cSDimitry Andric         auto NextDst = std::make_unique<HashNode>();
108ac9a064cSDimitry Andric         NextDstNode = NextDst.get();
109ac9a064cSDimitry Andric         NextDstNode->Hash = Hash;
110ac9a064cSDimitry Andric         DstNode->Successors.emplace(Hash, std::move(NextDst));
111ac9a064cSDimitry Andric       } else
112ac9a064cSDimitry Andric         NextDstNode = I->second.get();
113ac9a064cSDimitry Andric 
114ac9a064cSDimitry Andric       Stack.emplace_back(NextDstNode, NextSrcNode.get());
115ac9a064cSDimitry Andric     }
116ac9a064cSDimitry Andric   }
117ac9a064cSDimitry Andric }
118ac9a064cSDimitry Andric 
119ac9a064cSDimitry Andric std::optional<unsigned>
find(const HashSequence & Sequence) const120ac9a064cSDimitry Andric OutlinedHashTree::find(const HashSequence &Sequence) const {
121ac9a064cSDimitry Andric   const HashNode *Current = getRoot();
122ac9a064cSDimitry Andric   for (stable_hash StableHash : Sequence) {
123ac9a064cSDimitry Andric     const auto I = Current->Successors.find(StableHash);
124ac9a064cSDimitry Andric     if (I == Current->Successors.end())
125ac9a064cSDimitry Andric       return 0;
126ac9a064cSDimitry Andric     Current = I->second.get();
127ac9a064cSDimitry Andric   }
128ac9a064cSDimitry Andric   return Current->Terminals;
129ac9a064cSDimitry Andric }
130