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