1; This test checks that nested loops are revisited in various scenarios when
2; unrolling. Note that if we ever start doing outer loop peeling a test case
3; for that should be added here that will look essentially like a hybrid of the
4; current two cases.
5;
6; RUN: opt < %s -disable-output -debug-pass-manager 2>&1 \
7; RUN:     -passes='require<opt-remark-emit>,loop(unroll-full)' \
8; RUN:     | FileCheck %s
9;
10; Also run in a special mode that visits children.
11; RUN: opt < %s -disable-output -debug-pass-manager -unroll-revisit-child-loops 2>&1 \
12; RUN:     -passes='require<opt-remark-emit>,loop(unroll-full)' \
13; RUN:     | FileCheck %s --check-prefixes=CHECK,CHECK-CHILDREN
14
15; Basic test is fully unrolled and we revisit the post-unroll new sibling
16; loops, including the ones that used to be child loops.
17define void @full_unroll(i1* %ptr) {
18; CHECK-LABEL: FunctionToLoopPassAdaptor{{.*}} on full_unroll
19; CHECK-NOT: LoopFullUnrollPass
20
21entry:
22  br label %l0
23
24l0:
25  %cond.0 = load volatile i1, i1* %ptr
26  br i1 %cond.0, label %l0.0.ph, label %exit
27
28l0.0.ph:
29  br label %l0.0
30
31l0.0:
32  %iv = phi i32 [ %iv.next, %l0.0.latch ], [ 0, %l0.0.ph ]
33  %iv.next = add i32 %iv, 1
34  br label %l0.0.0.ph
35
36l0.0.0.ph:
37  br label %l0.0.0
38
39l0.0.0:
40  %cond.0.0.0 = load volatile i1, i1* %ptr
41  br i1 %cond.0.0.0, label %l0.0.0, label %l0.0.1.ph
42; CHECK: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.0<header>
43; CHECK-NOT: LoopFullUnrollPass
44
45l0.0.1.ph:
46  br label %l0.0.1
47
48l0.0.1:
49  %cond.0.0.1 = load volatile i1, i1* %ptr
50  br i1 %cond.0.0.1, label %l0.0.1, label %l0.0.latch
51; CHECK: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.1<header>
52; CHECK-NOT: LoopFullUnrollPass
53
54l0.0.latch:
55  %cmp = icmp slt i32 %iv.next, 2
56  br i1 %cmp, label %l0.0, label %l0.latch
57; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0
58; CHECK-NOT: LoopFullUnrollPass
59;
60; Unrolling occurs, so we visit what were the inner loops twice over. First we
61; visit their clones, and then we visit the original loops re-parented.
62; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0.1.1<header>
63; CHECK-NOT: LoopFullUnrollPass
64; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0.0.1<header>
65; CHECK-NOT: LoopFullUnrollPass
66; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0.1<header>
67; CHECK-NOT: LoopFullUnrollPass
68; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0.0<header>
69; CHECK-NOT: LoopFullUnrollPass
70
71l0.latch:
72  br label %l0
73; CHECK: LoopFullUnrollPass on Loop at depth 1 containing: %l0<header>
74; CHECK-NOT: LoopFullUnrollPass
75
76exit:
77  ret void
78}
79
80; Now we test forced runtime partial unrolling with metadata. Here we end up
81; duplicating child loops without changing their structure and so they aren't by
82; default visited, but will be visited with a special parameter.
83define void @partial_unroll(i32 %count, i1* %ptr) {
84; CHECK-LABEL: FunctionToLoopPassAdaptor{{.*}} on partial_unroll
85; CHECK-NOT: LoopFullUnrollPass
86
87entry:
88  br label %l0
89
90l0:
91  %cond.0 = load volatile i1, i1* %ptr
92  br i1 %cond.0, label %l0.0.ph, label %exit
93
94l0.0.ph:
95  br label %l0.0
96
97l0.0:
98  %iv = phi i32 [ %iv.next, %l0.0.latch ], [ 0, %l0.0.ph ]
99  %iv.next = add i32 %iv, 1
100  br label %l0.0.0.ph
101
102l0.0.0.ph:
103  br label %l0.0.0
104
105l0.0.0:
106  %cond.0.0.0 = load volatile i1, i1* %ptr
107  br i1 %cond.0.0.0, label %l0.0.0, label %l0.0.1.ph
108; CHECK: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.0<header>
109; CHECK-NOT: LoopFullUnrollPass
110
111l0.0.1.ph:
112  br label %l0.0.1
113
114l0.0.1:
115  %cond.0.0.1 = load volatile i1, i1* %ptr
116  br i1 %cond.0.0.1, label %l0.0.1, label %l0.0.latch
117; CHECK: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.1<header>
118; CHECK-NOT: LoopFullUnrollPass
119
120l0.0.latch:
121  %cmp = icmp slt i32 %iv.next, %count
122  br i1 %cmp, label %l0.0, label %l0.latch, !llvm.loop !1
123; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0
124; CHECK-NOT: LoopFullUnrollPass
125;
126; Partial unrolling occurs which introduces both new child loops and new sibling
127; loops. We only visit the child loops in a special mode, not by default.
128; CHECK-CHILDREN: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.0<header>
129; CHECK-CHILDREN-NOT: LoopFullUnrollPass
130; CHECK-CHILDREN: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.1<header>
131; CHECK-CHILDREN-NOT: LoopFullUnrollPass
132; CHECK-CHILDREN: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.0.1<header>
133; CHECK-CHILDREN-NOT: LoopFullUnrollPass
134; CHECK-CHILDREN: LoopFullUnrollPass on Loop at depth 3 containing: %l0.0.1.1<header>
135; CHECK-CHILDREN-NOT: LoopFullUnrollPass
136;
137; When we revisit children, we also revisit the current loop.
138; CHECK-CHILDREN: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0<header>
139; CHECK-CHILDREN-NOT: LoopFullUnrollPass
140;
141; Revisit the children of the outer loop that are part of the epilogue.
142;
143; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0.0.epil<header>
144; CHECK-NOT: LoopFullUnrollPass
145; CHECK: LoopFullUnrollPass on Loop at depth 2 containing: %l0.0.1.epil<header>
146; CHECK-NOT: LoopFullUnrollPass
147l0.latch:
148  br label %l0
149; CHECK: LoopFullUnrollPass on Loop at depth 1 containing: %l0<header>
150; CHECK-NOT: LoopFullUnrollPass
151
152exit:
153  ret void
154}
155!1 = !{!1, !2}
156!2 = !{!"llvm.loop.unroll.count", i32 2}
157