mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
02ea66d696
Summary: This patch introduces a way of informing the (Post)DominatorTree about multiple CFG updates that happened since the last tree update. This makes performing tree updates much easier, as it internally takes care of applying the updates in lockstep with the (virtual) updates to the CFG, which is done by reverse-applying future CFG updates. The batch updater is able to remove redundant updates that cancel each other out. In the future, it should be also possible to reorder updates to reduce the amount of work needed to perform the updates. Reviewers: dberlin, sanjoy, grosser, davide, brzycki Reviewed By: brzycki Subscribers: mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D36167 llvm-svn: 311015
261 lines
8.5 KiB
C++
261 lines
8.5 KiB
C++
//===- 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());
|
|
}
|
|
}
|