llvm-project/llvm/test/Transforms/LoopSimplify/basictest.ll

237 lines
6.3 KiB
LLVM
Raw Normal View History

; RUN: opt < %s -S -loop-simplify | FileCheck %s
; RUN: opt < %s -S -passes=loop-simplify | FileCheck %s
; This function should get a preheader inserted before bb3, that is jumped
; to by bb1 & bb2
define void @test() {
; CHECK-LABEL: define void @test(
entry:
br i1 true, label %bb1, label %bb2
bb1:
br label %bb3
; CHECK: bb1:
; CHECK-NEXT: br label %[[PH:.*]]
bb2:
br label %bb3
; CHECK: bb2:
; CHECK-NEXT: br label %[[PH]]
bb3:
br label %bb3
; CHECK: [[PH]]:
; CHECK-NEXT: br label %bb3
;
; CHECK: bb3:
; CHECK-NEXT: br label %bb3
}
; Test a case where we have multiple exit blocks as successors of a single loop
; block that need to be made dedicated exit blocks. We also have multiple
; exiting edges to one of the exit blocks that all should be rewritten.
define void @test_multiple_exits_from_single_block(i8 %a, i8* %b.ptr) {
; CHECK-LABEL: define void @test_multiple_exits_from_single_block(
entry:
switch i8 %a, label %loop [
i8 0, label %exit.a
i8 1, label %exit.b
]
; CHECK: entry:
; CHECK-NEXT: switch i8 %a, label %[[PH:.*]] [
; CHECK-NEXT: i8 0, label %exit.a
; CHECK-NEXT: i8 1, label %exit.b
; CHECK-NEXT: ]
loop:
%b = load volatile i8, i8* %b.ptr
switch i8 %b, label %loop [
i8 0, label %exit.a
i8 1, label %exit.b
i8 2, label %loop
i8 3, label %exit.a
i8 4, label %loop
i8 5, label %exit.a
i8 6, label %loop
]
; CHECK: [[PH]]:
; CHECK-NEXT: br label %loop
;
; CHECK: loop:
; CHECK-NEXT: %[[B:.*]] = load volatile i8, i8* %b.ptr
; CHECK-NEXT: switch i8 %[[B]], label %[[BACKEDGE:.*]] [
; CHECK-NEXT: i8 0, label %[[LOOPEXIT_A:.*]]
; CHECK-NEXT: i8 1, label %[[LOOPEXIT_B:.*]]
; CHECK-NEXT: i8 2, label %[[BACKEDGE]]
; CHECK-NEXT: i8 3, label %[[LOOPEXIT_A]]
; CHECK-NEXT: i8 4, label %[[BACKEDGE]]
; CHECK-NEXT: i8 5, label %[[LOOPEXIT_A]]
; CHECK-NEXT: i8 6, label %[[BACKEDGE]]
; CHECK-NEXT: ]
;
; CHECK: [[BACKEDGE]]:
; CHECK-NEXT: br label %loop
exit.a:
ret void
; CHECK: [[LOOPEXIT_A]]:
; CHECK-NEXT: br label %exit.a
;
; CHECK: exit.a:
; CHECK-NEXT: ret void
exit.b:
ret void
; CHECK: [[LOOPEXIT_B]]:
; CHECK-NEXT: br label %exit.b
;
; CHECK: exit.b:
; CHECK-NEXT: ret void
2008-03-25 12:26:08 +08:00
}
; Check that we leave already dedicated exits alone when forming dedicated exit
; blocks.
define void @test_pre_existing_dedicated_exits(i1 %a, i1* %ptr) {
; CHECK-LABEL: define void @test_pre_existing_dedicated_exits(
entry:
br i1 %a, label %loop.ph, label %non_dedicated_exit
; CHECK: entry:
; CHECK-NEXT: br i1 %a, label %loop.ph, label %non_dedicated_exit
loop.ph:
br label %loop.header
; CHECK: loop.ph:
; CHECK-NEXT: br label %loop.header
loop.header:
%c1 = load volatile i1, i1* %ptr
br i1 %c1, label %loop.body1, label %dedicated_exit1
; CHECK: loop.header:
; CHECK-NEXT: %[[C1:.*]] = load volatile i1, i1* %ptr
; CHECK-NEXT: br i1 %[[C1]], label %loop.body1, label %dedicated_exit1
loop.body1:
%c2 = load volatile i1, i1* %ptr
br i1 %c2, label %loop.body2, label %non_dedicated_exit
; CHECK: loop.body1:
; CHECK-NEXT: %[[C2:.*]] = load volatile i1, i1* %ptr
; CHECK-NEXT: br i1 %[[C2]], label %loop.body2, label %[[LOOPEXIT:.*]]
loop.body2:
%c3 = load volatile i1, i1* %ptr
br i1 %c3, label %loop.backedge, label %dedicated_exit2
; CHECK: loop.body2:
; CHECK-NEXT: %[[C3:.*]] = load volatile i1, i1* %ptr
; CHECK-NEXT: br i1 %[[C3]], label %loop.backedge, label %dedicated_exit2
loop.backedge:
br label %loop.header
; CHECK: loop.backedge:
; CHECK-NEXT: br label %loop.header
dedicated_exit1:
ret void
; Check that there isn't a split loop exit.
; CHECK-NOT: br label %dedicated_exit1
;
; CHECK: dedicated_exit1:
; CHECK-NEXT: ret void
dedicated_exit2:
ret void
; Check that there isn't a split loop exit.
; CHECK-NOT: br label %dedicated_exit2
;
; CHECK: dedicated_exit2:
; CHECK-NEXT: ret void
non_dedicated_exit:
ret void
; CHECK: [[LOOPEXIT]]:
; CHECK-NEXT: br label %non_dedicated_exit
;
; CHECK: non_dedicated_exit:
; CHECK-NEXT: ret void
}
[LoopSimplify] Re-instate r306081 with a bug fix w.r.t. indirectbr. This was reverted in r306252, but I already had the bug fixed and was just trying to form a test case. The original commit factored the logic for forming dedicated exits inside of LoopSimplify into a helper that could be used elsewhere and with an approach that required fewer intermediate data structures. See that commit for full details including the change to the statistic, etc. The code looked fine to me and my reviewers, but in fact didn't handle indirectbr correctly -- it left the 'InLoopPredecessors' vector dirty. If you have code that looks *just* right, you can end up leaking these predecessors into a subsequent rewrite, and crash deep down when trying to update PHI nodes for predecessors that don't exist. I've added an assert that makes the bug much more obvious, and then changed the code to reliably clear the vector so we don't get this bug again in some other form as the code changes. I've also added a test case that *does* manage to catch this while also giving some nice positive coverage in the face of indirectbr. The real code that found this came out of what I think is CPython's interpreter loop, but any code with really "creative" interpreter loops mixing indirectbr and other exit paths could manage to tickle the bug. I was hard to reduce the original test case because in addition to having a particular pattern of IR, the whole thing depends on the order of the predecessors which is in turn depends on use list order. The test case added here was designed so that in multiple different predecessor orderings it should always end up going down the same path and tripping the same bug. I hope. At least, it tripped it for me without manipulating the use list order which is better than anything bugpoint could do... llvm-svn: 306257
2017-06-26 06:45:31 +08:00
; Check that we form what dedicated exits we can even when some exits are
; reached via indirectbr which precludes forming dedicated exits.
define void @test_form_some_dedicated_exits_despite_indirectbr(i8 %a, i8* %ptr, i8** %addr.ptr) {
; CHECK-LABEL: define void @test_form_some_dedicated_exits_despite_indirectbr(
entry:
switch i8 %a, label %loop.ph [
i8 0, label %exit.a
i8 1, label %exit.b
i8 2, label %exit.c
]
; CHECK: entry:
; CHECK-NEXT: switch i8 %a, label %loop.ph [
; CHECK-NEXT: i8 0, label %exit.a
; CHECK-NEXT: i8 1, label %exit.b
; CHECK-NEXT: i8 2, label %exit.c
; CHECK-NEXT: ]
loop.ph:
br label %loop.header
; CHECK: loop.ph:
; CHECK-NEXT: br label %loop.header
loop.header:
%addr1 = load volatile i8*, i8** %addr.ptr
indirectbr i8* %addr1, [label %loop.body1, label %exit.a]
; CHECK: loop.header:
; CHECK-NEXT: %[[ADDR1:.*]] = load volatile i8*, i8** %addr.ptr
; CHECK-NEXT: indirectbr i8* %[[ADDR1]], [label %loop.body1, label %exit.a]
loop.body1:
%b = load volatile i8, i8* %ptr
switch i8 %b, label %loop.body2 [
i8 0, label %exit.a
i8 1, label %exit.b
i8 2, label %exit.c
]
; CHECK: loop.body1:
; CHECK-NEXT: %[[B:.*]] = load volatile i8, i8* %ptr
; CHECK-NEXT: switch i8 %[[B]], label %loop.body2 [
; CHECK-NEXT: i8 0, label %exit.a
; CHECK-NEXT: i8 1, label %[[LOOPEXIT:.*]]
; CHECK-NEXT: i8 2, label %exit.c
; CHECK-NEXT: ]
loop.body2:
%addr2 = load volatile i8*, i8** %addr.ptr
indirectbr i8* %addr2, [label %loop.backedge, label %exit.c]
; CHECK: loop.body2:
; CHECK-NEXT: %[[ADDR2:.*]] = load volatile i8*, i8** %addr.ptr
; CHECK-NEXT: indirectbr i8* %[[ADDR2]], [label %loop.backedge, label %exit.c]
loop.backedge:
br label %loop.header
; CHECK: loop.backedge:
; CHECK-NEXT: br label %loop.header
exit.a:
ret void
; Check that there isn't a split loop exit.
; CHECK-NOT: br label %exit.a
;
; CHECK: exit.a:
; CHECK-NEXT: ret void
exit.b:
ret void
; CHECK: [[LOOPEXIT]]:
; CHECK-NEXT: br label %exit.b
;
; CHECK: exit.b:
; CHECK-NEXT: ret void
exit.c:
ret void
; Check that there isn't a split loop exit.
; CHECK-NOT: br label %exit.c
;
; CHECK: exit.c:
; CHECK-NEXT: ret void
}