1; RUN: opt -S -loop-predication < %s 2>&1 | FileCheck %s
2; RUN: opt -S -passes='require<scalar-evolution>,loop(loop-predication)' < %s 2>&1 | FileCheck %s
3
4declare void @llvm.experimental.guard(i1, ...)
5
6define i32 @signed_loop_0_to_n_nested_0_to_l_inner_index_check(i32* %array, i32 %length, i32 %n, i32 %l) {
7; CHECK-LABEL: @signed_loop_0_to_n_nested_0_to_l_inner_index_check
8entry:
9  %tmp5 = icmp sle i32 %n, 0
10  br i1 %tmp5, label %exit, label %outer.loop.preheader
11
12outer.loop.preheader:
13; CHECK: outer.loop.preheader:
14; CHECK: [[iteration_count:[^ ]+]] = add i32 %l, -1
15  br label %outer.loop
16
17outer.loop:
18  %outer.loop.acc = phi i32 [ %outer.loop.acc.next, %outer.loop.inc ], [ 0, %outer.loop.preheader ]
19  %i = phi i32 [ %i.next, %outer.loop.inc ], [ 0, %outer.loop.preheader ]
20  %tmp6 = icmp sle i32 %l, 0
21  br i1 %tmp6, label %outer.loop.inc, label %inner.loop.preheader
22
23inner.loop.preheader:
24; CHECK: inner.loop.preheader:
25; CHECK: [[wide_cond:[^ ]+]] = icmp slt i32 [[iteration_count]], %length
26  br label %inner.loop
27
28inner.loop:
29; CHECK: inner.loop:
30; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[wide_cond]], i32 9) [ "deopt"() ]
31  %inner.loop.acc = phi i32 [ %inner.loop.acc.next, %inner.loop ], [ %outer.loop.acc, %inner.loop.preheader ]
32  %j = phi i32 [ %j.next, %inner.loop ], [ 0, %inner.loop.preheader ]
33
34  %within.bounds = icmp slt i32 %j, %length
35  call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
36
37  %j.i64 = zext i32 %j to i64
38  %array.j.ptr = getelementptr inbounds i32, i32* %array, i64 %j.i64
39  %array.j = load i32, i32* %array.j.ptr, align 4
40  %inner.loop.acc.next = add i32 %inner.loop.acc, %array.j
41
42  %j.next = add nsw i32 %j, 1
43  %inner.continue = icmp slt i32 %j.next, %l
44  br i1 %inner.continue, label %inner.loop, label %outer.loop.inc
45
46outer.loop.inc:
47  %outer.loop.acc.next = phi i32 [ %inner.loop.acc.next, %inner.loop ], [ %outer.loop.acc, %outer.loop ]
48  %i.next = add nsw i32 %i, 1
49  %outer.continue = icmp slt i32 %i.next, %n
50  br i1 %outer.continue, label %outer.loop, label %exit
51
52exit:
53  %result = phi i32 [ 0, %entry ], [ %outer.loop.acc.next, %outer.loop.inc ]
54  ret i32 %result
55}
56
57define i32 @signed_loop_0_to_n_nested_0_to_l_outer_index_check(i32* %array, i32 %length, i32 %n, i32 %l) {
58; CHECK-LABEL: @signed_loop_0_to_n_nested_0_to_l_outer_index_check
59entry:
60  %tmp5 = icmp sle i32 %n, 0
61  br i1 %tmp5, label %exit, label %outer.loop.preheader
62
63outer.loop.preheader:
64; CHECK: outer.loop.preheader:
65; CHECK: [[iteration_count:[^ ]+]] = add i32 %n, -1
66; CHECK: [[wide_cond:[^ ]+]] = icmp slt i32 [[iteration_count]], %length
67  br label %outer.loop
68
69outer.loop:
70  %outer.loop.acc = phi i32 [ %outer.loop.acc.next, %outer.loop.inc ], [ 0, %outer.loop.preheader ]
71  %i = phi i32 [ %i.next, %outer.loop.inc ], [ 0, %outer.loop.preheader ]
72  %tmp6 = icmp sle i32 %l, 0
73  br i1 %tmp6, label %outer.loop.inc, label %inner.loop.preheader
74
75inner.loop.preheader:
76  br label %inner.loop
77
78inner.loop:
79; CHECK: inner.loop:
80; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[wide_cond]], i32 9) [ "deopt"() ]
81
82  %inner.loop.acc = phi i32 [ %inner.loop.acc.next, %inner.loop ], [ %outer.loop.acc, %inner.loop.preheader ]
83  %j = phi i32 [ %j.next, %inner.loop ], [ 0, %inner.loop.preheader ]
84
85  %within.bounds = icmp slt i32 %i, %length
86  call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
87
88  %i.i64 = zext i32 %i to i64
89  %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
90  %array.i = load i32, i32* %array.i.ptr, align 4
91  %inner.loop.acc.next = add i32 %inner.loop.acc, %array.i
92
93  %j.next = add nsw i32 %j, 1
94  %inner.continue = icmp slt i32 %j.next, %l
95  br i1 %inner.continue, label %inner.loop, label %outer.loop.inc
96
97outer.loop.inc:
98  %outer.loop.acc.next = phi i32 [ %inner.loop.acc.next, %inner.loop ], [ %outer.loop.acc, %outer.loop ]
99  %i.next = add nsw i32 %i, 1
100  %outer.continue = icmp slt i32 %i.next, %n
101  br i1 %outer.continue, label %outer.loop, label %exit
102
103exit:
104  %result = phi i32 [ 0, %entry ], [ %outer.loop.acc.next, %outer.loop.inc ]
105  ret i32 %result
106}
107
108define i32 @signed_loop_0_to_n_nested_i_to_l_inner_index_check(i32* %array, i32 %length, i32 %n, i32 %l) {
109; CHECK-LABEL: @signed_loop_0_to_n_nested_i_to_l_inner_index_check
110entry:
111  %tmp5 = icmp sle i32 %n, 0
112  br i1 %tmp5, label %exit, label %outer.loop.preheader
113
114outer.loop.preheader:
115  br label %outer.loop
116
117outer.loop:
118; CHECK: outer.loop:
119; CHECK: [[i_1:[^ ]+]] = add i32 %i, 1
120; CHECK-NEXT: [[l_sgt_i_1:[^ ]+]] = icmp sgt i32 %l, [[i_1]]
121; CHECK-NEXT: [[smax:[^ ]+]] = select i1 [[l_sgt_i_1]], i32 %l, i32 [[i_1]]
122; CHECK-NEXT: [[max_j:[^ ]+]] = add i32 [[smax]], -1
123  %outer.loop.acc = phi i32 [ %outer.loop.acc.next, %outer.loop.inc ], [ 0, %outer.loop.preheader ]
124  %i = phi i32 [ %i.next, %outer.loop.inc ], [ 0, %outer.loop.preheader ]
125  %tmp6 = icmp sle i32 %l, 0
126  br i1 %tmp6, label %outer.loop.inc, label %inner.loop.preheader
127
128inner.loop.preheader:
129; CHECK: inner.loop.preheader:
130; CHECK: [[wide_cond:[^ ]+]] = icmp slt i32 [[max_j]], %length
131  br label %inner.loop
132
133inner.loop:
134; CHECK: inner.loop:
135; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 [[wide_cond]], i32 9) [ "deopt"() ]
136  %inner.loop.acc = phi i32 [ %inner.loop.acc.next, %inner.loop ], [ %outer.loop.acc, %inner.loop.preheader ]
137  %j = phi i32 [ %j.next, %inner.loop ], [ %i, %inner.loop.preheader ]
138
139  %within.bounds = icmp slt i32 %j, %length
140  call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
141
142  %j.i64 = zext i32 %j to i64
143  %array.j.ptr = getelementptr inbounds i32, i32* %array, i64 %j.i64
144  %array.j = load i32, i32* %array.j.ptr, align 4
145  %inner.loop.acc.next = add i32 %inner.loop.acc, %array.j
146
147  %j.next = add nsw i32 %j, 1
148  %inner.continue = icmp slt i32 %j.next, %l
149  br i1 %inner.continue, label %inner.loop, label %outer.loop.inc
150
151outer.loop.inc:
152  %outer.loop.acc.next = phi i32 [ %inner.loop.acc.next, %inner.loop ], [ %outer.loop.acc, %outer.loop ]
153  %i.next = add nsw i32 %i, 1
154  %outer.continue = icmp slt i32 %i.next, %n
155  br i1 %outer.continue, label %outer.loop, label %exit
156
157exit:
158  %result = phi i32 [ 0, %entry ], [ %outer.loop.acc.next, %outer.loop.inc ]
159  ret i32 %result
160}