Files
clang-p2996/llvm/lib/CodeGenData/OutlinedHashTree.cpp
Kyungwoo Lee d00f1c14dc [CGData] Outlined Hash Tree (#89792)
This defines the OutlinedHashTree class.
It contains sequences of stable hash values of instructions that have
been outlined. This OutlinedHashTree can be used to track the outlined
instruction sequences across modules. A trie structure is used in its
implementation, allowing for a compact sharing of common prefixes.

This is a patch for
https://discourse.llvm.org/t/rfc-enhanced-machine-outliner-part-2-thinlto-nolto/78753.
2024-07-07 09:15:54 +09:00

130 lines
4.3 KiB
C++

//===-- OutlinedHashTree.cpp ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// An OutlinedHashTree is a Trie that contains sequences of stable hash values
// of instructions that have been outlined. This OutlinedHashTree can be used
// to understand the outlined instruction sequences collected across modules.
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGenData/OutlinedHashTree.h"
#define DEBUG_TYPE "outlined-hash-tree"
using namespace llvm;
void OutlinedHashTree::walkGraph(NodeCallbackFn CallbackNode,
EdgeCallbackFn CallbackEdge,
bool SortedWalk) const {
SmallVector<const HashNode *> Stack;
Stack.emplace_back(getRoot());
while (!Stack.empty()) {
const auto *Current = Stack.pop_back_val();
if (CallbackNode)
CallbackNode(Current);
auto HandleNext = [&](const HashNode *Next) {
if (CallbackEdge)
CallbackEdge(Current, Next);
Stack.emplace_back(Next);
};
if (SortedWalk) {
SmallVector<std::pair<stable_hash, const HashNode *>> SortedSuccessors;
for (const auto &[Hash, Successor] : Current->Successors)
SortedSuccessors.emplace_back(Hash, Successor.get());
llvm::sort(SortedSuccessors);
for (const auto &P : SortedSuccessors)
HandleNext(P.second);
} else {
for (const auto &P : Current->Successors)
HandleNext(P.second.get());
}
}
}
size_t OutlinedHashTree::size(bool GetTerminalCountOnly) const {
size_t Size = 0;
walkGraph([&Size, GetTerminalCountOnly](const HashNode *N) {
Size += (N && (!GetTerminalCountOnly || N->Terminals));
});
return Size;
}
size_t OutlinedHashTree::depth() const {
size_t Size = 0;
DenseMap<const HashNode *, size_t> DepthMap;
walkGraph([&Size, &DepthMap](
const HashNode *N) { Size = std::max(Size, DepthMap[N]); },
[&DepthMap](const HashNode *Src, const HashNode *Dst) {
size_t Depth = DepthMap[Src];
DepthMap[Dst] = Depth + 1;
});
return Size;
}
void OutlinedHashTree::insert(const HashSequencePair &SequencePair) {
auto &[Sequence, Count] = SequencePair;
HashNode *Current = getRoot();
for (stable_hash StableHash : Sequence) {
auto I = Current->Successors.find(StableHash);
if (I == Current->Successors.end()) {
std::unique_ptr<HashNode> Next = std::make_unique<HashNode>();
HashNode *NextPtr = Next.get();
NextPtr->Hash = StableHash;
Current->Successors.emplace(StableHash, std::move(Next));
Current = NextPtr;
} else
Current = I->second.get();
}
if (Count)
Current->Terminals = (Current->Terminals ? *Current->Terminals : 0) + Count;
}
void OutlinedHashTree::merge(const OutlinedHashTree *Tree) {
HashNode *Dst = getRoot();
const HashNode *Src = Tree->getRoot();
SmallVector<std::pair<HashNode *, const HashNode *>> Stack;
Stack.emplace_back(Dst, Src);
while (!Stack.empty()) {
auto [DstNode, SrcNode] = Stack.pop_back_val();
if (!SrcNode)
continue;
if (SrcNode->Terminals)
DstNode->Terminals =
(DstNode->Terminals ? *DstNode->Terminals : 0) + *SrcNode->Terminals;
for (auto &[Hash, NextSrcNode] : SrcNode->Successors) {
HashNode *NextDstNode;
auto I = DstNode->Successors.find(Hash);
if (I == DstNode->Successors.end()) {
auto NextDst = std::make_unique<HashNode>();
NextDstNode = NextDst.get();
NextDstNode->Hash = Hash;
DstNode->Successors.emplace(Hash, std::move(NextDst));
} else
NextDstNode = I->second.get();
Stack.emplace_back(NextDstNode, NextSrcNode.get());
}
}
}
std::optional<unsigned>
OutlinedHashTree::find(const HashSequence &Sequence) const {
const HashNode *Current = getRoot();
for (stable_hash StableHash : Sequence) {
const auto I = Current->Successors.find(StableHash);
if (I == Current->Successors.end())
return 0;
Current = I->second.get();
}
return Current->Terminals;
}