123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- //===- llvm/unittests/IR/DominatorTreeBatchUpdatesTest.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
- //
- //===----------------------------------------------------------------------===//
- #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;
- using DomUpdate = DominatorTree::UpdateType;
- static_assert(
- std::is_same<DomUpdate, PostDominatorTree::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;
- cfg::LegalizeUpdates<BasicBlock *>(Updates, Legalized, false);
- LLVM_DEBUG(dbgs() << "Legalized updates:\t");
- LLVM_DEBUG(for (auto &U : Legalized) { U.dump(); dbgs() << ", "; });
- LLVM_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;
- cfg::LegalizeUpdates<BasicBlock *>(Updates, Legalized, true);
- LLVM_DEBUG(dbgs() << "Legalized postdom updates:\t");
- LLVM_DEBUG(for (auto &U : Legalized) { U.dump(); dbgs() << ", "; });
- LLVM_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());
- PostDominatorTree PDT(*Holder.F);
- EXPECT_TRUE(PDT.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());
- PostDominatorTree PDT(*Holder.F);
- EXPECT_TRUE(PDT.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());
- PostDominatorTree 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());
- PostDominatorTree 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());
- PostDominatorTree 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());
- PostDominatorTree 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());
- }
- }
- // These are some odd flowgraphs, usually generated from csmith cases,
- // which are difficult on post dom trees.
- TEST(DominatorTreeBatchUpdates, InfiniteLoop) {
- std::vector<CFGBuilder::Arc> Arcs = {
- {"1", "2"},
- {"2", "3"},
- {"3", "6"}, {"3", "5"},
- {"4", "5"},
- {"5", "2"},
- {"6", "3"}, {"6", "4"}};
- // SplitBlock on 3 -> 5
- std::vector<CFGBuilder::Update> Updates = {
- {CFGInsert, {"N", "5"}}, {CFGInsert, {"3", "N"}}, {CFGDelete, {"3", "5"}}};
- CFGHolder Holder;
- CFGBuilder B(Holder.F, Arcs, Updates);
- DominatorTree DT(*Holder.F);
- EXPECT_TRUE(DT.verify());
- PostDominatorTree 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, DeadBlocks) {
- std::vector<CFGBuilder::Arc> Arcs = {
- {"1", "2"},
- {"2", "3"},
- {"3", "4"}, {"3", "7"},
- {"4", "4"},
- {"5", "6"}, {"5", "7"},
- {"6", "7"},
- {"7", "2"}, {"7", "8"}};
- // Remove dead 5 and 7,
- // plus SplitBlock on 7 -> 8
- std::vector<CFGBuilder::Update> Updates = {
- {CFGDelete, {"6", "7"}}, {CFGDelete, {"5", "7"}}, {CFGDelete, {"5", "6"}},
- {CFGInsert, {"N", "8"}}, {CFGInsert, {"7", "N"}}, {CFGDelete, {"7", "8"}}};
- CFGHolder Holder;
- CFGBuilder B(Holder.F, Arcs, Updates);
- DominatorTree DT(*Holder.F);
- EXPECT_TRUE(DT.verify());
- PostDominatorTree 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, InfiniteLoop2) {
- std::vector<CFGBuilder::Arc> Arcs = {
- {"1", "2"},
- {"2", "6"}, {"2", "3"},
- {"3", "4"},
- {"4", "5"}, {"4", "6"},
- {"5", "4"},
- {"6", "2"}};
- // SplitBlock on 4 -> 6
- std::vector<CFGBuilder::Update> Updates = {
- {CFGInsert, {"N", "6"}}, {CFGInsert, {"4", "N"}}, {CFGDelete, {"4", "6"}}};
- CFGHolder Holder;
- CFGBuilder B(Holder.F, Arcs, Updates);
- DominatorTree DT(*Holder.F);
- EXPECT_TRUE(DT.verify());
- PostDominatorTree 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());
- }
|