llvm.org GIT mirror llvm / 243b4a4
[LoopUnroll+LoopUnswitch] do not transform loops containing callbr Summary: There is currently a correctness issue when unrolling loops containing callbr's where their indirect targets are being updated correctly to the newly created labels, but their operands are not. This manifests in unrolled loops where the second and subsequent copies of callbr instructions have blockaddresses of the label from the first instance of the unrolled loop, which would result in nonsensical runtime control flow. For now, conservatively do not unroll the loop. In the future, I think we can pursue unrolling such loops provided we transform the cloned callbr's operands correctly. Such a transform and its legalities are being discussed in: https://reviews.llvm.org/D64101 Link: https://bugs.llvm.org/show_bug.cgi?id=42489 Link: https://groups.google.com/forum/#!topic/clang-built-linux/z-hRWP9KqPI Reviewers: fhahn, hfinkel, efriedma Reviewed By: fhahn, hfinkel, efriedma Subscribers: efriedma, hiraditya, zzheng, dmgreen, llvm-commits, pirama, kees, nathanchance, E5ten, craig.topper, chandlerc, glider, void, srhines Tags: #llvm Differential Revision: https://reviews.llvm.org/D64368 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@366130 91177308-0d34-0410-b5e6-96231b3b80d8 Nick Desaulniers a month ago
3 changed file(s) with 121 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
431431 bool Loop::isSafeToClone() const {
432432 // Return false if any loop blocks contain indirectbrs, or there are any calls
433433 // to noduplicate functions.
434 // FIXME: it should be ok to clone CallBrInst's if we correctly update the
435 // operand list to reflect the newly cloned labels.
434436 for (BasicBlock *BB : this->blocks()) {
435 if (isa(BB->getTerminator()))
437 if (isa(BB->getTerminator()) ||
438 isa(BB->getTerminator()))
436439 return false;
437440
438441 for (Instruction &I : *BB)
0 ; RUN: opt -loop-unroll -S %s | FileCheck %s
1
2 ; Check that the loop body exists.
3 ; CHECK: for.body
4 ; CHECK: if.then
5 ; CHECK: asm.fallthrough
6 ; CHECK: l_yes
7 ; CHECK: for.inc
8
9 ; Check that the loop body does not get unrolled. We could modify this test in
10 ; the future to support loop unrolling callbr's IFF we checked that the callbr
11 ; operands were unrolled/updated correctly, as today they are not.
12 ; CHECK-NOT: if.then.1
13 ; CHECK-NOT: asm.fallthrough.1
14 ; CHECK-NOT: l_yes.1
15 ; CHECK-NOT: for.inc.1
16 ; CHECK-NOT: if.then.2
17 ; CHECK-NOT: asm.fallthrough.2
18 ; CHECK-NOT: l_yes.2
19 ; CHECK-NOT: for.inc.2
20
21 define dso_local void @d() {
22 entry:
23 br label %for.body
24
25 for.cond.cleanup: ; preds = %for.inc
26 ret void
27
28 for.body: ; preds = %for.inc, %entry
29 %e.04 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
30 %tobool = icmp eq i32 %e.04, 0
31 br i1 %tobool, label %for.inc, label %if.then
32
33 if.then: ; preds = %for.body
34 callbr void asm sideeffect "1: nop\0A\09.quad b, ${0:l}, $$5\0A\09", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@d, %l_yes))
35 to label %asm.fallthrough [label %l_yes]
36
37 asm.fallthrough: ; preds = %if.then
38 br label %l_yes
39
40 l_yes: ; preds = %asm.fallthrough, %if.then
41 %call = tail call i32 (...) @g()
42 br label %for.inc
43
44 for.inc: ; preds = %for.body, %l_yes
45 %inc = add nuw nsw i32 %e.04, 1
46 %exitcond = icmp eq i32 %inc, 3
47 br i1 %exitcond, label %for.cond.cleanup, label %for.body
48 }
49
50 declare dso_local i32 @g(...) local_unnamed_addr
0 ; RUN: opt -loop-unswitch %s -S | FileCheck %s
1
2 ; We want to check that the loop does not get split (so only 2 callbr's not 4).
3 ; It's ok to modify this test in the future should we allow the loop containing
4 ; callbr to be unswitched and are able to do so correctly.
5
6 ; CHECK: callbr void asm sideeffect "# ${0:l}", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@foo, %10))
7 ; CHECK: to label %7 [label %10]
8 ; CHECK: callbr void asm sideeffect "# ${0:l}", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@foo, %10))
9 ; CHECK: to label %9 [label %10]
10
11 ; CHECK-NOT: callbr void asm sideeffect "# ${0:l}", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@foo, %10))
12 ; CHECK-NOT: to label %7 [label %10]
13 ; CHECK-NOT: callbr void asm sideeffect "# ${0:l}", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@foo, %10))
14 ; CHECK-NOT: to label %9 [label %10]
15 ; CHECK-NOT: callbr void asm sideeffect "# ${0:l}", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@foo, %19))
16 ; CHECK-NOT: to label %16 [label %19]
17 ; CHECK-NOT: callbr void asm sideeffect "# ${0:l}", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@foo, %19))
18 ; CHECK-NOT: to label %18 [label %19]
19
20 ; This test is essentially:
21 ; void foo(int n) {
22 ; for (int i = 0; i < 1000; ++i)
23 ; if (n) {
24 ; asm goto("# %l0"::::bar);
25 ; bar:;
26 ; } else {
27 ; asm goto("# %l0"::::baz);
28 ; baz:;
29 ; }
30 ;}
31
32 define dso_local void @foo(i32) #0 {
33 br label %2
34
35 2: ; preds = %10, %1
36 %.0 = phi i32 [ 0, %1 ], [ %11, %10 ]
37 %3 = icmp ult i32 %.0, 1000
38 br i1 %3, label %4, label %12
39
40 4: ; preds = %2
41 %5 = icmp eq i32 %0, 0
42 br i1 %5, label %8, label %6
43
44 6: ; preds = %4
45 callbr void asm sideeffect "# ${0:l}", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@foo, %10)) #0
46 to label %7 [label %10]
47
48 7: ; preds = %6
49 br label %10
50
51 8: ; preds = %4
52 callbr void asm sideeffect "# ${0:l}", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@foo, %10)) #0
53 to label %9 [label %10]
54
55 9: ; preds = %8
56 br label %10
57
58 10: ; preds = %7, %6, %9, %8
59 %11 = add nuw nsw i32 %.0, 1
60 br label %2
61
62 12: ; preds = %2
63 ret void
64 }
65