xref: /llvm-project/llvm/test/Transforms/LoopBoundSplit/loop-bound-split.ll (revision dfc4a956f3df59287e0cf6652c0f72621aca6a6f)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -passes=loop-bound-split -S < %s | FileCheck %s
3
4; The transformation is failed with this test because we can not guarantee the
5; split condition is always true in pre-loop after transformation.
6define void @variable_split_loop_bound_and_exit_cond_inc_with_sgt(i64 %a, ptr noalias %src, ptr noalias %dst, i64 %n) {
7; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_sgt(
8; CHECK-NEXT:  loop.ph:
9; CHECK-NEXT:    br label [[LOOP:%.*]]
10; CHECK:       loop:
11; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
12; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]]
13; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
14; CHECK:       if.then:
15; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
16; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
17; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
18; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
19; CHECK-NEXT:    br label [[FOR_INC]]
20; CHECK:       if.else:
21; CHECK-NEXT:    br label [[FOR_INC]]
22; CHECK:       for.inc:
23; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
24; CHECK-NEXT:    [[COND:%.*]] = icmp sgt i64 [[INC]], [[N:%.*]]
25; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
26; CHECK:       exit:
27; CHECK-NEXT:    ret void
28;
29loop.ph:
30  br label %loop
31
32loop:
33  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
34  %cmp = icmp ult i64 %iv, %a
35  br i1 %cmp, label %if.then, label %if.else
36
37if.then:
38  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
39  %val = load i64, ptr %src.arrayidx
40  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
41  store i64 %val, ptr %dst.arrayidx
42  br label %for.inc
43
44if.else:
45  br label %for.inc
46
47for.inc:
48  %inc = add nuw nsw i64 %iv, 1
49  %cond = icmp sgt i64 %inc, %n
50  br i1 %cond, label %exit, label %loop
51
52exit:
53  ret void
54}
55
56; The transformation works with this test because we can guarantee the split
57; condition is always true in pre-loop after transformation.
58define void @umax_variable_split_loop_bound_and_exit_cond_inc_with_sgt(i64 %a, ptr noalias %src, ptr noalias %dst, i64 %n) {
59; CHECK-LABEL: @umax_variable_split_loop_bound_and_exit_cond_inc_with_sgt(
60; CHECK-NEXT:  loop.ph:
61; CHECK-NEXT:    [[B:%.*]] = call i64 @llvm.umax.i64(i64 [[A:%.*]], i64 1)
62; CHECK-NEXT:    br label [[LOOP_PH_SPLIT:%.*]]
63; CHECK:       loop.ph.split:
64; CHECK-NEXT:    [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 0)
65; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[SMAX]], i64 [[B]])
66; CHECK-NEXT:    br label [[LOOP:%.*]]
67; CHECK:       loop:
68; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ]
69; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[B]]
70; CHECK-NEXT:    br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
71; CHECK:       if.then:
72; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
73; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
74; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
75; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
76; CHECK-NEXT:    br label [[FOR_INC]]
77; CHECK:       if.else:
78; CHECK-NEXT:    br label [[FOR_INC]]
79; CHECK:       for.inc:
80; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
81; CHECK-NEXT:    [[COND:%.*]] = icmp sgt i64 [[INC]], [[NEW_BOUND]]
82; CHECK-NEXT:    br i1 [[COND]], label [[LOOP_PH_SPLIT_SPLIT:%.*]], label [[LOOP]]
83; CHECK:       loop.ph.split.split:
84; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i64 [ [[INC]], [[FOR_INC]] ]
85; CHECK-NEXT:    [[TMP0:%.*]] = icmp ne i64 [[IV_LCSSA]], [[N]]
86; CHECK-NEXT:    br i1 [[TMP0]], label [[LOOP_SPLIT_PREHEADER:%.*]], label [[EXIT:%.*]]
87; CHECK:       loop.split.preheader:
88; CHECK-NEXT:    br label [[LOOP_SPLIT:%.*]]
89; CHECK:       loop.split:
90; CHECK-NEXT:    [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[IV_LCSSA]], [[LOOP_SPLIT_PREHEADER]] ]
91; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], [[B]]
92; CHECK-NEXT:    br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]]
93; CHECK:       if.else.split:
94; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
95; CHECK:       if.then.split:
96; CHECK-NEXT:    [[SRC_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, ptr [[SRC]], i64 [[IV_SPLIT]]
97; CHECK-NEXT:    [[VAL_SPLIT:%.*]] = load i64, ptr [[SRC_ARRAYIDX_SPLIT]], align 4
98; CHECK-NEXT:    [[DST_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, ptr [[DST]], i64 [[IV_SPLIT]]
99; CHECK-NEXT:    store i64 [[VAL_SPLIT]], ptr [[DST_ARRAYIDX_SPLIT]], align 4
100; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
101; CHECK:       for.inc.split:
102; CHECK-NEXT:    [[INC_SPLIT]] = add nuw nsw i64 [[IV_SPLIT]], 1
103; CHECK-NEXT:    [[COND_SPLIT:%.*]] = icmp sgt i64 [[INC_SPLIT]], [[N]]
104; CHECK-NEXT:    br i1 [[COND_SPLIT]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_SPLIT]]
105; CHECK:       exit.loopexit:
106; CHECK-NEXT:    br label [[EXIT]]
107; CHECK:       exit:
108; CHECK-NEXT:    ret void
109;
110loop.ph:
111  %b = call i64 @llvm.umax.i64(i64 %a, i64 1)
112  br label %loop
113
114loop:
115  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
116  %cmp = icmp ult i64 %iv, %b
117  br i1 %cmp, label %if.then, label %if.else
118
119if.then:
120  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
121  %val = load i64, ptr %src.arrayidx
122  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
123  store i64 %val, ptr %dst.arrayidx
124  br label %for.inc
125
126if.else:
127  br label %for.inc
128
129for.inc:
130  %inc = add nuw nsw i64 %iv, 1
131  %cond = icmp sgt i64 %inc, %n
132  br i1 %cond, label %exit, label %loop
133
134exit:
135  ret void
136}
137
138; The transformation works with this test because we can guarantee the split
139; condition is always true in pre-loop after transformation.
140define void @constant_split_loop_bound_and_exit_cond_inc_with_sgt(ptr noalias %src, ptr noalias %dst, i64 %n) {
141; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_sgt(
142; CHECK-NEXT:  loop.ph:
143; CHECK-NEXT:    br label [[LOOP_PH_SPLIT:%.*]]
144; CHECK:       loop.ph.split:
145; CHECK-NEXT:    [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 0)
146; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[SMAX]], i64 10)
147; CHECK-NEXT:    br label [[LOOP:%.*]]
148; CHECK:       loop:
149; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ]
150; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
151; CHECK-NEXT:    br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
152; CHECK:       if.then:
153; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
154; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
155; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
156; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
157; CHECK-NEXT:    br label [[FOR_INC]]
158; CHECK:       if.else:
159; CHECK-NEXT:    br label [[FOR_INC]]
160; CHECK:       for.inc:
161; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
162; CHECK-NEXT:    [[COND:%.*]] = icmp sgt i64 [[INC]], [[NEW_BOUND]]
163; CHECK-NEXT:    br i1 [[COND]], label [[LOOP_PH_SPLIT_SPLIT:%.*]], label [[LOOP]]
164; CHECK:       loop.ph.split.split:
165; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i64 [ [[INC]], [[FOR_INC]] ]
166; CHECK-NEXT:    [[TMP0:%.*]] = icmp ne i64 [[IV_LCSSA]], [[N]]
167; CHECK-NEXT:    br i1 [[TMP0]], label [[LOOP_SPLIT_PREHEADER:%.*]], label [[EXIT:%.*]]
168; CHECK:       loop.split.preheader:
169; CHECK-NEXT:    br label [[LOOP_SPLIT:%.*]]
170; CHECK:       loop.split:
171; CHECK-NEXT:    [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[IV_LCSSA]], [[LOOP_SPLIT_PREHEADER]] ]
172; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10
173; CHECK-NEXT:    br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]]
174; CHECK:       if.else.split:
175; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
176; CHECK:       if.then.split:
177; CHECK-NEXT:    [[SRC_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, ptr [[SRC]], i64 [[IV_SPLIT]]
178; CHECK-NEXT:    [[VAL_SPLIT:%.*]] = load i64, ptr [[SRC_ARRAYIDX_SPLIT]], align 4
179; CHECK-NEXT:    [[DST_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, ptr [[DST]], i64 [[IV_SPLIT]]
180; CHECK-NEXT:    store i64 [[VAL_SPLIT]], ptr [[DST_ARRAYIDX_SPLIT]], align 4
181; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
182; CHECK:       for.inc.split:
183; CHECK-NEXT:    [[INC_SPLIT]] = add nuw nsw i64 [[IV_SPLIT]], 1
184; CHECK-NEXT:    [[COND_SPLIT:%.*]] = icmp sgt i64 [[INC_SPLIT]], [[N]]
185; CHECK-NEXT:    br i1 [[COND_SPLIT]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_SPLIT]]
186; CHECK:       exit.loopexit:
187; CHECK-NEXT:    br label [[EXIT]]
188; CHECK:       exit:
189; CHECK-NEXT:    ret void
190;
191loop.ph:
192  br label %loop
193
194loop:
195  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
196  %cmp = icmp ult i64 %iv, 10
197  br i1 %cmp, label %if.then, label %if.else
198
199if.then:
200  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
201  %val = load i64, ptr %src.arrayidx
202  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
203  store i64 %val, ptr %dst.arrayidx
204  br label %for.inc
205
206if.else:
207  br label %for.inc
208
209for.inc:
210  %inc = add nuw nsw i64 %iv, 1
211  %cond = icmp sgt i64 %inc, %n
212  br i1 %cond, label %exit, label %loop
213
214exit:
215  ret void
216}
217
218define void @variable_split_loop_bound_and_exit_cond_inc_with_eq(i64 %a, ptr noalias %src, ptr noalias %dst, i64 %n) {
219; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_eq(
220; CHECK-NEXT:  loop.ph:
221; CHECK-NEXT:    br label [[LOOP:%.*]]
222; CHECK:       loop:
223; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
224; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]]
225; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
226; CHECK:       if.then:
227; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
228; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
229; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
230; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
231; CHECK-NEXT:    br label [[FOR_INC]]
232; CHECK:       if.else:
233; CHECK-NEXT:    br label [[FOR_INC]]
234; CHECK:       for.inc:
235; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
236; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[INC]], [[N:%.*]]
237; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
238; CHECK:       exit:
239; CHECK-NEXT:    ret void
240;
241loop.ph:
242  br label %loop
243
244loop:
245  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
246  %cmp = icmp ult i64 %iv, %a
247  br i1 %cmp, label %if.then, label %if.else
248
249if.then:
250  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
251  %val = load i64, ptr %src.arrayidx
252  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
253  store i64 %val, ptr %dst.arrayidx
254  br label %for.inc
255
256if.else:
257  br label %for.inc
258
259for.inc:
260  %inc = add nuw nsw i64 %iv, 1
261  %cond = icmp eq i64 %inc, %n
262  br i1 %cond, label %exit, label %loop
263
264exit:
265  ret void
266}
267
268define void @constant_split_loop_bound_and_exit_cond_inc_with_eq(ptr noalias %src, ptr noalias %dst, i64 %n) {
269; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_eq(
270; CHECK-NEXT:  loop.ph:
271; CHECK-NEXT:    br label [[LOOP_PH_SPLIT:%.*]]
272; CHECK:       loop.ph.split:
273; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[N:%.*]], -1
274; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.umin.i64(i64 [[TMP0]], i64 10)
275; CHECK-NEXT:    br label [[LOOP:%.*]]
276; CHECK:       loop:
277; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ]
278; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
279; CHECK-NEXT:    br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
280; CHECK:       if.then:
281; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
282; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
283; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
284; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
285; CHECK-NEXT:    br label [[FOR_INC]]
286; CHECK:       if.else:
287; CHECK-NEXT:    br label [[FOR_INC]]
288; CHECK:       for.inc:
289; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
290; CHECK-NEXT:    [[COND:%.*]] = icmp eq i64 [[INC]], [[NEW_BOUND]]
291; CHECK-NEXT:    br i1 [[COND]], label [[LOOP_PH_SPLIT_SPLIT:%.*]], label [[LOOP]]
292; CHECK:       loop.ph.split.split:
293; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i64 [ [[INC]], [[FOR_INC]] ]
294; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i64 [[IV_LCSSA]], [[N]]
295; CHECK-NEXT:    br i1 [[TMP1]], label [[LOOP_SPLIT_PREHEADER:%.*]], label [[EXIT:%.*]]
296; CHECK:       loop.split.preheader:
297; CHECK-NEXT:    br label [[LOOP_SPLIT:%.*]]
298; CHECK:       loop.split:
299; CHECK-NEXT:    [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[IV_LCSSA]], [[LOOP_SPLIT_PREHEADER]] ]
300; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10
301; CHECK-NEXT:    br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]]
302; CHECK:       if.else.split:
303; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
304; CHECK:       if.then.split:
305; CHECK-NEXT:    [[SRC_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, ptr [[SRC]], i64 [[IV_SPLIT]]
306; CHECK-NEXT:    [[VAL_SPLIT:%.*]] = load i64, ptr [[SRC_ARRAYIDX_SPLIT]], align 4
307; CHECK-NEXT:    [[DST_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, ptr [[DST]], i64 [[IV_SPLIT]]
308; CHECK-NEXT:    store i64 [[VAL_SPLIT]], ptr [[DST_ARRAYIDX_SPLIT]], align 4
309; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
310; CHECK:       for.inc.split:
311; CHECK-NEXT:    [[INC_SPLIT]] = add nuw nsw i64 [[IV_SPLIT]], 1
312; CHECK-NEXT:    [[COND_SPLIT:%.*]] = icmp eq i64 [[INC_SPLIT]], [[N]]
313; CHECK-NEXT:    br i1 [[COND_SPLIT]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_SPLIT]]
314; CHECK:       exit.loopexit:
315; CHECK-NEXT:    br label [[EXIT]]
316; CHECK:       exit:
317; CHECK-NEXT:    ret void
318;
319loop.ph:
320  br label %loop
321
322loop:
323  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
324  %cmp = icmp ult i64 %iv, 10
325  br i1 %cmp, label %if.then, label %if.else
326
327if.then:
328  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
329  %val = load i64, ptr %src.arrayidx
330  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
331  store i64 %val, ptr %dst.arrayidx
332  br label %for.inc
333
334if.else:
335  br label %for.inc
336
337for.inc:
338  %inc = add nuw nsw i64 %iv, 1
339  %cond = icmp eq i64 %inc, %n
340  br i1 %cond, label %exit, label %loop
341
342exit:
343  ret void
344}
345
346define void @variable_split_loop_bound_and_exit_cond_inc_with_sge(i64 %a, ptr noalias %src, ptr noalias %dst, i64 %n) {
347; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_sge(
348; CHECK-NEXT:  loop.ph:
349; CHECK-NEXT:    br label [[LOOP:%.*]]
350; CHECK:       loop:
351; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
352; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]]
353; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
354; CHECK:       if.then:
355; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
356; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
357; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
358; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
359; CHECK-NEXT:    br label [[FOR_INC]]
360; CHECK:       if.else:
361; CHECK-NEXT:    br label [[FOR_INC]]
362; CHECK:       for.inc:
363; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
364; CHECK-NEXT:    [[COND:%.*]] = icmp sge i64 [[INC]], [[N:%.*]]
365; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
366; CHECK:       exit:
367; CHECK-NEXT:    ret void
368;
369loop.ph:
370  br label %loop
371
372loop:
373  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
374  %cmp = icmp ult i64 %iv, %a
375  br i1 %cmp, label %if.then, label %if.else
376
377if.then:
378  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
379  %val = load i64, ptr %src.arrayidx
380  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
381  store i64 %val, ptr %dst.arrayidx
382  br label %for.inc
383
384if.else:
385  br label %for.inc
386
387for.inc:
388  %inc = add nuw nsw i64 %iv, 1
389  %cond = icmp sge i64 %inc, %n
390  br i1 %cond, label %exit, label %loop
391
392exit:
393  ret void
394}
395
396define void @constant_split_loop_bound_and_exit_cond_inc_with_sge(ptr noalias %src, ptr noalias %dst, i64 %n) {
397; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_sge(
398; CHECK-NEXT:  loop.ph:
399; CHECK-NEXT:    br label [[LOOP_PH_SPLIT:%.*]]
400; CHECK:       loop.ph.split:
401; CHECK-NEXT:    [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 1)
402; CHECK-NEXT:    [[TMP0:%.*]] = add nsw i64 [[SMAX]], -1
403; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[TMP0]], i64 10)
404; CHECK-NEXT:    br label [[LOOP:%.*]]
405; CHECK:       loop:
406; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ]
407; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
408; CHECK-NEXT:    br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
409; CHECK:       if.then:
410; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
411; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
412; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
413; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
414; CHECK-NEXT:    br label [[FOR_INC]]
415; CHECK:       if.else:
416; CHECK-NEXT:    br label [[FOR_INC]]
417; CHECK:       for.inc:
418; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
419; CHECK-NEXT:    [[COND:%.*]] = icmp sge i64 [[INC]], [[NEW_BOUND]]
420; CHECK-NEXT:    br i1 [[COND]], label [[LOOP_PH_SPLIT_SPLIT:%.*]], label [[LOOP]]
421; CHECK:       loop.ph.split.split:
422; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i64 [ [[INC]], [[FOR_INC]] ]
423; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i64 [[IV_LCSSA]], [[N]]
424; CHECK-NEXT:    br i1 [[TMP1]], label [[LOOP_SPLIT_PREHEADER:%.*]], label [[EXIT:%.*]]
425; CHECK:       loop.split.preheader:
426; CHECK-NEXT:    br label [[LOOP_SPLIT:%.*]]
427; CHECK:       loop.split:
428; CHECK-NEXT:    [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[IV_LCSSA]], [[LOOP_SPLIT_PREHEADER]] ]
429; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10
430; CHECK-NEXT:    br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]]
431; CHECK:       if.else.split:
432; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
433; CHECK:       if.then.split:
434; CHECK-NEXT:    [[SRC_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, ptr [[SRC]], i64 [[IV_SPLIT]]
435; CHECK-NEXT:    [[VAL_SPLIT:%.*]] = load i64, ptr [[SRC_ARRAYIDX_SPLIT]], align 4
436; CHECK-NEXT:    [[DST_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, ptr [[DST]], i64 [[IV_SPLIT]]
437; CHECK-NEXT:    store i64 [[VAL_SPLIT]], ptr [[DST_ARRAYIDX_SPLIT]], align 4
438; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
439; CHECK:       for.inc.split:
440; CHECK-NEXT:    [[INC_SPLIT]] = add nuw nsw i64 [[IV_SPLIT]], 1
441; CHECK-NEXT:    [[COND_SPLIT:%.*]] = icmp sge i64 [[INC_SPLIT]], [[N]]
442; CHECK-NEXT:    br i1 [[COND_SPLIT]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_SPLIT]]
443; CHECK:       exit.loopexit:
444; CHECK-NEXT:    br label [[EXIT]]
445; CHECK:       exit:
446; CHECK-NEXT:    ret void
447;
448loop.ph:
449  br label %loop
450
451loop:
452  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
453  %cmp = icmp ult i64 %iv, 10
454  br i1 %cmp, label %if.then, label %if.else
455
456if.then:
457  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
458  %val = load i64, ptr %src.arrayidx
459  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
460  store i64 %val, ptr %dst.arrayidx
461  br label %for.inc
462
463if.else:
464  br label %for.inc
465
466for.inc:
467  %inc = add nuw nsw i64 %iv, 1
468  %cond = icmp sge i64 %inc, %n
469  br i1 %cond, label %exit, label %loop
470
471exit:
472  ret void
473}
474
475define void @variable_split_loop_bound_and_exit_cond_inc_with_step_is_not_one(i64 %a, ptr noalias %src, ptr noalias %dst, i64 %n) {
476; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_step_is_not_one(
477; CHECK-NEXT:  loop.ph:
478; CHECK-NEXT:    br label [[LOOP:%.*]]
479; CHECK:       loop:
480; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
481; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]]
482; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
483; CHECK:       if.then:
484; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
485; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
486; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
487; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
488; CHECK-NEXT:    br label [[FOR_INC]]
489; CHECK:       if.else:
490; CHECK-NEXT:    br label [[FOR_INC]]
491; CHECK:       for.inc:
492; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 2
493; CHECK-NEXT:    [[COND:%.*]] = icmp sgt i64 [[INC]], [[N:%.*]]
494; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
495; CHECK:       exit:
496; CHECK-NEXT:    ret void
497;
498loop.ph:
499  br label %loop
500
501loop:
502  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
503  %cmp = icmp ult i64 %iv, %a
504  br i1 %cmp, label %if.then, label %if.else
505
506if.then:
507  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
508  %val = load i64, ptr %src.arrayidx
509  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
510  store i64 %val, ptr %dst.arrayidx
511  br label %for.inc
512
513if.else:
514  br label %for.inc
515
516for.inc:
517  %inc = add nuw nsw i64 %iv, 2
518  %cond = icmp sgt i64 %inc, %n
519  br i1 %cond, label %exit, label %loop
520
521exit:
522  ret void
523}
524
525define void @constant_split_loop_bound_and_exit_cond_inc_with_step_is_not_one(ptr noalias %src, ptr noalias %dst, i64 %n) {
526; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_step_is_not_one(
527; CHECK-NEXT:  loop.ph:
528; CHECK-NEXT:    br label [[LOOP_PH_SPLIT:%.*]]
529; CHECK:       loop.ph.split:
530; CHECK-NEXT:    [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 1)
531; CHECK-NEXT:    [[TMP0:%.*]] = lshr i64 [[SMAX]], 1
532; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[TMP0]], i64 10)
533; CHECK-NEXT:    br label [[LOOP:%.*]]
534; CHECK:       loop:
535; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH_SPLIT]] ]
536; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
537; CHECK-NEXT:    br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
538; CHECK:       if.then:
539; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
540; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
541; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
542; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
543; CHECK-NEXT:    br label [[FOR_INC]]
544; CHECK:       if.else:
545; CHECK-NEXT:    br label [[FOR_INC]]
546; CHECK:       for.inc:
547; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 2
548; CHECK-NEXT:    [[COND:%.*]] = icmp sgt i64 [[INC]], [[NEW_BOUND]]
549; CHECK-NEXT:    br i1 [[COND]], label [[LOOP_PH_SPLIT_SPLIT:%.*]], label [[LOOP]]
550; CHECK:       loop.ph.split.split:
551; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i64 [ [[INC]], [[FOR_INC]] ]
552; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i64 [[IV_LCSSA]], [[N]]
553; CHECK-NEXT:    br i1 [[TMP1]], label [[LOOP_SPLIT_PREHEADER:%.*]], label [[EXIT:%.*]]
554; CHECK:       loop.split.preheader:
555; CHECK-NEXT:    br label [[LOOP_SPLIT:%.*]]
556; CHECK:       loop.split:
557; CHECK-NEXT:    [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT:%.*]] ], [ [[IV_LCSSA]], [[LOOP_SPLIT_PREHEADER]] ]
558; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10
559; CHECK-NEXT:    br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]]
560; CHECK:       if.else.split:
561; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
562; CHECK:       if.then.split:
563; CHECK-NEXT:    [[SRC_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, ptr [[SRC]], i64 [[IV_SPLIT]]
564; CHECK-NEXT:    [[VAL_SPLIT:%.*]] = load i64, ptr [[SRC_ARRAYIDX_SPLIT]], align 4
565; CHECK-NEXT:    [[DST_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, ptr [[DST]], i64 [[IV_SPLIT]]
566; CHECK-NEXT:    store i64 [[VAL_SPLIT]], ptr [[DST_ARRAYIDX_SPLIT]], align 4
567; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
568; CHECK:       for.inc.split:
569; CHECK-NEXT:    [[INC_SPLIT]] = add nuw nsw i64 [[IV_SPLIT]], 2
570; CHECK-NEXT:    [[COND_SPLIT:%.*]] = icmp sgt i64 [[INC_SPLIT]], [[N]]
571; CHECK-NEXT:    br i1 [[COND_SPLIT]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_SPLIT]]
572; CHECK:       exit.loopexit:
573; CHECK-NEXT:    br label [[EXIT]]
574; CHECK:       exit:
575; CHECK-NEXT:    ret void
576;
577loop.ph:
578  br label %loop
579
580loop:
581  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
582  %cmp = icmp ult i64 %iv, 10
583  br i1 %cmp, label %if.then, label %if.else
584
585if.then:
586  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
587  %val = load i64, ptr %src.arrayidx
588  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
589  store i64 %val, ptr %dst.arrayidx
590  br label %for.inc
591
592if.else:
593  br label %for.inc
594
595for.inc:
596  %inc = add nuw nsw i64 %iv, 2
597  %cond = icmp sgt i64 %inc, %n
598  br i1 %cond, label %exit, label %loop
599
600exit:
601  ret void
602}
603
604define void @variable_split_loop_bound_and_exit_cond_inc_with_ne(i64 %a, ptr noalias %src, ptr noalias %dst, i64 %n) {
605; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_inc_with_ne(
606; CHECK-NEXT:  loop.ph:
607; CHECK-NEXT:    br label [[LOOP:%.*]]
608; CHECK:       loop:
609; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
610; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]]
611; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_INC]]
612; CHECK:       if.then:
613; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
614; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
615; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
616; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
617; CHECK-NEXT:    br label [[FOR_INC]]
618; CHECK:       for.inc:
619; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
620; CHECK-NEXT:    [[COND:%.*]] = icmp ne i64 [[INC]], [[N:%.*]]
621; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
622; CHECK:       exit:
623; CHECK-NEXT:    ret void
624;
625loop.ph:
626  br label %loop
627
628loop:
629  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
630  %cmp = icmp ult i64 %iv, %a
631  br i1 %cmp, label %if.then, label %for.inc
632
633if.then:
634  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
635  %val = load i64, ptr %src.arrayidx
636  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
637  store i64 %val, ptr %dst.arrayidx
638  br label %for.inc
639
640for.inc:
641  %inc = add nuw nsw i64 %iv, 1
642  %cond = icmp ne i64 %inc, %n
643  br i1 %cond, label %exit, label %loop
644
645exit:
646  ret void
647}
648
649define void @constant_split_loop_bound_and_exit_cond_inc_with_ne(ptr noalias %src, ptr noalias %dst, i64 %n) {
650; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_ne(
651; CHECK-NEXT:  loop.ph:
652; CHECK-NEXT:    br label [[LOOP:%.*]]
653; CHECK:       loop:
654; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
655; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
656; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_INC]]
657; CHECK:       if.then:
658; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
659; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
660; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
661; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
662; CHECK-NEXT:    br label [[FOR_INC]]
663; CHECK:       for.inc:
664; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
665; CHECK-NEXT:    [[COND:%.*]] = icmp ne i64 [[INC]], [[N:%.*]]
666; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
667; CHECK:       exit:
668; CHECK-NEXT:    ret void
669;
670loop.ph:
671  br label %loop
672
673loop:
674  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
675  %cmp = icmp ult i64 %iv, 10
676  br i1 %cmp, label %if.then, label %for.inc
677
678if.then:
679  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
680  %val = load i64, ptr %src.arrayidx
681  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
682  store i64 %val, ptr %dst.arrayidx
683  br label %for.inc
684
685for.inc:
686  %inc = add nuw nsw i64 %iv, 1
687  %cond = icmp ne i64 %inc, %n
688  br i1 %cond, label %exit, label %loop
689
690exit:
691  ret void
692}
693
694define void @varialbe_split_loop_bound_and_exit_cond_dec_with_slt(i64 %a, ptr noalias %src, ptr noalias %dst, i64 %n) {
695; CHECK-LABEL: @varialbe_split_loop_bound_and_exit_cond_dec_with_slt(
696; CHECK-NEXT:  loop.ph:
697; CHECK-NEXT:    br label [[LOOP:%.*]]
698; CHECK:       loop:
699; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[DEC:%.*]], [[FOR_DEC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
700; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]]
701; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_DEC]]
702; CHECK:       if.then:
703; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
704; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
705; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
706; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
707; CHECK-NEXT:    br label [[FOR_DEC]]
708; CHECK:       for.dec:
709; CHECK-NEXT:    [[DEC]] = sub nuw nsw i64 [[IV]], 1
710; CHECK-NEXT:    [[COND:%.*]] = icmp slt i64 [[DEC]], [[N:%.*]]
711; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
712; CHECK:       exit:
713; CHECK-NEXT:    ret void
714;
715loop.ph:
716  br label %loop
717
718loop:
719  %iv = phi i64 [ %dec, %for.dec ], [ 0, %loop.ph ]
720  %cmp = icmp ult i64 %iv, %a
721  br i1 %cmp, label %if.then, label %for.dec
722
723if.then:
724  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
725  %val = load i64, ptr %src.arrayidx
726  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
727  store i64 %val, ptr %dst.arrayidx
728  br label %for.dec
729
730for.dec:
731  %dec = sub nuw nsw i64 %iv, 1
732  %cond = icmp slt i64 %dec, %n
733  br i1 %cond, label %exit, label %loop
734
735exit:
736  ret void
737}
738
739define void @constant_split_loop_bound_and_exit_cond_dec_with_slt(ptr noalias %src, ptr noalias %dst, i64 %n) {
740; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_dec_with_slt(
741; CHECK-NEXT:  loop.ph:
742; CHECK-NEXT:    br label [[LOOP:%.*]]
743; CHECK:       loop:
744; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[DEC:%.*]], [[FOR_DEC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
745; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
746; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_DEC]]
747; CHECK:       if.then:
748; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
749; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
750; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
751; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
752; CHECK-NEXT:    br label [[FOR_DEC]]
753; CHECK:       for.dec:
754; CHECK-NEXT:    [[DEC]] = sub nuw nsw i64 [[IV]], 1
755; CHECK-NEXT:    [[COND:%.*]] = icmp slt i64 [[DEC]], [[N:%.*]]
756; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
757; CHECK:       exit:
758; CHECK-NEXT:    ret void
759;
760loop.ph:
761  br label %loop
762
763loop:
764  %iv = phi i64 [ %dec, %for.dec ], [ 0, %loop.ph ]
765  %cmp = icmp ult i64 %iv, 10
766  br i1 %cmp, label %if.then, label %for.dec
767
768if.then:
769  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
770  %val = load i64, ptr %src.arrayidx
771  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
772  store i64 %val, ptr %dst.arrayidx
773  br label %for.dec
774
775for.dec:
776  %dec = sub nuw nsw i64 %iv, 1
777  %cond = icmp slt i64 %dec, %n
778  br i1 %cond, label %exit, label %loop
779
780exit:
781  ret void
782}
783
784define void @variable_split_loop_bound_and_exit_cond_dec_with_sle(i64 %a, ptr noalias %src, ptr noalias %dst, i64 %n) {
785; CHECK-LABEL: @variable_split_loop_bound_and_exit_cond_dec_with_sle(
786; CHECK-NEXT:  loop.ph:
787; CHECK-NEXT:    br label [[LOOP:%.*]]
788; CHECK:       loop:
789; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[DEC:%.*]], [[FOR_DEC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
790; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], [[A:%.*]]
791; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_DEC]]
792; CHECK:       if.then:
793; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
794; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
795; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
796; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
797; CHECK-NEXT:    br label [[FOR_DEC]]
798; CHECK:       for.dec:
799; CHECK-NEXT:    [[DEC]] = sub nuw nsw i64 [[IV]], 1
800; CHECK-NEXT:    [[COND:%.*]] = icmp sle i64 [[DEC]], [[N:%.*]]
801; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
802; CHECK:       exit:
803; CHECK-NEXT:    ret void
804;
805loop.ph:
806  br label %loop
807
808loop:
809  %iv = phi i64 [ %dec, %for.dec ], [ 0, %loop.ph ]
810  %cmp = icmp ult i64 %iv, %a
811  br i1 %cmp, label %if.then, label %for.dec
812
813if.then:
814  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
815  %val = load i64, ptr %src.arrayidx
816  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
817  store i64 %val, ptr %dst.arrayidx
818  br label %for.dec
819
820for.dec:
821  %dec = sub nuw nsw i64 %iv, 1
822  %cond = icmp sle i64 %dec, %n
823  br i1 %cond, label %exit, label %loop
824
825exit:
826  ret void
827}
828
829define void @constant_split_loop_bound_and_exit_cond_dec_with_sle(ptr noalias %src, ptr noalias %dst, i64 %n) {
830; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_dec_with_sle(
831; CHECK-NEXT:  loop.ph:
832; CHECK-NEXT:    br label [[LOOP:%.*]]
833; CHECK:       loop:
834; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[DEC:%.*]], [[FOR_DEC:%.*]] ], [ 0, [[LOOP_PH:%.*]] ]
835; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
836; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[FOR_DEC]]
837; CHECK:       if.then:
838; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
839; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
840; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
841; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
842; CHECK-NEXT:    br label [[FOR_DEC]]
843; CHECK:       for.dec:
844; CHECK-NEXT:    [[DEC]] = sub nuw nsw i64 [[IV]], 1
845; CHECK-NEXT:    [[COND:%.*]] = icmp sle i64 [[DEC]], [[N:%.*]]
846; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[LOOP]]
847; CHECK:       exit:
848; CHECK-NEXT:    ret void
849;
850loop.ph:
851  br label %loop
852
853loop:
854  %iv = phi i64 [ %dec, %for.dec ], [ 0, %loop.ph ]
855  %cmp = icmp ult i64 %iv, 10
856  br i1 %cmp, label %if.then, label %for.dec
857
858if.then:
859  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
860  %val = load i64, ptr %src.arrayidx
861  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
862  store i64 %val, ptr %dst.arrayidx
863  br label %for.dec
864
865for.dec:
866  %dec = sub nuw nsw i64 %iv, 1
867  %cond = icmp sle i64 %dec, %n
868  br i1 %cond, label %exit, label %loop
869
870exit:
871  ret void
872}
873
874; LoopBoundSplit pass should ignore phi which is not scevable phi.
875define void @constant_split_loop_bound_and_exit_cond_inc_with_sgt_and_is_not_scevable_phi(ptr noalias %src, ptr noalias %dst, i64 %n) {
876; CHECK-LABEL: @constant_split_loop_bound_and_exit_cond_inc_with_sgt_and_is_not_scevable_phi(
877; CHECK-NEXT:  loop.ph:
878; CHECK-NEXT:    br label [[LOOP_PH_SPLIT:%.*]]
879; CHECK:       loop.ph.split:
880; CHECK-NEXT:    [[SMAX:%.*]] = call i64 @llvm.smax.i64(i64 [[N:%.*]], i64 0)
881; CHECK-NEXT:    [[NEW_BOUND:%.*]] = call i64 @llvm.smin.i64(i64 [[SMAX]], i64 10)
882; CHECK-NEXT:    br label [[LOOP:%.*]]
883; CHECK:       loop:
884; CHECK-NEXT:    [[IS_NOT_SCEVABLE_PHI:%.*]] = phi double [ 1.000000e+00, [[FOR_INC:%.*]] ], [ 2.000000e+00, [[LOOP_PH_SPLIT]] ]
885; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_INC]] ], [ 0, [[LOOP_PH_SPLIT]] ]
886; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IV]], 10
887; CHECK-NEXT:    br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
888; CHECK:       if.then:
889; CHECK-NEXT:    [[SRC_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[SRC:%.*]], i64 [[IV]]
890; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[SRC_ARRAYIDX]], align 4
891; CHECK-NEXT:    [[DST_ARRAYIDX:%.*]] = getelementptr inbounds i64, ptr [[DST:%.*]], i64 [[IV]]
892; CHECK-NEXT:    store i64 [[VAL]], ptr [[DST_ARRAYIDX]], align 4
893; CHECK-NEXT:    br label [[FOR_INC]]
894; CHECK:       if.else:
895; CHECK-NEXT:    br label [[FOR_INC]]
896; CHECK:       for.inc:
897; CHECK-NEXT:    [[INC]] = add nuw nsw i64 [[IV]], 1
898; CHECK-NEXT:    [[COND:%.*]] = icmp sgt i64 [[INC]], [[NEW_BOUND]]
899; CHECK-NEXT:    br i1 [[COND]], label [[LOOP_PH_SPLIT_SPLIT:%.*]], label [[LOOP]]
900; CHECK:       loop.ph.split.split:
901; CHECK-NEXT:    [[IS_NOT_SCEVABLE_PHI_LCSSA:%.*]] = phi double [ 1.000000e+00, [[FOR_INC]] ]
902; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i64 [ [[INC]], [[FOR_INC]] ]
903; CHECK-NEXT:    [[TMP0:%.*]] = icmp ne i64 [[IV_LCSSA]], [[N]]
904; CHECK-NEXT:    br i1 [[TMP0]], label [[LOOP_SPLIT_PREHEADER:%.*]], label [[EXIT:%.*]]
905; CHECK:       loop.split.preheader:
906; CHECK-NEXT:    br label [[LOOP_SPLIT:%.*]]
907; CHECK:       loop.split:
908; CHECK-NEXT:    [[IS_NOT_SCEVABLE_PHI_SPLIT:%.*]] = phi double [ 1.000000e+00, [[FOR_INC_SPLIT:%.*]] ], [ [[IS_NOT_SCEVABLE_PHI_LCSSA]], [[LOOP_SPLIT_PREHEADER]] ]
909; CHECK-NEXT:    [[IV_SPLIT:%.*]] = phi i64 [ [[INC_SPLIT:%.*]], [[FOR_INC_SPLIT]] ], [ [[IV_LCSSA]], [[LOOP_SPLIT_PREHEADER]] ]
910; CHECK-NEXT:    [[CMP_SPLIT:%.*]] = icmp ult i64 [[IV_SPLIT]], 10
911; CHECK-NEXT:    br i1 false, label [[IF_THEN_SPLIT:%.*]], label [[IF_ELSE_SPLIT:%.*]]
912; CHECK:       if.else.split:
913; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
914; CHECK:       if.then.split:
915; CHECK-NEXT:    [[SRC_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, ptr [[SRC]], i64 [[IV_SPLIT]]
916; CHECK-NEXT:    [[VAL_SPLIT:%.*]] = load i64, ptr [[SRC_ARRAYIDX_SPLIT]], align 4
917; CHECK-NEXT:    [[DST_ARRAYIDX_SPLIT:%.*]] = getelementptr inbounds i64, ptr [[DST]], i64 [[IV_SPLIT]]
918; CHECK-NEXT:    store i64 [[VAL_SPLIT]], ptr [[DST_ARRAYIDX_SPLIT]], align 4
919; CHECK-NEXT:    br label [[FOR_INC_SPLIT]]
920; CHECK:       for.inc.split:
921; CHECK-NEXT:    [[INC_SPLIT]] = add nuw nsw i64 [[IV_SPLIT]], 1
922; CHECK-NEXT:    [[COND_SPLIT:%.*]] = icmp sgt i64 [[INC_SPLIT]], [[N]]
923; CHECK-NEXT:    br i1 [[COND_SPLIT]], label [[EXIT_LOOPEXIT:%.*]], label [[LOOP_SPLIT]]
924; CHECK:       exit.loopexit:
925; CHECK-NEXT:    br label [[EXIT]]
926; CHECK:       exit:
927; CHECK-NEXT:    ret void
928;
929loop.ph:
930  br label %loop
931
932loop:
933  %is_not_scevable_phi = phi double [ 1.0, %for.inc ], [ 2.0, %loop.ph ]
934  %iv = phi i64 [ %inc, %for.inc ], [ 0, %loop.ph ]
935  %cmp = icmp ult i64 %iv, 10
936  br i1 %cmp, label %if.then, label %if.else
937
938if.then:
939  %src.arrayidx = getelementptr inbounds i64, ptr %src, i64 %iv
940  %val = load i64, ptr %src.arrayidx
941  %dst.arrayidx = getelementptr inbounds i64, ptr %dst, i64 %iv
942  store i64 %val, ptr %dst.arrayidx
943  br label %for.inc
944
945if.else:
946  br label %for.inc
947
948for.inc:
949  %inc = add nuw nsw i64 %iv, 1
950  %cond = icmp sgt i64 %inc, %n
951  br i1 %cond, label %exit, label %loop
952
953exit:
954  ret void
955}
956
957declare i64 @llvm.umax.i64(i64, i64)
958