aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChandler Carruth <chandlerc@gmail.com>2018-04-24 10:33:08 +0000
committerChandler Carruth <chandlerc@gmail.com>2018-04-24 10:33:08 +0000
commitfef8b01d9b1a75def0ff6b5511f1e95e4437ba9e (patch)
tree928c33b3edf4eedf7e081d65bf691e580dde50cf
parentb6bee651995d906ef640f23a64018e06f7f49278 (diff)
[PM/LoopUnswitch] Fix a bug in the loop block set formation of the new
loop unswitch. This code incorrectly added the header to the loop block set early. As a consequence we would incorrectly conclude that a nested loop body had already been visited when the header of the outer loop was the preheader of the nested loop. In retrospect, adding the header eagerly doesn't really make sense. It seems nicer to let the cycle be formed naturally. This will catch crazy bugs in the CFG reconstruction where we can't correctly form the cycle earlier rather than later, and makes the rest of the logic just fall out. I've also added various asserts that make these issues *much* easier to debug. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@330707 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Transforms/Scalar/SimpleLoopUnswitch.cpp14
-rw-r--r--test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch.ll54
2 files changed, 64 insertions, 4 deletions
diff --git a/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
index c28311fe4b0..fed5e62157a 100644
--- a/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
+++ b/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp
@@ -1333,14 +1333,15 @@ static SmallPtrSet<const BasicBlock *, 16> recomputeLoopBlockSet(Loop &L,
if (LoopBlockSet.empty())
return LoopBlockSet;
- // Add the loop header to the set.
- LoopBlockSet.insert(Header);
-
// We found backedges, recurse through them to identify the loop blocks.
while (!Worklist.empty()) {
BasicBlock *BB = Worklist.pop_back_val();
assert(LoopBlockSet.count(BB) && "Didn't put block into the loop set!");
+ // No need to walk past the header.
+ if (BB == Header)
+ continue;
+
// Because we know the inner loop structure remains valid we can use the
// loop structure to jump immediately across the entire nested loop.
// Further, because it is in loop simplified form, we can directly jump
@@ -1388,6 +1389,8 @@ static SmallPtrSet<const BasicBlock *, 16> recomputeLoopBlockSet(Loop &L,
Worklist.push_back(Pred);
}
+ assert(LoopBlockSet.count(Header) && "Cannot fail to add the header!");
+
// We've found all the blocks participating in the loop, return our completed
// set.
return LoopBlockSet;
@@ -1792,9 +1795,12 @@ static bool unswitchInvariantBranch(
// unnecessary loops.
auto UpdateLCSSA = [&](Loop &UpdateL) {
#ifndef NDEBUG
- for (Loop *ChildL : UpdateL)
+ UpdateL.verifyLoop();
+ for (Loop *ChildL : UpdateL) {
+ ChildL->verifyLoop();
assert(ChildL->isRecursivelyLCSSAForm(DT, LI) &&
"Perturbed a child loop's LCSSA form!");
+ }
#endif
formLCSSA(UpdateL, DT, &LI, nullptr);
};
diff --git a/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch.ll b/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch.ll
index 48075172b10..51afdf386e5 100644
--- a/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch.ll
+++ b/test/Transforms/SimpleLoopUnswitch/nontrivial-unswitch.ll
@@ -2508,3 +2508,57 @@ loop1.exit:
call void @g()
ret void
}
+
+; Test that when we are unswitching and need to rebuild the loop block set we
+; correctly skip past inner loops. We want to use the inner loop to efficiently
+; skip whole subregions of the outer loop blocks but just because the header of
+; the outer loop is also the preheader of an inner loop shouldn't confuse this
+; walk.
+define void @test23(i1 %arg, i1* %ptr) {
+; CHECK-LABEL: define void @test23(
+entry:
+ br label %outer.header
+; CHECK: entry:
+; CHECK-NEXT: br i1 %arg,
+;
+; Just verify that we unswitched the correct bits. We should call `@f` twice in
+; one unswitch and `@f` and then `@g` in the other.
+; CHECK: call void
+; CHECK-SAME: @f
+; CHECK: call void
+; CHECK-SAME: @f
+;
+; CHECK: call void
+; CHECK-SAME: @f
+; CHECK: call void
+; CHECK-SAME: @g
+
+outer.header:
+ br label %inner.header
+
+inner.header:
+ call void @f()
+ br label %inner.latch
+
+inner.latch:
+ %inner.cond = load i1, i1* %ptr
+ br i1 %inner.cond, label %inner.header, label %outer.body
+
+outer.body:
+ br i1 %arg, label %outer.body.left, label %outer.body.right
+
+outer.body.left:
+ call void @f()
+ br label %outer.latch
+
+outer.body.right:
+ call void @g()
+ br label %outer.latch
+
+outer.latch:
+ %outer.cond = load i1, i1* %ptr
+ br i1 %outer.cond, label %outer.header, label %exit
+
+exit:
+ ret void
+}