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 21*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 51*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 59*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 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 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> 120*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