|
|
@@ -0,0 +1,260 @@ |
|
|
//===- llvm/unittests/IR/DominatorTreeBatchUpdatesTest.cpp ----------------===// |
|
|
// |
|
|
// The LLVM Compiler Infrastructure |
|
|
// |
|
|
// This file is distributed under the University of Illinois Open Source |
|
|
// License. See LICENSE.TXT for details. |
|
|
// |
|
|
//===----------------------------------------------------------------------===// |
|
|
|
|
|
#include <random> |
|
|
#include "CFGBuilder.h" |
|
|
#include "gtest/gtest.h" |
|
|
#include "llvm/Analysis/PostDominators.h" |
|
|
#include "llvm/IR/Dominators.h" |
|
|
#include "llvm/Support/GenericDomTreeConstruction.h" |
|
|
|
|
|
#define DEBUG_TYPE "batch-update-tests" |
|
|
|
|
|
using namespace llvm; |
|
|
|
|
|
namespace { |
|
|
const auto CFGInsert = CFGBuilder::ActionKind::Insert; |
|
|
const auto CFGDelete = CFGBuilder::ActionKind::Delete; |
|
|
|
|
|
struct PostDomTree : PostDomTreeBase<BasicBlock> { |
|
|
PostDomTree(Function &F) { recalculate(F); } |
|
|
}; |
|
|
|
|
|
using DomUpdate = DominatorTree::UpdateType; |
|
|
static_assert( |
|
|
std::is_same<DomUpdate, PostDomTree::UpdateType>::value, |
|
|
"Trees differing only in IsPostDom should have the same update types"); |
|
|
using DomSNCA = DomTreeBuilder::SemiNCAInfo<DomTreeBuilder::BBDomTree>; |
|
|
using PostDomSNCA = DomTreeBuilder::SemiNCAInfo<DomTreeBuilder::BBPostDomTree>; |
|
|
const auto Insert = DominatorTree::Insert; |
|
|
const auto Delete = DominatorTree::Delete; |
|
|
|
|
|
std::vector<DomUpdate> ToDomUpdates(CFGBuilder &B, |
|
|
std::vector<CFGBuilder::Update> &In) { |
|
|
std::vector<DomUpdate> Res; |
|
|
Res.reserve(In.size()); |
|
|
|
|
|
for (const auto &CFGU : In) |
|
|
Res.push_back({CFGU.Action == CFGInsert ? Insert : Delete, |
|
|
B.getOrAddBlock(CFGU.Edge.From), |
|
|
B.getOrAddBlock(CFGU.Edge.To)}); |
|
|
return Res; |
|
|
} |
|
|
} // namespace |
|
|
|
|
|
TEST(DominatorTreeBatchUpdates, LegalizeDomUpdates) { |
|
|
CFGHolder Holder; |
|
|
CFGBuilder Builder(Holder.F, {{"A", "B"}}, {}); |
|
|
|
|
|
BasicBlock *A = Builder.getOrAddBlock("A"); |
|
|
BasicBlock *B = Builder.getOrAddBlock("B"); |
|
|
BasicBlock *C = Builder.getOrAddBlock("C"); |
|
|
BasicBlock *D = Builder.getOrAddBlock("D"); |
|
|
|
|
|
std::vector<DomUpdate> Updates = { |
|
|
{Insert, B, C}, {Insert, C, D}, {Delete, B, C}, {Insert, B, C}, |
|
|
{Insert, B, D}, {Delete, C, D}, {Delete, A, B}}; |
|
|
SmallVector<DomUpdate, 4> Legalized; |
|
|
DomSNCA::LegalizeUpdates(Updates, Legalized); |
|
|
DEBUG(dbgs() << "Legalized updates:\t"); |
|
|
DEBUG(for (auto &U : Legalized) dbgs() << U << ", "); |
|
|
DEBUG(dbgs() << "\n"); |
|
|
EXPECT_EQ(Legalized.size(), 3UL); |
|
|
EXPECT_NE(llvm::find(Legalized, DomUpdate{Insert, B, C}), Legalized.end()); |
|
|
EXPECT_NE(llvm::find(Legalized, DomUpdate{Insert, B, D}), Legalized.end()); |
|
|
EXPECT_NE(llvm::find(Legalized, DomUpdate{Delete, A, B}), Legalized.end()); |
|
|
} |
|
|
|
|
|
TEST(DominatorTreeBatchUpdates, LegalizePostDomUpdates) { |
|
|
CFGHolder Holder; |
|
|
CFGBuilder Builder(Holder.F, {{"A", "B"}}, {}); |
|
|
|
|
|
BasicBlock *A = Builder.getOrAddBlock("A"); |
|
|
BasicBlock *B = Builder.getOrAddBlock("B"); |
|
|
BasicBlock *C = Builder.getOrAddBlock("C"); |
|
|
BasicBlock *D = Builder.getOrAddBlock("D"); |
|
|
|
|
|
std::vector<DomUpdate> Updates = { |
|
|
{Insert, B, C}, {Insert, C, D}, {Delete, B, C}, {Insert, B, C}, |
|
|
{Insert, B, D}, {Delete, C, D}, {Delete, A, B}}; |
|
|
SmallVector<DomUpdate, 4> Legalized; |
|
|
PostDomSNCA::LegalizeUpdates(Updates, Legalized); |
|
|
DEBUG(dbgs() << "Legalized postdom updates:\t"); |
|
|
DEBUG(for (auto &U : Legalized) dbgs() << U << ", "); |
|
|
DEBUG(dbgs() << "\n"); |
|
|
EXPECT_EQ(Legalized.size(), 3UL); |
|
|
EXPECT_NE(llvm::find(Legalized, DomUpdate{Insert, C, B}), Legalized.end()); |
|
|
EXPECT_NE(llvm::find(Legalized, DomUpdate{Insert, D, B}), Legalized.end()); |
|
|
EXPECT_NE(llvm::find(Legalized, DomUpdate{Delete, B, A}), Legalized.end()); |
|
|
} |
|
|
|
|
|
TEST(DominatorTreeBatchUpdates, SingleInsertion) { |
|
|
CFGHolder Holder; |
|
|
CFGBuilder Builder(Holder.F, {{"A", "B"}}, {{CFGInsert, {"B", "C"}}}); |
|
|
|
|
|
DominatorTree DT(*Holder.F); |
|
|
EXPECT_TRUE(DT.verify()); |
|
|
PostDomTree PDT(*Holder.F); |
|
|
EXPECT_TRUE(DT.verify()); |
|
|
|
|
|
BasicBlock *B = Builder.getOrAddBlock("B"); |
|
|
BasicBlock *C = Builder.getOrAddBlock("C"); |
|
|
std::vector<DomUpdate> Updates = {{Insert, B, C}}; |
|
|
|
|
|
ASSERT_TRUE(Builder.applyUpdate()); |
|
|
|
|
|
DT.applyUpdates(Updates); |
|
|
EXPECT_TRUE(DT.verify()); |
|
|
PDT.applyUpdates(Updates); |
|
|
EXPECT_TRUE(PDT.verify()); |
|
|
} |
|
|
|
|
|
TEST(DominatorTreeBatchUpdates, SingleDeletion) { |
|
|
CFGHolder Holder; |
|
|
CFGBuilder Builder(Holder.F, {{"A", "B"}, {"B", "C"}}, |
|
|
{{CFGDelete, {"B", "C"}}}); |
|
|
|
|
|
DominatorTree DT(*Holder.F); |
|
|
EXPECT_TRUE(DT.verify()); |
|
|
PostDomTree PDT(*Holder.F); |
|
|
EXPECT_TRUE(DT.verify()); |
|
|
|
|
|
BasicBlock *B = Builder.getOrAddBlock("B"); |
|
|
BasicBlock *C = Builder.getOrAddBlock("C"); |
|
|
std::vector<DomUpdate> Updates = {{Delete, B, C}}; |
|
|
|
|
|
ASSERT_TRUE(Builder.applyUpdate()); |
|
|
|
|
|
DT.applyUpdates(Updates); |
|
|
EXPECT_TRUE(DT.verify()); |
|
|
PDT.applyUpdates(Updates); |
|
|
EXPECT_TRUE(PDT.verify()); |
|
|
} |
|
|
|
|
|
TEST(DominatorTreeBatchUpdates, FewInsertion) { |
|
|
std::vector<CFGBuilder::Update> CFGUpdates = {{CFGInsert, {"B", "C"}}, |
|
|
{CFGInsert, {"C", "B"}}, |
|
|
{CFGInsert, {"C", "D"}}, |
|
|
{CFGInsert, {"D", "E"}}}; |
|
|
|
|
|
CFGHolder Holder; |
|
|
CFGBuilder Builder(Holder.F, {{"A", "B"}}, CFGUpdates); |
|
|
|
|
|
DominatorTree DT(*Holder.F); |
|
|
EXPECT_TRUE(DT.verify()); |
|
|
PostDomTree PDT(*Holder.F); |
|
|
EXPECT_TRUE(PDT.verify()); |
|
|
|
|
|
BasicBlock *B = Builder.getOrAddBlock("B"); |
|
|
BasicBlock *C = Builder.getOrAddBlock("C"); |
|
|
BasicBlock *D = Builder.getOrAddBlock("D"); |
|
|
BasicBlock *E = Builder.getOrAddBlock("E"); |
|
|
|
|
|
std::vector<DomUpdate> Updates = { |
|
|
{Insert, B, C}, {Insert, C, B}, {Insert, C, D}, {Insert, D, E}}; |
|
|
|
|
|
while (Builder.applyUpdate()) |
|
|
; |
|
|
|
|
|
DT.applyUpdates(Updates); |
|
|
EXPECT_TRUE(DT.verify()); |
|
|
PDT.applyUpdates(Updates); |
|
|
EXPECT_TRUE(PDT.verify()); |
|
|
} |
|
|
|
|
|
TEST(DominatorTreeBatchUpdates, FewDeletions) { |
|
|
std::vector<CFGBuilder::Update> CFGUpdates = {{CFGDelete, {"B", "C"}}, |
|
|
{CFGDelete, {"C", "B"}}, |
|
|
{CFGDelete, {"B", "D"}}, |
|
|
{CFGDelete, {"D", "E"}}}; |
|
|
|
|
|
CFGHolder Holder; |
|
|
CFGBuilder Builder( |
|
|
Holder.F, {{"A", "B"}, {"B", "C"}, {"B", "D"}, {"D", "E"}, {"C", "B"}}, |
|
|
CFGUpdates); |
|
|
|
|
|
DominatorTree DT(*Holder.F); |
|
|
EXPECT_TRUE(DT.verify()); |
|
|
PostDomTree PDT(*Holder.F); |
|
|
EXPECT_TRUE(PDT.verify()); |
|
|
|
|
|
auto Updates = ToDomUpdates(Builder, CFGUpdates); |
|
|
|
|
|
while (Builder.applyUpdate()) |
|
|
; |
|
|
|
|
|
DT.applyUpdates(Updates); |
|
|
EXPECT_TRUE(DT.verify()); |
|
|
PDT.applyUpdates(Updates); |
|
|
EXPECT_TRUE(PDT.verify()); |
|
|
} |
|
|
|
|
|
TEST(DominatorTreeBatchUpdates, InsertDelete) { |
|
|
std::vector<CFGBuilder::Arc> Arcs = { |
|
|
{"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"}, |
|
|
{"3", "8"}, {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}}; |
|
|
|
|
|
std::vector<CFGBuilder::Update> Updates = { |
|
|
{CFGInsert, {"2", "4"}}, {CFGInsert, {"12", "10"}}, |
|
|
{CFGInsert, {"10", "9"}}, {CFGInsert, {"7", "6"}}, |
|
|
{CFGInsert, {"7", "5"}}, {CFGDelete, {"3", "8"}}, |
|
|
{CFGInsert, {"10", "7"}}, {CFGInsert, {"2", "8"}}, |
|
|
{CFGDelete, {"3", "4"}}, {CFGDelete, {"8", "9"}}, |
|
|
{CFGDelete, {"11", "12"}}}; |
|
|
|
|
|
CFGHolder Holder; |
|
|
CFGBuilder B(Holder.F, Arcs, Updates); |
|
|
DominatorTree DT(*Holder.F); |
|
|
EXPECT_TRUE(DT.verify()); |
|
|
PostDomTree PDT(*Holder.F); |
|
|
EXPECT_TRUE(PDT.verify()); |
|
|
|
|
|
while (B.applyUpdate()) |
|
|
; |
|
|
|
|
|
auto DomUpdates = ToDomUpdates(B, Updates); |
|
|
DT.applyUpdates(DomUpdates); |
|
|
EXPECT_TRUE(DT.verify()); |
|
|
PDT.applyUpdates(DomUpdates); |
|
|
EXPECT_TRUE(PDT.verify()); |
|
|
} |
|
|
|
|
|
TEST(DominatorTreeBatchUpdates, InsertDeleteExhaustive) { |
|
|
std::vector<CFGBuilder::Arc> Arcs = { |
|
|
{"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"}, |
|
|
{"3", "8"}, {"8", "9"}, {"9", "10"}, {"8", "11"}, {"11", "12"}}; |
|
|
|
|
|
std::vector<CFGBuilder::Update> Updates = { |
|
|
{CFGInsert, {"2", "4"}}, {CFGInsert, {"12", "10"}}, |
|
|
{CFGInsert, {"10", "9"}}, {CFGInsert, {"7", "6"}}, |
|
|
{CFGInsert, {"7", "5"}}, {CFGDelete, {"3", "8"}}, |
|
|
{CFGInsert, {"10", "7"}}, {CFGInsert, {"2", "8"}}, |
|
|
{CFGDelete, {"3", "4"}}, {CFGDelete, {"8", "9"}}, |
|
|
{CFGDelete, {"11", "12"}}}; |
|
|
|
|
|
std::mt19937 Generator(0); |
|
|
for (unsigned i = 0; i < 16; ++i) { |
|
|
std::shuffle(Updates.begin(), Updates.end(), Generator); |
|
|
CFGHolder Holder; |
|
|
CFGBuilder B(Holder.F, Arcs, Updates); |
|
|
DominatorTree DT(*Holder.F); |
|
|
EXPECT_TRUE(DT.verify()); |
|
|
PostDomTree PDT(*Holder.F); |
|
|
EXPECT_TRUE(PDT.verify()); |
|
|
|
|
|
while (B.applyUpdate()) |
|
|
; |
|
|
|
|
|
auto DomUpdates = ToDomUpdates(B, Updates); |
|
|
DT.applyUpdates(DomUpdates); |
|
|
EXPECT_TRUE(DT.verify()); |
|
|
PDT.applyUpdates(DomUpdates); |
|
|
EXPECT_TRUE(PDT.verify()); |
|
|
} |
|
|
} |