
Use basic block numbers to store dominator tree nodes in a vector. This avoids frequent map lookups. Use block number epochs to validate that no renumbering occured since the tree was created; after a renumbering, the dominator tree can be updated with updateBlockNumbers(). Block numbers, block number epoch, and max block number are fetched via newly added GraphTraits methods. Graphs which do not implement getNumber() for blocks will use a DenseMap for an ad-hoc numbering.
110 lines
3.2 KiB
C++
110 lines
3.2 KiB
C++
//===- unittests/Support/GenericDomTreeTest.cpp - GenericDomTree.h tests --===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Support/GenericDomTree.h"
|
|
#include "llvm/ADT/GraphTraits.h"
|
|
#include "llvm/Support/DataTypes.h"
|
|
#include "gtest/gtest.h"
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
// Very simple (fake) graph structure to test dominator tree on.
|
|
struct NumberedGraph;
|
|
|
|
struct NumberedNode {
|
|
NumberedGraph *Parent;
|
|
unsigned Number;
|
|
|
|
NumberedNode(NumberedGraph *Parent, unsigned Number)
|
|
: Parent(Parent), Number(Number) {}
|
|
|
|
NumberedGraph *getParent() const { return Parent; }
|
|
};
|
|
|
|
struct NumberedGraph {
|
|
SmallVector<std::unique_ptr<NumberedNode>> Nodes;
|
|
unsigned NumberEpoch = 0;
|
|
|
|
NumberedNode *addNode() {
|
|
unsigned Num = Nodes.size();
|
|
return Nodes.emplace_back(std::make_unique<NumberedNode>(this, Num)).get();
|
|
}
|
|
};
|
|
} // namespace
|
|
|
|
namespace llvm {
|
|
template <> struct GraphTraits<NumberedNode *> {
|
|
using NodeRef = NumberedNode *;
|
|
static unsigned getNumber(NumberedNode *Node) { return Node->Number; }
|
|
};
|
|
|
|
template <> struct GraphTraits<const NumberedNode *> {
|
|
using NodeRef = NumberedNode *;
|
|
static unsigned getNumber(const NumberedNode *Node) { return Node->Number; }
|
|
};
|
|
|
|
template <> struct GraphTraits<NumberedGraph *> {
|
|
using NodeRef = NumberedNode *;
|
|
static unsigned getMaxNumber(NumberedGraph *G) { return G->Nodes.size(); }
|
|
static unsigned getNumberEpoch(NumberedGraph *G) { return G->NumberEpoch; }
|
|
};
|
|
|
|
namespace DomTreeBuilder {
|
|
// Dummy specialization. Only needed so that we can call recalculate(), which
|
|
// sets DT.Parent -- but we can't access DT.Parent here.
|
|
template <> void Calculate(DomTreeBase<NumberedNode> &DT) {}
|
|
} // end namespace DomTreeBuilder
|
|
} // end namespace llvm
|
|
|
|
namespace {
|
|
|
|
TEST(GenericDomTree, BlockNumbers) {
|
|
NumberedGraph G;
|
|
NumberedNode *N1 = G.addNode();
|
|
NumberedNode *N2 = G.addNode();
|
|
|
|
DomTreeBase<NumberedNode> DT;
|
|
DT.recalculate(G); // only sets parent
|
|
// Construct fake domtree: node 0 dominates all other nodes
|
|
DT.setNewRoot(N1);
|
|
DT.addNewBlock(N2, N1);
|
|
|
|
// Roundtrip is correct
|
|
for (auto &N : G.Nodes)
|
|
EXPECT_EQ(DT.getNode(N.get())->getBlock(), N.get());
|
|
// If we manually change a number, we should get a different node.
|
|
ASSERT_EQ(N1->Number, 0u);
|
|
ASSERT_EQ(N2->Number, 1u);
|
|
N1->Number = 1;
|
|
EXPECT_EQ(DT.getNode(N1)->getBlock(), N2);
|
|
EXPECT_EQ(DT.getNode(N2)->getBlock(), N2);
|
|
N2->Number = 0;
|
|
EXPECT_EQ(DT.getNode(N2)->getBlock(), N1);
|
|
|
|
// Renumer blocks, should fix node domtree-internal node map
|
|
DT.updateBlockNumbers();
|
|
for (auto &N : G.Nodes)
|
|
EXPECT_EQ(DT.getNode(N.get())->getBlock(), N.get());
|
|
|
|
// Adding a new node with a higher number is no problem
|
|
NumberedNode *N3 = G.addNode();
|
|
EXPECT_EQ(DT.getNode(N3), nullptr);
|
|
// ... even if it exceeds getMaxNumber()
|
|
NumberedNode *N4 = G.addNode();
|
|
N4->Number = 1000;
|
|
EXPECT_EQ(DT.getNode(N4), nullptr);
|
|
|
|
DT.addNewBlock(N3, N1);
|
|
DT.addNewBlock(N4, N1);
|
|
for (auto &N : G.Nodes)
|
|
EXPECT_EQ(DT.getNode(N.get())->getBlock(), N.get());
|
|
}
|
|
|
|
} // namespace
|