| //===- llvm/unittests/IR/DeferredDominanceTest.cpp - DDT unit tests -------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/AsmParser/Parser.h" |
| #include "llvm/IR/Constants.h" |
| #include "llvm/IR/Dominators.h" |
| #include "llvm/IR/Instructions.h" |
| #include "llvm/IR/LLVMContext.h" |
| #include "llvm/IR/Module.h" |
| #include "llvm/Support/SourceMgr.h" |
| #include "gtest/gtest.h" |
| |
| using namespace llvm; |
| |
| static std::unique_ptr<Module> makeLLVMModule(LLVMContext &Context, |
| StringRef ModuleStr) { |
| SMDiagnostic Err; |
| std::unique_ptr<Module> M = parseAssemblyString(ModuleStr, Err, Context); |
| assert(M && "Bad LLVM IR?"); |
| return M; |
| } |
| |
| TEST(DeferredDominance, BasicOperations) { |
| StringRef FuncName = "f"; |
| StringRef ModuleString = |
| "define i32 @f(i32 %i, i32 *%p) {\n" |
| " bb0:\n" |
| " store i32 %i, i32 *%p\n" |
| " switch i32 %i, label %bb1 [\n" |
| " i32 0, label %bb2\n" |
| " i32 1, label %bb2\n" |
| " i32 2, label %bb3\n" |
| " ]\n" |
| " bb1:\n" |
| " ret i32 1\n" |
| " bb2:\n" |
| " ret i32 2\n" |
| " bb3:\n" |
| " ret i32 3\n" |
| "}\n"; |
| // Make the module. |
| LLVMContext Context; |
| std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); |
| Function *F = M->getFunction(FuncName); |
| ASSERT_NE(F, nullptr) << "Couldn't get function " << FuncName << "."; |
| |
| // Make the DDT. |
| DominatorTree DT(*F); |
| DeferredDominance DDT(DT); |
| ASSERT_TRUE(DDT.flush().verify()); |
| |
| Function::iterator FI = F->begin(); |
| BasicBlock *BB0 = &*FI++; |
| BasicBlock *BB1 = &*FI++; |
| BasicBlock *BB2 = &*FI++; |
| BasicBlock *BB3 = &*FI++; |
| |
| // Test discards of invalid self-domination updates. These use the single |
| // short-hand interface but are still queued inside DDT. |
| DDT.deleteEdge(BB0, BB0); |
| DDT.insertEdge(BB1, BB1); |
| |
| // Delete edge bb0 -> bb3 and push the update twice to verify duplicate |
| // entries are discarded. |
| std::vector<DominatorTree::UpdateType> Updates; |
| Updates.reserve(4); |
| Updates.push_back({DominatorTree::Delete, BB0, BB3}); |
| Updates.push_back({DominatorTree::Delete, BB0, BB3}); |
| |
| // Unnecessary Insert: no edge bb1 -> bb2 after change to bb0. |
| Updates.push_back({DominatorTree::Insert, BB1, BB2}); |
| // Unnecessary Delete: edge exists bb0 -> bb1 after change to bb0. |
| Updates.push_back({DominatorTree::Delete, BB0, BB1}); |
| |
| // CFG Change: remove edge bb0 -> bb3 and one duplicate edge bb0 -> bb2. |
| EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 4u); |
| BB0->getTerminator()->eraseFromParent(); |
| BranchInst::Create(BB1, BB2, ConstantInt::getTrue(F->getContext()), BB0); |
| EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 2u); |
| |
| // Deletion of a BasicBlock is an immediate event. We remove all uses to the |
| // contained Instructions and change the Terminator to "unreachable" when |
| // queued for deletion. Its parent is still F until DDT.flush() is called. We |
| // don't defer this action because it can cause problems for other transforms |
| // or analysis as it's part of the actual CFG. We only defer updates to the |
| // DominatorTree. This code will crash if it is placed before the |
| // BranchInst::Create() call above. |
| ASSERT_FALSE(isa<UnreachableInst>(BB3->getTerminator())); |
| EXPECT_FALSE(DDT.pendingDeletedBB(BB3)); |
| DDT.deleteBB(BB3); |
| EXPECT_TRUE(DDT.pendingDeletedBB(BB3)); |
| ASSERT_TRUE(isa<UnreachableInst>(BB3->getTerminator())); |
| EXPECT_EQ(BB3->getParent(), F); |
| |
| // Verify. Updates to DDT must be applied *after* all changes to the CFG |
| // (including block deletion). |
| DDT.applyUpdates(Updates); |
| ASSERT_TRUE(DDT.flush().verify()); |
| } |
| |
| TEST(DeferredDominance, PairedUpdate) { |
| StringRef FuncName = "f"; |
| StringRef ModuleString = |
| "define i32 @f(i32 %i, i32 *%p) {\n" |
| " bb0:\n" |
| " store i32 %i, i32 *%p\n" |
| " switch i32 %i, label %bb1 [\n" |
| " i32 0, label %bb2\n" |
| " i32 1, label %bb2\n" |
| " ]\n" |
| " bb1:\n" |
| " ret i32 1\n" |
| " bb2:\n" |
| " ret i32 2\n" |
| "}\n"; |
| // Make the module. |
| LLVMContext Context; |
| std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); |
| Function *F = M->getFunction(FuncName); |
| ASSERT_NE(F, nullptr) << "Couldn't get function " << FuncName << "."; |
| |
| // Make the DDT. |
| DominatorTree DT(*F); |
| DeferredDominance DDT(DT); |
| ASSERT_TRUE(DDT.flush().verify()); |
| |
| Function::iterator FI = F->begin(); |
| BasicBlock *BB0 = &*FI++; |
| BasicBlock *BB1 = &*FI++; |
| BasicBlock *BB2 = &*FI++; |
| |
| // CFG Change: only edge from bb0 is bb0 -> bb1. |
| EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 3u); |
| BB0->getTerminator()->eraseFromParent(); |
| BranchInst::Create(BB1, BB0); |
| EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 1u); |
| |
| // Must be done after the CFG change. The applyUpdate() routine analyzes the |
| // current state of the CFG. |
| DDT.deleteEdge(BB0, BB2); |
| |
| // CFG Change: bb0 now has bb0 -> bb1 and bb0 -> bb2. |
| // With this change no dominance has been altered from the original IR. DT |
| // doesn't care if the type of TerminatorInstruction changed, only if the |
| // unique edges have. |
| EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 1u); |
| BB0->getTerminator()->eraseFromParent(); |
| BranchInst::Create(BB1, BB2, ConstantInt::getTrue(F->getContext()), BB0); |
| EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 2u); |
| |
| // Must be done after the CFG change. The applyUpdate() routine analyzes the |
| // current state of the CFG. This DDT update pairs with the previous one and |
| // is cancelled out before ever applying updates to DT. |
| DDT.insertEdge(BB0, BB2); |
| |
| // Test the empty DeletedBB list. |
| EXPECT_FALSE(DDT.pendingDeletedBB(BB0)); |
| EXPECT_FALSE(DDT.pendingDeletedBB(BB1)); |
| EXPECT_FALSE(DDT.pendingDeletedBB(BB2)); |
| |
| // The DT has no changes, this flush() simply returns a reference to the |
| // internal DT calculated at the beginning of this test. |
| ASSERT_TRUE(DDT.flush().verify()); |
| } |
| |
| TEST(DeferredDominance, ReplaceEntryBB) { |
| StringRef FuncName = "f"; |
| StringRef ModuleString = |
| "define i32 @f() {\n" |
| "bb0:\n" |
| " br label %bb1\n" |
| " bb1:\n" |
| " ret i32 1\n" |
| "}\n"; |
| // Make the module. |
| LLVMContext Context; |
| std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); |
| Function *F = M->getFunction(FuncName); |
| ASSERT_NE(F, nullptr) << "Couldn't get function " << FuncName << "."; |
| |
| // Make the DDT. |
| DominatorTree DT(*F); |
| DeferredDominance DDT(DT); |
| ASSERT_TRUE(DDT.flush().verify()); |
| |
| Function::iterator FI = F->begin(); |
| BasicBlock *BB0 = &*FI++; |
| BasicBlock *BB1 = &*FI++; |
| |
| // Add a block as the new function entry BB. We also link it to BB0. |
| BasicBlock *NewEntry = |
| BasicBlock::Create(F->getContext(), "new_entry", F, BB0); |
| BranchInst::Create(BB0, NewEntry); |
| EXPECT_EQ(F->begin()->getName(), NewEntry->getName()); |
| EXPECT_TRUE(&F->getEntryBlock() == NewEntry); |
| |
| // Insert the new edge between new_eentry -> bb0. Without this the |
| // recalculate() call below will not actually recalculate the DT as there |
| // are no changes pending and no blocks deleted. |
| DDT.insertEdge(NewEntry, BB0); |
| |
| // Changing the Entry BB requires a full recalulation. |
| DDT.recalculate(*F); |
| ASSERT_TRUE(DDT.flush().verify()); |
| |
| // CFG Change: remove new_edge -> bb0 and redirect to new_edge -> bb1. |
| EXPECT_EQ(NewEntry->getTerminator()->getNumSuccessors(), 1u); |
| NewEntry->getTerminator()->eraseFromParent(); |
| BranchInst::Create(BB1, NewEntry); |
| EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 1u); |
| |
| // Update the DDT. At this point bb0 now has no predecessors but is still a |
| // Child of F. |
| DDT.applyUpdates({{DominatorTree::Delete, NewEntry, BB0}, |
| {DominatorTree::Insert, NewEntry, BB1}}); |
| ASSERT_TRUE(DDT.flush().verify()); |
| |
| // Now remove bb0 from F. |
| ASSERT_FALSE(isa<UnreachableInst>(BB0->getTerminator())); |
| EXPECT_FALSE(DDT.pendingDeletedBB(BB0)); |
| DDT.deleteBB(BB0); |
| EXPECT_TRUE(DDT.pendingDeletedBB(BB0)); |
| ASSERT_TRUE(isa<UnreachableInst>(BB0->getTerminator())); |
| EXPECT_EQ(BB0->getParent(), F); |
| |
| // Perform a full recalculation of the DDT. It is not necessary here but we |
| // do this to test the case when there are no pending DT updates but there are |
| // pending deleted BBs. |
| DDT.recalculate(*F); |
| ASSERT_TRUE(DDT.flush().verify()); |
| } |
| |
| TEST(DeferredDominance, InheritedPreds) { |
| StringRef FuncName = "f"; |
| StringRef ModuleString = |
| "define i32 @f(i32 %i, i32 *%p) {\n" |
| " bb0:\n" |
| " store i32 %i, i32 *%p\n" |
| " switch i32 %i, label %bb1 [\n" |
| " i32 2, label %bb2\n" |
| " i32 3, label %bb3\n" |
| " ]\n" |
| " bb1:\n" |
| " br label %bb3\n" |
| " bb2:\n" |
| " br label %bb3\n" |
| " bb3:\n" |
| " ret i32 3\n" |
| "}\n"; |
| // Make the module. |
| LLVMContext Context; |
| std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString); |
| Function *F = M->getFunction(FuncName); |
| ASSERT_NE(F, nullptr) << "Couldn't get function " << FuncName << "."; |
| |
| // Make the DDT. |
| DominatorTree DT(*F); |
| DeferredDominance DDT(DT); |
| ASSERT_TRUE(DDT.flush().verify()); |
| |
| Function::iterator FI = F->begin(); |
| BasicBlock *BB0 = &*FI++; |
| BasicBlock *BB1 = &*FI++; |
| BasicBlock *BB2 = &*FI++; |
| BasicBlock *BB3 = &*FI++; |
| |
| // There are several CFG locations where we have: |
| // |
| // pred1..predN |
| // | | |
| // +> curr <+ converted into: pred1..predN curr |
| // | | | |
| // v +> succ <+ |
| // succ |
| // |
| // There is a specific shape of this we have to be careful of: |
| // |
| // pred1..predN |
| // || | |
| // |+> curr <+ converted into: pred1..predN curr |
| // | | | | |
| // | v +> succ <+ |
| // +-> succ |
| // |
| // While the final CFG form is functionally identical the updates to |
| // DDT are not. In the first case we must have DDT.insertEdge(Pred1, Succ) |
| // while in the latter case we must *NOT* have DDT.insertEdge(Pred1, Succ). |
| |
| // CFG Change: bb0 now only has bb0 -> bb1 and bb0 -> bb3. We are preparing to |
| // remove bb2. |
| EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 3u); |
| BB0->getTerminator()->eraseFromParent(); |
| BranchInst::Create(BB1, BB3, ConstantInt::getTrue(F->getContext()), BB0); |
| EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 2u); |
| |
| // Remove bb2 from F. This has to happen before the call to applyUpdates() for |
| // DDT to detect there is no longer an edge between bb2 -> bb3. The deleteBB() |
| // method converts bb2's TI into "unreachable". |
| ASSERT_FALSE(isa<UnreachableInst>(BB2->getTerminator())); |
| EXPECT_FALSE(DDT.pendingDeletedBB(BB2)); |
| DDT.deleteBB(BB2); |
| EXPECT_TRUE(DDT.pendingDeletedBB(BB2)); |
| ASSERT_TRUE(isa<UnreachableInst>(BB2->getTerminator())); |
| EXPECT_EQ(BB2->getParent(), F); |
| |
| // Queue up the DDT updates. |
| std::vector<DominatorTree::UpdateType> Updates; |
| Updates.reserve(4); |
| Updates.push_back({DominatorTree::Delete, BB0, BB2}); |
| Updates.push_back({DominatorTree::Delete, BB2, BB3}); |
| |
| // Handle the specific shape case next. |
| // CFG Change: bb0 now only branches to bb3. We are preparing to remove bb1. |
| EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 2u); |
| BB0->getTerminator()->eraseFromParent(); |
| BranchInst::Create(BB3, BB0); |
| EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 1u); |
| |
| // Remove bb1 from F. This has to happen before the call to applyUpdates() for |
| // DDT to detect there is no longer an edge between bb1 -> bb3. The deleteBB() |
| // method converts bb1's TI into "unreachable". |
| ASSERT_FALSE(isa<UnreachableInst>(BB1->getTerminator())); |
| EXPECT_FALSE(DDT.pendingDeletedBB(BB1)); |
| DDT.deleteBB(BB1); |
| EXPECT_TRUE(DDT.pendingDeletedBB(BB1)); |
| ASSERT_TRUE(isa<UnreachableInst>(BB1->getTerminator())); |
| EXPECT_EQ(BB1->getParent(), F); |
| |
| // Update the DDT. In this case we don't call DDT.insertEdge(BB0, BB3) because |
| // the edge previously existed at the start of this test when DT was first |
| // created. |
| Updates.push_back({DominatorTree::Delete, BB0, BB1}); |
| Updates.push_back({DominatorTree::Delete, BB1, BB3}); |
| |
| // Verify everything. |
| DDT.applyUpdates(Updates); |
| ASSERT_TRUE(DDT.flush().verify()); |
| } |