summaryrefslogtreecommitdiff
path: root/unittests/Transforms
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/Transforms')
-rw-r--r--unittests/Transforms/Scalar/LoopPassManagerTest.cpp59
-rw-r--r--unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp29
-rw-r--r--unittests/Transforms/Utils/CMakeLists.txt2
-rw-r--r--unittests/Transforms/Utils/Cloning.cpp3
-rw-r--r--unittests/Transforms/Utils/CodeExtractor.cpp69
-rw-r--r--unittests/Transforms/Utils/Local.cpp117
6 files changed, 244 insertions, 35 deletions
diff --git a/unittests/Transforms/Scalar/LoopPassManagerTest.cpp b/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
index 0e5780ebec47..2b8130b9e009 100644
--- a/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
+++ b/unittests/Transforms/Scalar/LoopPassManagerTest.cpp
@@ -21,8 +21,8 @@
#include "llvm/IR/PassManager.h"
#include "llvm/Support/SourceMgr.h"
-// Workaround for the gcc 7.1 bug PR80916.
-#if defined(__GNUC__) && __GNUC__ > 6
+// Workaround for the gcc 6.1 bug PR80916.
+#if defined(__GNUC__) && __GNUC__ > 5
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-function"
#endif
@@ -30,7 +30,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
-#if defined(__GNUC__) && __GNUC__ > 6
+#if defined(__GNUC__) && __GNUC__ > 5
# pragma GCC diagnostic pop
#endif
@@ -946,7 +946,7 @@ TEST_F(LoopPassManagerTest, LoopChildInsertion) {
.WillOnce(Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &Updater) {
- auto *NewLoop = new Loop();
+ auto *NewLoop = AR.LI.AllocateLoop();
L.addChildLoop(NewLoop);
auto *NewLoop010PHBB =
BasicBlock::Create(Context, "loop.0.1.0.ph", &F, &Loop02PHBB);
@@ -992,7 +992,7 @@ TEST_F(LoopPassManagerTest, LoopChildInsertion) {
.WillOnce(Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &Updater) {
- auto *NewLoop = new Loop();
+ auto *NewLoop = AR.LI.AllocateLoop();
L.addChildLoop(NewLoop);
auto *NewLoop011PHBB = BasicBlock::Create(Context, "loop.0.1.1.ph", &F, NewLoop01LatchBB);
auto *NewLoop011BB = BasicBlock::Create(Context, "loop.0.1.1", &F, NewLoop01LatchBB);
@@ -1139,7 +1139,7 @@ TEST_F(LoopPassManagerTest, LoopPeerInsertion) {
.WillOnce(Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &Updater) {
- auto *NewLoop = new Loop();
+ auto *NewLoop = AR.LI.AllocateLoop();
L.getParentLoop()->addChildLoop(NewLoop);
auto *NewLoop01PHBB = BasicBlock::Create(Context, "loop.0.1.ph", &F, &Loop02PHBB);
auto *NewLoop01BB = BasicBlock::Create(Context, "loop.0.1", &F, &Loop02PHBB);
@@ -1181,7 +1181,8 @@ TEST_F(LoopPassManagerTest, LoopPeerInsertion) {
.WillOnce(Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &Updater) {
- Loop *NewLoops[] = {new Loop(), new Loop(), new Loop()};
+ Loop *NewLoops[] = {AR.LI.AllocateLoop(), AR.LI.AllocateLoop(),
+ AR.LI.AllocateLoop()};
L.getParentLoop()->addChildLoop(NewLoops[0]);
L.getParentLoop()->addChildLoop(NewLoops[1]);
NewLoops[1]->addChildLoop(NewLoops[2]);
@@ -1260,7 +1261,7 @@ TEST_F(LoopPassManagerTest, LoopPeerInsertion) {
.WillOnce(Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &Updater) {
- auto *NewLoop = new Loop();
+ auto *NewLoop = AR.LI.AllocateLoop();
AR.LI.addTopLevelLoop(NewLoop);
auto *NewLoop1PHBB = BasicBlock::Create(Context, "loop.1.ph", &F, &Loop2BB);
auto *NewLoop1BB = BasicBlock::Create(Context, "loop.1", &F, &Loop2BB);
@@ -1374,12 +1375,11 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
// to isolate ourselves from the rest of LLVM and for simplicity. Here we can
// egregiously cheat based on knowledge of the test case. For example, we
// have no PHI nodes and there is always a single i-dom.
- auto RemoveLoop = [](Loop &L, BasicBlock &IDomBB,
- LoopStandardAnalysisResults &AR,
- LPMUpdater &Updater) {
+ auto EraseLoop = [](Loop &L, BasicBlock &IDomBB,
+ LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
assert(L.empty() && "Can only delete leaf loops with this routine!");
SmallVector<BasicBlock *, 4> LoopBBs(L.block_begin(), L.block_end());
- Updater.markLoopAsDeleted(L);
+ Updater.markLoopAsDeleted(L, L.getName());
IDomBB.getTerminator()->replaceUsesOfWith(L.getHeader(),
L.getUniqueExitBlock());
for (BasicBlock *LoopBB : LoopBBs) {
@@ -1394,10 +1394,7 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
for (BasicBlock *LoopBB : LoopBBs)
LoopBB->eraseFromParent();
- if (Loop *ParentL = L.getParentLoop())
- return ParentL->removeChildLoop(find(*ParentL, &L));
-
- return AR.LI.removeLoop(find(AR.LI, &L));
+ AR.LI.erase(&L);
};
// Build up the pass managers.
@@ -1442,7 +1439,7 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
Loop *ParentL = L.getParentLoop();
AR.SE.forgetLoop(&L);
- delete RemoveLoop(L, Loop01PHBB, AR, Updater);
+ EraseLoop(L, Loop01PHBB, AR, Updater);
ParentL->verifyLoop();
return PreservedAnalyses::all();
}));
@@ -1469,10 +1466,8 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
.WillRepeatedly(Invoke(getLoopAnalysisResult));
// Run the loop pipeline again. This time we delete the last loop, which
- // contains a nested loop within it, and we reuse its inner loop object to
- // insert a new loop into the nest. This makes sure that we don't reuse
- // cached analysis results for loop objects when removed just because their
- // pointers match, and that we can handle nested loop deletion.
+ // contains a nested loop within it and insert a new loop into the nest. This
+ // makes sure we can handle nested loop deletion.
AddLoopPipelineAndVerificationPasses();
EXPECT_CALL(MLPHandle, run(HasName("loop.0.0"), _, _, _))
.Times(3)
@@ -1489,16 +1484,16 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
.WillOnce(
Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
- // Remove the inner loop first but retain it to reuse later.
AR.SE.forgetLoop(*L.begin());
- auto *OldL = RemoveLoop(**L.begin(), Loop020PHBB, AR, Updater);
+ EraseLoop(**L.begin(), Loop020PHBB, AR, Updater);
auto *ParentL = L.getParentLoop();
AR.SE.forgetLoop(&L);
- delete RemoveLoop(L, Loop02PHBB, AR, Updater);
+ EraseLoop(L, Loop02PHBB, AR, Updater);
- // Now insert a new sibling loop, reusing a loop pointer.
- ParentL->addChildLoop(OldL);
+ // Now insert a new sibling loop.
+ auto *NewSibling = AR.LI.AllocateLoop();
+ ParentL->addChildLoop(NewSibling);
NewLoop03PHBB =
BasicBlock::Create(Context, "loop.0.3.ph", &F, &Loop0LatchBB);
auto *NewLoop03BB =
@@ -1515,10 +1510,10 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
AR.DT[NewLoop03BB]);
AR.DT.verifyDomTree();
ParentL->addBasicBlockToLoop(NewLoop03PHBB, AR.LI);
- OldL->addBasicBlockToLoop(NewLoop03BB, AR.LI);
- OldL->verifyLoop();
+ NewSibling->addBasicBlockToLoop(NewLoop03BB, AR.LI);
+ NewSibling->verifyLoop();
ParentL->verifyLoop();
- Updater.addSiblingLoops({OldL});
+ Updater.addSiblingLoops({NewSibling});
return PreservedAnalyses::all();
}));
@@ -1550,7 +1545,7 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
AR.SE.forgetLoop(&L);
- delete RemoveLoop(L, Loop00PHBB, AR, Updater);
+ EraseLoop(L, Loop00PHBB, AR, Updater);
return PreservedAnalyses::all();
}));
@@ -1561,7 +1556,7 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
AR.SE.forgetLoop(&L);
- delete RemoveLoop(L, *NewLoop03PHBB, AR, Updater);
+ EraseLoop(L, *NewLoop03PHBB, AR, Updater);
return PreservedAnalyses::all();
}));
@@ -1572,7 +1567,7 @@ TEST_F(LoopPassManagerTest, LoopDeletion) {
Invoke([&](Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR, LPMUpdater &Updater) {
AR.SE.forgetLoop(&L);
- delete RemoveLoop(L, EntryBB, AR, Updater);
+ EraseLoop(L, EntryBB, AR, Updater);
return PreservedAnalyses::all();
}));
diff --git a/unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp b/unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp
index 2337ec04776a..777918e5cfdd 100644
--- a/unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp
+++ b/unittests/Transforms/Utils/ASanStackFrameLayoutTest.cpp
@@ -68,9 +68,12 @@ TEST(ASanStackFrameLayout, Test) {
VAR(a, 16, 16, 1, 0);
VAR(a, 41, 9, 1, 7);
VAR(a, 105, 103, 1, 0);
+ VAR(a, 200, 97, 1, 0);
TEST_LAYOUT({a1_1}, 8, 16, "1 16 1 4 a1_1", "LL1R", "LL1R");
- TEST_LAYOUT({a1_1}, 64, 64, "1 64 1 4 a1_1", "L1", "L1");
+ TEST_LAYOUT({a1_1}, 16, 16, "1 16 1 4 a1_1", "L1R", "L1R");
+ TEST_LAYOUT({a1_1}, 32, 32, "1 32 1 4 a1_1", "L1R", "L1R");
+ TEST_LAYOUT({a1_1}, 64, 64, "1 64 1 4 a1_1", "L1R", "L1R");
TEST_LAYOUT({p1_32}, 8, 32, "1 32 1 8 p1_32:15", "LLLL1RRR", "LLLL1RRR");
TEST_LAYOUT({p1_32}, 8, 64, "1 64 1 8 p1_32:15", "LLLLLLLL1RRRRRRR",
"LLLLLLLL1RRRRRRR");
@@ -103,6 +106,30 @@ TEST(ASanStackFrameLayout, Test) {
TEST_LAYOUT(t, 8, 32, "3 32 1 4 a1_1 48 16 5 a16_1 80 41 7 a41_1:7",
"LLLL1M00MM000001RRRR", "LLLL1MSSMMSS0001RRRR");
}
+
+ TEST_LAYOUT({a2_1}, 32, 32, "1 32 2 4 a2_1", "L2R", "L2R");
+ TEST_LAYOUT({a9_1}, 32, 32, "1 32 9 4 a9_1", "L9R", "L9R");
+ TEST_LAYOUT({a16_1}, 32, 32, "1 32 16 5 a16_1", "L16R", "LSR");
+ TEST_LAYOUT({p1_256}, 32, 32, "1 256 1 11 p1_256:2700",
+ "LLLLLLLL1R", "LLLLLLLL1R");
+ TEST_LAYOUT({a41_1}, 32, 32, "1 32 41 7 a41_1:7", "L09R",
+ "LS9R");
+ TEST_LAYOUT({a105_1}, 32, 32, "1 32 105 6 a105_1", "L0009R",
+ "LSSSSR");
+ TEST_LAYOUT({a200_1}, 32, 32, "1 32 200 6 a200_1", "L0000008RR",
+ "LSSSS008RR");
+
+ {
+ SmallVector<ASanStackVariableDescription, 10> t = {a1_1, p1_256};
+ TEST_LAYOUT(t, 32, 32, "2 256 1 11 p1_256:2700 320 1 4 a1_1",
+ "LLLLLLLL1M1R", "LLLLLLLL1M1R");
+ }
+
+ {
+ SmallVector<ASanStackVariableDescription, 10> t = {a1_1, a16_1, a41_1};
+ TEST_LAYOUT(t, 32, 32, "3 32 1 4 a1_1 96 16 5 a16_1 160 41 7 a41_1:7",
+ "L1M16M09R", "L1MSMS9R");
+ }
#undef VAR
#undef TEST_LAYOUT
}
diff --git a/unittests/Transforms/Utils/CMakeLists.txt b/unittests/Transforms/Utils/CMakeLists.txt
index 475c365dddc4..e2bb0af0f773 100644
--- a/unittests/Transforms/Utils/CMakeLists.txt
+++ b/unittests/Transforms/Utils/CMakeLists.txt
@@ -1,5 +1,6 @@
set(LLVM_LINK_COMPONENTS
Analysis
+ AsmParser
Core
Support
TransformUtils
@@ -8,6 +9,7 @@ set(LLVM_LINK_COMPONENTS
add_llvm_unittest(UtilsTests
ASanStackFrameLayoutTest.cpp
Cloning.cpp
+ CodeExtractor.cpp
FunctionComparator.cpp
IntegerDivision.cpp
Local.cpp
diff --git a/unittests/Transforms/Utils/Cloning.cpp b/unittests/Transforms/Utils/Cloning.cpp
index beb50455f012..fe4e2ba7e943 100644
--- a/unittests/Transforms/Utils/Cloning.cpp
+++ b/unittests/Transforms/Utils/Cloning.cpp
@@ -309,8 +309,7 @@ protected:
DBuilder.createAutoVariable(Subprogram, "x", File, 5, IntType, true);
auto *DL = DILocation::get(Subprogram->getContext(), 5, 0, Subprogram);
DBuilder.insertDeclare(Alloca, Variable, E, DL, Store);
- DBuilder.insertDbgValueIntrinsic(AllocaContent, 0, Variable, E, DL,
- Entry);
+ DBuilder.insertDbgValueIntrinsic(AllocaContent, Variable, E, DL, Entry);
// Also create an inlined variable.
// Create a distinct struct type that we should not duplicate during
// cloning).
diff --git a/unittests/Transforms/Utils/CodeExtractor.cpp b/unittests/Transforms/Utils/CodeExtractor.cpp
new file mode 100644
index 000000000000..c229be6d6952
--- /dev/null
+++ b/unittests/Transforms/Utils/CodeExtractor.cpp
@@ -0,0 +1,69 @@
+//===- CodeExtractor.cpp - Unit tests for CodeExtractor -------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Utils/CodeExtractor.h"
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Dominators.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Support/SourceMgr.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+TEST(CodeExtractor, ExitStub) {
+ LLVMContext Ctx;
+ SMDiagnostic Err;
+ std::unique_ptr<Module> M(parseAssemblyString(R"invalid(
+ define i32 @foo(i32 %x, i32 %y, i32 %z) {
+ header:
+ %0 = icmp ugt i32 %x, %y
+ br i1 %0, label %body1, label %body2
+
+ body1:
+ %1 = add i32 %z, 2
+ br label %notExtracted
+
+ body2:
+ %2 = mul i32 %z, 7
+ br label %notExtracted
+
+ notExtracted:
+ %3 = phi i32 [ %1, %body1 ], [ %2, %body2 ]
+ %4 = add i32 %3, %x
+ ret i32 %4
+ }
+ )invalid",
+ Err, Ctx));
+
+ Function *Func = M->getFunction("foo");
+ SmallVector<BasicBlock *, 3> Candidates;
+ for (auto &BB : *Func) {
+ if (BB.getName() == "body1")
+ Candidates.push_back(&BB);
+ if (BB.getName() == "body2")
+ Candidates.push_back(&BB);
+ }
+ // CodeExtractor requires the first basic block
+ // to dominate all the other ones.
+ Candidates.insert(Candidates.begin(), &Func->getEntryBlock());
+
+ DominatorTree DT(*Func);
+ CodeExtractor CE(Candidates, &DT);
+ EXPECT_TRUE(CE.isEligible());
+
+ Function *Outlined = CE.extractCodeRegion();
+ EXPECT_TRUE(Outlined);
+ EXPECT_FALSE(verifyFunction(*Outlined));
+}
+} // end anonymous namespace
diff --git a/unittests/Transforms/Utils/Local.cpp b/unittests/Transforms/Utils/Local.cpp
index 5164bdbb2a4e..4789b0558d77 100644
--- a/unittests/Transforms/Utils/Local.cpp
+++ b/unittests/Transforms/Utils/Local.cpp
@@ -8,10 +8,14 @@
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Utils/Local.h"
+#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
+#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"
using namespace llvm;
@@ -95,3 +99,116 @@ TEST(Local, RemoveDuplicatePHINodes) {
EXPECT_TRUE(EliminateDuplicatePHINodes(BB));
EXPECT_EQ(3U, BB->size());
}
+
+std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
+ SMDiagnostic Err;
+ std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
+ if (!Mod)
+ Err.print("UtilsTests", errs());
+ return Mod;
+}
+
+TEST(Local, ReplaceDbgDeclare) {
+ LLVMContext C;
+
+ // Original C source to get debug info for a local variable:
+ // void f() { int x; }
+ std::unique_ptr<Module> M = parseIR(
+ C,
+ "define void @f() !dbg !8 {\n"
+ "entry:\n"
+ " %x = alloca i32, align 4\n"
+ " call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata "
+ "!DIExpression()), !dbg !13\n"
+ " call void @llvm.dbg.declare(metadata i32* %x, metadata !11, metadata "
+ "!DIExpression()), !dbg !13\n"
+ " ret void, !dbg !14\n"
+ "}\n"
+ "declare void @llvm.dbg.declare(metadata, metadata, metadata)\n"
+ "!llvm.dbg.cu = !{!0}\n"
+ "!llvm.module.flags = !{!3, !4}\n"
+ "!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "
+ "\"clang version 6.0.0 \", isOptimized: false, runtimeVersion: 0, "
+ "emissionKind: FullDebug, enums: !2)\n"
+ "!1 = !DIFile(filename: \"t2.c\", directory: \"foo\")\n"
+ "!2 = !{}\n"
+ "!3 = !{i32 2, !\"Dwarf Version\", i32 4}\n"
+ "!4 = !{i32 2, !\"Debug Info Version\", i32 3}\n"
+ "!8 = distinct !DISubprogram(name: \"f\", scope: !1, file: !1, line: 1, "
+ "type: !9, isLocal: false, isDefinition: true, scopeLine: 1, "
+ "isOptimized: false, unit: !0, variables: !2)\n"
+ "!9 = !DISubroutineType(types: !10)\n"
+ "!10 = !{null}\n"
+ "!11 = !DILocalVariable(name: \"x\", scope: !8, file: !1, line: 2, type: "
+ "!12)\n"
+ "!12 = !DIBasicType(name: \"int\", size: 32, encoding: DW_ATE_signed)\n"
+ "!13 = !DILocation(line: 2, column: 7, scope: !8)\n"
+ "!14 = !DILocation(line: 3, column: 1, scope: !8)\n");
+ auto *GV = M->getNamedValue("f");
+ ASSERT_TRUE(GV);
+ auto *F = dyn_cast<Function>(GV);
+ ASSERT_TRUE(F);
+ Instruction *Inst = &F->front().front();
+ auto *AI = dyn_cast<AllocaInst>(Inst);
+ ASSERT_TRUE(AI);
+ Inst = Inst->getNextNode()->getNextNode();
+ ASSERT_TRUE(Inst);
+ auto *DII = dyn_cast<DbgDeclareInst>(Inst);
+ ASSERT_TRUE(DII);
+ Value *NewBase = Constant::getNullValue(Type::getInt32PtrTy(C));
+ DIBuilder DIB(*M);
+ replaceDbgDeclare(AI, NewBase, DII, DIB, DIExpression::NoDeref, 0,
+ DIExpression::NoDeref);
+
+ // There should be exactly two dbg.declares.
+ int Declares = 0;
+ for (const Instruction &I : F->front())
+ if (isa<DbgDeclareInst>(I))
+ Declares++;
+ EXPECT_EQ(2, Declares);
+}
+
+/// Build the dominator tree for the function and run the Test.
+static void runWithDomTree(
+ Module &M, StringRef FuncName,
+ function_ref<void(Function &F, DominatorTree *DT)> Test) {
+ auto *F = M.getFunction(FuncName);
+ ASSERT_NE(F, nullptr) << "Could not find " << FuncName;
+ // Compute the dominator tree for the function.
+ DominatorTree DT(*F);
+ Test(*F, &DT);
+}
+
+TEST(Local, MergeBasicBlockIntoOnlyPred) {
+ LLVMContext C;
+
+ std::unique_ptr<Module> M = parseIR(
+ C,
+ "define i32 @f(i8* %str) {\n"
+ "entry:\n"
+ " br label %bb2.i\n"
+ "bb2.i: ; preds = %bb4.i, %entry\n"
+ " br i1 false, label %bb4.i, label %base2flt.exit204\n"
+ "bb4.i: ; preds = %bb2.i\n"
+ " br i1 false, label %base2flt.exit204, label %bb2.i\n"
+ "bb10.i196.bb7.i197_crit_edge: ; No predecessors!\n"
+ " br label %bb7.i197\n"
+ "bb7.i197: ; preds = %bb10.i196.bb7.i197_crit_edge\n"
+ " %.reg2mem.0 = phi i32 [ %.reg2mem.0, %bb10.i196.bb7.i197_crit_edge ]\n"
+ " br i1 undef, label %base2flt.exit204, label %base2flt.exit204\n"
+ "base2flt.exit204: ; preds = %bb7.i197, %bb7.i197, %bb2.i, %bb4.i\n"
+ " ret i32 0\n"
+ "}\n");
+ runWithDomTree(
+ *M, "f", [&](Function &F, DominatorTree *DT) {
+ for (Function::iterator I = F.begin(), E = F.end(); I != E;) {
+ BasicBlock *BB = &*I++;
+ BasicBlock *SinglePred = BB->getSinglePredecessor();
+ if (!SinglePred || SinglePred == BB || BB->hasAddressTaken()) continue;
+ BranchInst *Term = dyn_cast<BranchInst>(SinglePred->getTerminator());
+ if (Term && !Term->isConditional())
+ MergeBasicBlockIntoOnlyPred(BB, DT);
+ }
+ EXPECT_TRUE(DT->verify());
+ });
+}