diff options
| author | 2018-04-06 14:26:03 +0000 | |
|---|---|---|
| committer | 2018-04-06 14:26:03 +0000 | |
| commit | bdabc2f19ffb9e20600dad6e8a300842a7bda50e (patch) | |
| tree | c50e7b2e5449b074651bb82a58517a8ebc4a8cf7 /gnu/llvm/unittests/IR/DominatorTreeTest.cpp | |
| parent | Print a 'p' flag for file descriptors that were opened after pledge(2). (diff) | |
| download | wireguard-openbsd-bdabc2f19ffb9e20600dad6e8a300842a7bda50e.tar.xz wireguard-openbsd-bdabc2f19ffb9e20600dad6e8a300842a7bda50e.zip | |
Import LLVM 6.0.1 release including clang, lld and lldb.
"where is the kaboom?" deraadt@
Diffstat (limited to 'gnu/llvm/unittests/IR/DominatorTreeTest.cpp')
| -rw-r--r-- | gnu/llvm/unittests/IR/DominatorTreeTest.cpp | 348 |
1 files changed, 348 insertions, 0 deletions
diff --git a/gnu/llvm/unittests/IR/DominatorTreeTest.cpp b/gnu/llvm/unittests/IR/DominatorTreeTest.cpp index df1e2993dc8..4666f93da2d 100644 --- a/gnu/llvm/unittests/IR/DominatorTreeTest.cpp +++ b/gnu/llvm/unittests/IR/DominatorTreeTest.cpp @@ -326,6 +326,278 @@ TEST(DominatorTree, NonUniqueEdges) { }); } +// Verify that the PDT is correctly updated in case an edge removal results +// in a new unreachable CFG node. Also make sure that the updated PDT is the +// same as a freshly recalculated one. +// +// For the following input code and initial PDT: +// +// CFG PDT +// +// A Exit +// | | +// _B D +// / | \ | +// ^ v \ B +// \ / D / \ +// C \ C A +// v +// Exit +// +// we verify that CFG' and PDT-updated is obtained after removal of edge C -> B. +// +// CFG' PDT-updated +// +// A Exit +// | / | \ +// B C B D +// | \ | +// v \ A +// / D +// C \ +// | \ +// unreachable Exit +// +// Both the blocks that end with ret and with unreachable become trivial +// PostDomTree roots, as they have no successors. +// +TEST(DominatorTree, DeletingEdgesIntroducesUnreachables) { + StringRef ModuleString = + "define void @f() {\n" + "A:\n" + " br label %B\n" + "B:\n" + " br i1 undef, label %D, label %C\n" + "C:\n" + " br label %B\n" + "D:\n" + " ret void\n" + "}\n"; + + // Parse the module. + LLVMContext Context; + std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); + + runWithDomTree( + *M, "f", [&](Function &F, DominatorTree *DT, PostDomTree *PDT) { + Function::iterator FI = F.begin(); + + FI++; + BasicBlock *B = &*FI++; + BasicBlock *C = &*FI++; + BasicBlock *D = &*FI++; + + ASSERT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B))); + EXPECT_TRUE(DT->verify()); + EXPECT_TRUE(PDT->verify()); + + C->getTerminator()->eraseFromParent(); + new UnreachableInst(C->getContext(), C); + + DT->deleteEdge(C, B); + PDT->deleteEdge(C, B); + + EXPECT_TRUE(DT->verify()); + EXPECT_TRUE(PDT->verify()); + + EXPECT_FALSE(PDT->dominates(PDT->getNode(D), PDT->getNode(B))); + EXPECT_NE(PDT->getNode(C), nullptr); + + DominatorTree NDT(F); + EXPECT_EQ(DT->compare(NDT), 0); + + PostDomTree NPDT(F); + EXPECT_EQ(PDT->compare(NPDT), 0); + }); +} + +// Verify that the PDT is correctly updated in case an edge removal results +// in an infinite loop. Also make sure that the updated PDT is the +// same as a freshly recalculated one. +// +// Test case: +// +// CFG PDT +// +// A Exit +// | | +// _B D +// / | \ | +// ^ v \ B +// \ / D / \ +// C \ C A +// / \ v +// ^ v Exit +// \_/ +// +// After deleting the edge C->B, C is part of an infinite reverse-unreachable +// loop: +// +// CFG' PDT' +// +// A Exit +// | / | \ +// B C B D +// | \ | +// v \ A +// / D +// C \ +// / \ v +// ^ v Exit +// \_/ +// +// As C now becomes reverse-unreachable, it forms a new non-trivial root and +// gets connected to the virtual exit. +// D does not postdominate B anymore, because there are two forward paths from +// B to the virtual exit: +// - B -> C -> VirtualExit +// - B -> D -> VirtualExit. +// +TEST(DominatorTree, DeletingEdgesIntroducesInfiniteLoop) { + StringRef ModuleString = + "define void @f() {\n" + "A:\n" + " br label %B\n" + "B:\n" + " br i1 undef, label %D, label %C\n" + "C:\n" + " switch i32 undef, label %C [\n" + " i32 0, label %B\n" + " ]\n" + "D:\n" + " ret void\n" + "}\n"; + + // Parse the module. + LLVMContext Context; + std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); + + runWithDomTree( + *M, "f", [&](Function &F, DominatorTree *DT, PostDomTree *PDT) { + Function::iterator FI = F.begin(); + + FI++; + BasicBlock *B = &*FI++; + BasicBlock *C = &*FI++; + BasicBlock *D = &*FI++; + + ASSERT_TRUE(PDT->dominates(PDT->getNode(D), PDT->getNode(B))); + EXPECT_TRUE(DT->verify()); + EXPECT_TRUE(PDT->verify()); + + auto SwitchC = cast<SwitchInst>(C->getTerminator()); + SwitchC->removeCase(SwitchC->case_begin()); + DT->deleteEdge(C, B); + EXPECT_TRUE(DT->verify()); + PDT->deleteEdge(C, B); + EXPECT_TRUE(PDT->verify()); + + EXPECT_FALSE(PDT->dominates(PDT->getNode(D), PDT->getNode(B))); + EXPECT_NE(PDT->getNode(C), nullptr); + + DominatorTree NDT(F); + EXPECT_EQ(DT->compare(NDT), 0); + + PostDomTree NPDT(F); + EXPECT_EQ(PDT->compare(NPDT), 0); + }); +} + +// Verify that the PDT is correctly updated in case an edge removal results +// in an infinite loop. +// +// Test case: +// +// CFG PDT +// +// A Exit +// | / | \ +// B-- C2 B D +// | \ / | +// v \ C A +// / D +// C--C2 \ +// / \ \ v +// ^ v --Exit +// \_/ +// +// After deleting the edge C->E, C is part of an infinite reverse-unreachable +// loop: +// +// CFG' PDT' +// +// A Exit +// | / | \ +// B C B D +// | \ | +// v \ A +// / D +// C \ +// / \ v +// ^ v Exit +// \_/ +// +// In PDT, D does not post-dominate B. After the edge C -> C2 is removed, +// C becomes a new nontrivial PDT root. +// +TEST(DominatorTree, DeletingEdgesIntroducesInfiniteLoop2) { + StringRef ModuleString = + "define void @f() {\n" + "A:\n" + " br label %B\n" + "B:\n" + " br i1 undef, label %D, label %C\n" + "C:\n" + " switch i32 undef, label %C [\n" + " i32 0, label %C2\n" + " ]\n" + "C2:\n" + " ret void\n" + "D:\n" + " ret void\n" + "}\n"; + + // Parse the module. + LLVMContext Context; + std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); + + runWithDomTree( + *M, "f", [&](Function &F, DominatorTree *DT, PostDomTree *PDT) { + Function::iterator FI = F.begin(); + + FI++; + BasicBlock *B = &*FI++; + BasicBlock *C = &*FI++; + BasicBlock *C2 = &*FI++; + BasicBlock *D = &*FI++; + + EXPECT_TRUE(DT->verify()); + EXPECT_TRUE(PDT->verify()); + + auto SwitchC = cast<SwitchInst>(C->getTerminator()); + SwitchC->removeCase(SwitchC->case_begin()); + DT->deleteEdge(C, C2); + PDT->deleteEdge(C, C2); + C2->removeFromParent(); + + EXPECT_EQ(DT->getNode(C2), nullptr); + PDT->eraseNode(C2); + delete C2; + + EXPECT_TRUE(DT->verify()); + EXPECT_TRUE(PDT->verify()); + + EXPECT_FALSE(PDT->dominates(PDT->getNode(D), PDT->getNode(B))); + EXPECT_NE(PDT->getNode(C), nullptr); + + DominatorTree NDT(F); + EXPECT_EQ(DT->compare(NDT), 0); + + PostDomTree NPDT(F); + EXPECT_EQ(PDT->compare(NPDT), 0); + }); +} + namespace { const auto Insert = CFGBuilder::ActionKind::Insert; const auto Delete = CFGBuilder::ActionKind::Delete; @@ -418,6 +690,27 @@ TEST(DominatorTree, InsertUnreachable) { } } +TEST(DominatorTree, InsertFromUnreachable) { + CFGHolder Holder; + std::vector<CFGBuilder::Arc> Arcs = {{"1", "2"}, {"2", "3"}, {"3", "4"}}; + + std::vector<CFGBuilder::Update> Updates = {{Insert, {"3", "5"}}}; + CFGBuilder B(Holder.F, Arcs, Updates); + PostDomTree PDT(*Holder.F); + EXPECT_TRUE(PDT.verify()); + + Optional<CFGBuilder::Update> LastUpdate = B.applyUpdate(); + EXPECT_TRUE(LastUpdate); + + EXPECT_EQ(LastUpdate->Action, Insert); + BasicBlock *From = B.getOrAddBlock(LastUpdate->Edge.From); + BasicBlock *To = B.getOrAddBlock(LastUpdate->Edge.To); + PDT.insertEdge(From, To); + EXPECT_TRUE(PDT.verify()); + EXPECT_TRUE(PDT.getRoots().size() == 2); + EXPECT_NE(PDT.getNode(B.getOrAddBlock("5")), nullptr); +} + TEST(DominatorTree, InsertMixed) { CFGHolder Holder; std::vector<CFGBuilder::Arc> Arcs = { @@ -529,6 +822,36 @@ TEST(DominatorTree, DeleteUnreachable) { } } +TEST(DominatorTree, DeletionsInSubtrees) { + CFGHolder Holder; + std::vector<CFGBuilder::Arc> Arcs = {{"0", "1"}, {"1", "2"}, {"1", "3"}, + {"1", "6"}, {"3", "4"}, {"2", "5"}, + {"5", "2"}}; + + // It is possible to perform multiple deletions and inform the + // DominatorTree about them at the same time, if the all of the + // deletions happen in different subtrees. + std::vector<CFGBuilder::Update> Updates = {{Delete, {"1", "2"}}, + {Delete, {"1", "3"}}}; + CFGBuilder B(Holder.F, Arcs, Updates); + DominatorTree DT(*Holder.F); + EXPECT_TRUE(DT.verify()); + + Optional<CFGBuilder::Update> LastUpdate; + while ((LastUpdate = B.applyUpdate())) + ; + + DT.deleteEdge(B.getOrAddBlock("1"), B.getOrAddBlock("2")); + DT.deleteEdge(B.getOrAddBlock("1"), B.getOrAddBlock("3")); + + EXPECT_TRUE(DT.verify()); + EXPECT_EQ(DT.getNode(B.getOrAddBlock("2")), nullptr); + EXPECT_EQ(DT.getNode(B.getOrAddBlock("3")), nullptr); + EXPECT_EQ(DT.getNode(B.getOrAddBlock("4")), nullptr); + EXPECT_EQ(DT.getNode(B.getOrAddBlock("5")), nullptr); + EXPECT_NE(DT.getNode(B.getOrAddBlock("6")), nullptr); +} + TEST(DominatorTree, InsertDelete) { std::vector<CFGBuilder::Arc> Arcs = { {"1", "2"}, {"2", "3"}, {"3", "4"}, {"4", "5"}, {"5", "6"}, {"5", "7"}, @@ -602,3 +925,28 @@ TEST(DominatorTree, InsertDeleteExhaustive) { } } } + +TEST(DominatorTree, InsertIntoIrreducible) { + std::vector<CFGBuilder::Arc> Arcs = { + {"0", "1"}, + {"1", "27"}, {"1", "7"}, + {"10", "18"}, + {"13", "10"}, + {"18", "13"}, {"18", "23"}, + {"23", "13"}, {"23", "24"}, + {"24", "1"}, {"24", "18"}, + {"27", "24"}}; + + CFGHolder Holder; + CFGBuilder B(Holder.F, Arcs, {{Insert, {"7", "23"}}}); + DominatorTree DT(*Holder.F); + EXPECT_TRUE(DT.verify()); + + B.applyUpdate(); + BasicBlock *From = B.getOrAddBlock("7"); + BasicBlock *To = B.getOrAddBlock("23"); + DT.insertEdge(From, To); + + EXPECT_TRUE(DT.verify()); +} + |
