llvm-project/llvm/test/Transforms/LoopUnroll/peel-loop-conditions.ll
Nikita Popov b43a4d0850 [LoopPeeling] Support peeling loops with non-latch exits
Loop peeling currently requires that a) the latch is exiting
b) a branch and c) other exits are unreachable/deopt. This patch
removes all of these limitations, and adds the necessary branch
weight updating support. It essentially works the same way as
before with latch -> exiting terminator and
loop trip count -> per exit trip count.

It's worth noting that there are still other limitations in
profitability heuristics: This patch enables peeling of loops to
make conditions invariant (which is pretty much always highly
profitable if possible), while peeling to make loads dereferenceable
still checks that non-latch exits are unreachable and PGO-based
peeling has even more conditions. Those checks could be relaxed
later if we consider those cases profitable.

The motivation for this change is that loops using iterator adaptors
in Rust often optimize very badly, and end up with a loop phi of the
form phi(true, false) in the final result. Peeling eliminates that
phi and conditions based on it, which enables a lot of follow-on
simplification.

Differential Revision: https://reviews.llvm.org/D134803
2022-10-07 12:35:52 +02:00

1237 lines
47 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -S -loop-unroll -unroll-peel-max-count=4 -verify-dom-info | FileCheck %s
declare void @f1()
declare void @f2()
; Check that we can peel off iterations that make conditions true.
define void @test1(i32 %k) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: for.body.lr.ph:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_BEGIN:%.*]]
; CHECK: for.body.peel.begin:
; CHECK-NEXT: br label [[FOR_BODY_PEEL:%.*]]
; CHECK: for.body.peel:
; CHECK-NEXT: [[CMP1_PEEL:%.*]] = icmp ult i32 0, 2
; CHECK-NEXT: br i1 [[CMP1_PEEL]], label [[IF_THEN_PEEL:%.*]], label [[IF_ELSE_PEEL:%.*]]
; CHECK: if.else.peel:
; CHECK-NEXT: call void @f2()
; CHECK-NEXT: br label [[FOR_INC_PEEL:%.*]]
; CHECK: if.then.peel:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL]]
; CHECK: for.inc.peel:
; CHECK-NEXT: [[INC_PEEL:%.*]] = add nsw i32 0, 1
; CHECK-NEXT: [[CMP_PEEL:%.*]] = icmp slt i32 [[INC_PEEL]], [[K:%.*]]
; CHECK-NEXT: br i1 [[CMP_PEEL]], label [[FOR_BODY_PEEL_NEXT:%.*]], label [[FOR_END:%[^,]*]]
; Verify that MD_loop metadata is dropped.
; CHECK-NOT: , !llvm.loop !{{[0-9]*}}
; CHECK: for.body.peel.next:
; CHECK-NEXT: br label [[FOR_BODY_PEEL2:%.*]]
; CHECK: for.body.peel2:
; CHECK-NEXT: [[CMP1_PEEL3:%.*]] = icmp ult i32 [[INC_PEEL]], 2
; CHECK-NEXT: br i1 [[CMP1_PEEL3]], label [[IF_THEN_PEEL5:%.*]], label [[IF_ELSE_PEEL4:%.*]]
; CHECK: if.else.peel4:
; CHECK-NEXT: call void @f2()
; CHECK-NEXT: br label [[FOR_INC_PEEL6:%.*]]
; CHECK: if.then.peel5:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL6]]
; CHECK: for.inc.peel6:
; CHECK-NEXT: [[INC_PEEL7:%.*]] = add nsw i32 [[INC_PEEL]], 1
; CHECK-NEXT: [[CMP_PEEL8:%.*]] = icmp slt i32 [[INC_PEEL7]], [[K]]
; CHECK-NEXT: br i1 [[CMP_PEEL8]], label [[FOR_BODY_PEEL_NEXT1:%.*]], label [[FOR_END]]
; Verify that MD_loop metadata is dropped.
; CHECK-NOT: , !llvm.loop !{{[0-9]*}}
; CHECK: for.body.peel.next1:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_NEXT9:%.*]]
; CHECK: for.body.peel.next9:
; CHECK-NEXT: br label [[FOR_BODY_LR_PH_PEEL_NEWPH:%.*]]
; CHECK: for.body.lr.ph.peel.newph:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[I_05:%.*]] = phi i32 [ [[INC_PEEL7]], [[FOR_BODY_LR_PH_PEEL_NEWPH]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: if.else:
; CHECK-NEXT: call void @f2()
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_05]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[K]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]], !llvm.loop !{{.*}}
; CHECK: for.end.loopexit:
; CHECK-NEXT: br label [[FOR_END]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
for.body.lr.ph:
br label %for.body
for.body:
%i.05 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.inc ]
%cmp1 = icmp ult i32 %i.05, 2
br i1 %cmp1, label %if.then, label %if.else
if.then:
call void @f1()
br label %for.inc
if.else:
call void @f2()
br label %for.inc
for.inc:
%inc = add nsw i32 %i.05, 1
%cmp = icmp slt i32 %inc, %k
br i1 %cmp, label %for.body, label %for.end, !llvm.loop !1
for.end:
ret void
}
!1 = distinct !{!1}
; Check we peel off the maximum number of iterations that make conditions true.
define void @test2(i32 %k) {
; CHECK-LABEL: @test2(
; CHECK-NEXT: for.body.lr.ph:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_BEGIN:%.*]]
; CHECK: for.body.peel.begin:
; CHECK-NEXT: br label [[FOR_BODY_PEEL:%.*]]
; CHECK: for.body.peel:
; CHECK-NEXT: [[CMP1_PEEL:%.*]] = icmp ult i32 0, 2
; CHECK-NEXT: br i1 [[CMP1_PEEL]], label [[IF_THEN_PEEL:%.*]], label [[IF_ELSE_PEEL:%.*]]
; CHECK: if.else.peel:
; CHECK-NEXT: call void @f2()
; CHECK-NEXT: br label [[IF2_PEEL:%.*]]
; CHECK: if.then.peel:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[IF2_PEEL]]
; CHECK: if2.peel:
; CHECK-NEXT: [[CMP2_PEEL:%.*]] = icmp ult i32 0, 4
; CHECK-NEXT: br i1 [[CMP2_PEEL]], label [[IF_THEN2_PEEL:%.*]], label [[FOR_INC_PEEL:%.*]]
; CHECK: if.then2.peel:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL]]
; CHECK: for.inc.peel:
; CHECK-NEXT: [[INC_PEEL:%.*]] = add nsw i32 0, 1
; CHECK-NEXT: [[CMP_PEEL:%.*]] = icmp slt i32 [[INC_PEEL]], [[K:%.*]]
; CHECK-NEXT: br i1 [[CMP_PEEL]], label [[FOR_BODY_PEEL_NEXT:%.*]], label [[FOR_END:%[^,]*]]
; Verify that MD_loop metadata is dropped.
; CHECK-NOT: , !llvm.loop !{{[0-9]*}}
; CHECK: for.body.peel.next:
; CHECK-NEXT: br label [[FOR_BODY_PEEL2:%.*]]
; CHECK: for.body.peel2:
; CHECK-NEXT: [[CMP1_PEEL3:%.*]] = icmp ult i32 [[INC_PEEL]], 2
; CHECK-NEXT: br i1 [[CMP1_PEEL3]], label [[IF_THEN_PEEL5:%.*]], label [[IF_ELSE_PEEL4:%.*]]
; CHECK: if.else.peel4:
; CHECK-NEXT: call void @f2()
; CHECK-NEXT: br label [[IF2_PEEL6:%.*]]
; CHECK: if.then.peel5:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[IF2_PEEL6]]
; CHECK: if2.peel6:
; CHECK-NEXT: [[CMP2_PEEL7:%.*]] = icmp ult i32 [[INC_PEEL]], 4
; CHECK-NEXT: br i1 [[CMP2_PEEL7]], label [[IF_THEN2_PEEL8:%.*]], label [[FOR_INC_PEEL9:%.*]]
; CHECK: if.then2.peel8:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL9]]
; CHECK: for.inc.peel9:
; CHECK-NEXT: [[INC_PEEL10:%.*]] = add nsw i32 [[INC_PEEL]], 1
; CHECK-NEXT: [[CMP_PEEL11:%.*]] = icmp slt i32 [[INC_PEEL10]], [[K]]
; CHECK-NEXT: br i1 [[CMP_PEEL11]], label [[FOR_BODY_PEEL_NEXT1:%.*]], label [[FOR_END]]
; Verify that MD_loop metadata is dropped.
; CHECK-NOT: , !llvm.loop !{{[0-9]*}}
; CHECK: for.body.peel.next1:
; CHECK-NEXT: br label [[FOR_BODY_PEEL13:%.*]]
; CHECK: for.body.peel13:
; CHECK-NEXT: [[CMP1_PEEL14:%.*]] = icmp ult i32 [[INC_PEEL10]], 2
; CHECK-NEXT: br i1 [[CMP1_PEEL14]], label [[IF_THEN_PEEL16:%.*]], label [[IF_ELSE_PEEL15:%.*]]
; CHECK: if.else.peel15:
; CHECK-NEXT: call void @f2()
; CHECK-NEXT: br label [[IF2_PEEL17:%.*]]
; CHECK: if.then.peel16:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[IF2_PEEL17]]
; CHECK: if2.peel17:
; CHECK-NEXT: [[CMP2_PEEL18:%.*]] = icmp ult i32 [[INC_PEEL10]], 4
; CHECK-NEXT: br i1 [[CMP2_PEEL18]], label [[IF_THEN2_PEEL19:%.*]], label [[FOR_INC_PEEL20:%.*]]
; CHECK: if.then2.peel19:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL20]]
; CHECK: for.inc.peel20:
; CHECK-NEXT: [[INC_PEEL21:%.*]] = add nsw i32 [[INC_PEEL10]], 1
; CHECK-NEXT: [[CMP_PEEL22:%.*]] = icmp slt i32 [[INC_PEEL21]], [[K]]
; CHECK-NEXT: br i1 [[CMP_PEEL22]], label [[FOR_BODY_PEEL_NEXT12:%.*]], label [[FOR_END]]
; Verify that MD_loop metadata is dropped.
; CHECK-NOT: , !llvm.loop !{{[0-9]*}}
; CHECK: for.body.peel.next12:
; CHECK-NEXT: br label [[FOR_BODY_PEEL24:%.*]]
; CHECK: for.body.peel24:
; CHECK-NEXT: [[CMP1_PEEL25:%.*]] = icmp ult i32 [[INC_PEEL21]], 2
; CHECK-NEXT: br i1 [[CMP1_PEEL25]], label [[IF_THEN_PEEL27:%.*]], label [[IF_ELSE_PEEL26:%.*]]
; CHECK: if.else.peel26:
; CHECK-NEXT: call void @f2()
; CHECK-NEXT: br label [[IF2_PEEL28:%.*]]
; CHECK: if.then.peel27:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[IF2_PEEL28]]
; CHECK: if2.peel28:
; CHECK-NEXT: [[CMP2_PEEL29:%.*]] = icmp ult i32 [[INC_PEEL21]], 4
; CHECK-NEXT: br i1 [[CMP2_PEEL29]], label [[IF_THEN2_PEEL30:%.*]], label [[FOR_INC_PEEL31:%.*]]
; CHECK: if.then2.peel30:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL31]]
; CHECK: for.inc.peel31:
; CHECK-NEXT: [[INC_PEEL32:%.*]] = add nsw i32 [[INC_PEEL21]], 1
; CHECK-NEXT: [[CMP_PEEL33:%.*]] = icmp slt i32 [[INC_PEEL32]], [[K]]
; CHECK-NEXT: br i1 [[CMP_PEEL33]], label [[FOR_BODY_PEEL_NEXT23:%.*]], label [[FOR_END]]
; Verify that MD_loop metadata is dropped.
; CHECK-NOT: , !llvm.loop !{{[0-9]*}}
; CHECK: for.body.peel.next23:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_NEXT34:%.*]]
; CHECK: for.body.peel.next34:
; CHECK-NEXT: br label [[FOR_BODY_LR_PH_PEEL_NEWPH:%.*]]
; CHECK: for.body.lr.ph.peel.newph:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[I_05:%.*]] = phi i32 [ [[INC_PEEL32]], [[FOR_BODY_LR_PH_PEEL_NEWPH]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[IF2:%.*]]
; CHECK: if.else:
; CHECK-NEXT: call void @f2()
; CHECK-NEXT: br label [[IF2]]
; CHECK: if2:
; CHECK-NEXT: br i1 false, label [[IF_THEN2:%.*]], label [[FOR_INC]]
; CHECK: if.then2:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_05]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[K]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]], !llvm.loop !{{.*}}
; CHECK: for.end.loopexit:
; CHECK-NEXT: br label [[FOR_END]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
for.body.lr.ph:
br label %for.body
for.body:
%i.05 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.inc ]
%cmp1 = icmp ult i32 %i.05, 2
br i1 %cmp1, label %if.then, label %if.else
if.then:
call void @f1()
br label %if2
if.else:
call void @f2()
br label %if2
if2:
%cmp2 = icmp ult i32 %i.05, 4
br i1 %cmp2, label %if.then2, label %for.inc
if.then2:
call void @f1()
br label %for.inc
for.inc:
%inc = add nsw i32 %i.05, 1
%cmp = icmp slt i32 %inc, %k
br i1 %cmp, label %for.body, label %for.end, !llvm.loop !2
for.end:
ret void
}
!2 = distinct !{!2}
; Check that we can peel off iterations that make a condition false.
define void @test3(i32 %k) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: for.body.lr.ph:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_BEGIN:%.*]]
; CHECK: for.body.peel.begin:
; CHECK-NEXT: br label [[FOR_BODY_PEEL:%.*]]
; CHECK: for.body.peel:
; CHECK-NEXT: [[CMP1_PEEL:%.*]] = icmp ugt i32 0, 2
; CHECK-NEXT: br i1 [[CMP1_PEEL]], label [[IF_THEN_PEEL:%.*]], label [[IF_ELSE_PEEL:%.*]]
; CHECK: if.else.peel:
; CHECK-NEXT: call void @f2()
; CHECK-NEXT: br label [[FOR_INC_PEEL:%.*]]
; CHECK: if.then.peel:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL]]
; CHECK: for.inc.peel:
; CHECK-NEXT: [[INC_PEEL:%.*]] = add nsw i32 0, 1
; CHECK-NEXT: [[CMP_PEEL:%.*]] = icmp slt i32 [[INC_PEEL]], [[K:%.*]]
; CHECK-NEXT: br i1 [[CMP_PEEL]], label [[FOR_BODY_PEEL_NEXT:%.*]], label [[FOR_END:%[^,]*]]
; Verify that MD_loop metadata is dropped.
; CHECK-NOT: , !llvm.loop !{{[0-9]*}}
; CHECK: for.body.peel.next:
; CHECK-NEXT: br label [[FOR_BODY_PEEL2:%.*]]
; CHECK: for.body.peel2:
; CHECK-NEXT: [[CMP1_PEEL3:%.*]] = icmp ugt i32 [[INC_PEEL]], 2
; CHECK-NEXT: br i1 [[CMP1_PEEL3]], label [[IF_THEN_PEEL5:%.*]], label [[IF_ELSE_PEEL4:%.*]]
; CHECK: if.else.peel4:
; CHECK-NEXT: call void @f2()
; CHECK-NEXT: br label [[FOR_INC_PEEL6:%.*]]
; CHECK: if.then.peel5:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL6]]
; CHECK: for.inc.peel6:
; CHECK-NEXT: [[INC_PEEL7:%.*]] = add nsw i32 [[INC_PEEL]], 1
; CHECK-NEXT: [[CMP_PEEL8:%.*]] = icmp slt i32 [[INC_PEEL7]], [[K]]
; CHECK-NEXT: br i1 [[CMP_PEEL8]], label [[FOR_BODY_PEEL_NEXT1:%.*]], label [[FOR_END]]
; Verify that MD_loop metadata is dropped.
; CHECK-NOT: , !llvm.loop !{{[0-9]*}}
; CHECK: for.body.peel.next1:
; CHECK-NEXT: br label [[FOR_BODY_PEEL10:%.*]]
; CHECK: for.body.peel10:
; CHECK-NEXT: [[CMP1_PEEL11:%.*]] = icmp ugt i32 [[INC_PEEL7]], 2
; CHECK-NEXT: br i1 [[CMP1_PEEL11]], label [[IF_THEN_PEEL13:%.*]], label [[IF_ELSE_PEEL12:%.*]]
; CHECK: if.else.peel12:
; CHECK-NEXT: call void @f2()
; CHECK-NEXT: br label [[FOR_INC_PEEL14:%.*]]
; CHECK: if.then.peel13:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL14]]
; CHECK: for.inc.peel14:
; CHECK-NEXT: [[INC_PEEL15:%.*]] = add nsw i32 [[INC_PEEL7]], 1
; CHECK-NEXT: [[CMP_PEEL16:%.*]] = icmp slt i32 [[INC_PEEL15]], [[K]]
; CHECK-NEXT: br i1 [[CMP_PEEL16]], label [[FOR_BODY_PEEL_NEXT9:%.*]], label [[FOR_END]]
; Verify that MD_loop metadata is dropped.
; CHECK-NOT: , !llvm.loop !{{[0-9]*}}
; CHECK: for.body.peel.next9:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_NEXT17:%.*]]
; CHECK: for.body.peel.next17:
; CHECK-NEXT: br label [[FOR_BODY_LR_PH_PEEL_NEWPH:%.*]]
; CHECK: for.body.lr.ph.peel.newph:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[I_05:%.*]] = phi i32 [ [[INC_PEEL15]], [[FOR_BODY_LR_PH_PEEL_NEWPH]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: br i1 true, label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: if.else:
; CHECK-NEXT: call void @f2()
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_05]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[K]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]], !llvm.loop !{{.*}}
; CHECK: for.end.loopexit:
; CHECK-NEXT: br label [[FOR_END]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
for.body.lr.ph:
br label %for.body
for.body:
%i.05 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.inc ]
%cmp1 = icmp ugt i32 %i.05, 2
br i1 %cmp1, label %if.then, label %if.else
if.then:
call void @f1()
br label %for.inc
if.else:
call void @f2()
br label %for.inc
for.inc:
%inc = add nsw i32 %i.05, 1
%cmp = icmp slt i32 %inc, %k
br i1 %cmp, label %for.body, label %for.end, !llvm.loop !3
for.end:
ret void
}
!3 = distinct !{!3}
; Test that we only peel off iterations if it simplifies a condition in the
; loop body after peeling at most MaxPeelCount iterations.
define void @test4(i32 %k) {
; CHECK-LABEL: @test4(
; CHECK-NEXT: for.body.lr.ph:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[I_05:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[I_05]], 9999
; CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN:%.*]], label [[FOR_INC]]
; CHECK: if.then:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nsw i32 [[I_05]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[K:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
for.body.lr.ph:
br label %for.body
for.body:
%i.05 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.inc ]
%cmp1 = icmp ugt i32 %i.05, 9999
br i1 %cmp1, label %if.then, label %for.inc
if.then:
call void @f1()
br label %for.inc
for.inc:
%inc = add nsw i32 %i.05, 1
%cmp = icmp slt i32 %inc, %k
br i1 %cmp, label %for.body, label %for.end
for.end:
ret void
}
; In this test, the condition involves 2 AddRecs. Without evaluating both
; AddRecs, we cannot prove that the condition becomes known in the loop body
; after peeling.
define void @test5(i32 %k) {
; CHECK-LABEL: @test5(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[I_05:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[J:%.*]] = phi i32 [ 4, [[ENTRY]] ], [ [[J_INC:%.*]], [[FOR_INC]] ]
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[I_05]], [[J]]
; CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: if.else:
; CHECK-NEXT: call void @f2()
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nsw i32 [[I_05]], 2
; CHECK-NEXT: [[J_INC]] = add nsw i32 [[J]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[K:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
entry:
br label %for.body
for.body:
%i.05 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
%j = phi i32 [ 4, %entry ], [ %j.inc, %for.inc ]
%cmp1 = icmp ult i32 %i.05, %j
br i1 %cmp1, label %if.then, label %if.else
if.then:
call void @f1()
br label %for.inc
if.else:
call void @f2()
br label %for.inc
for.inc:
%inc = add nsw i32 %i.05, 2
%j.inc = add nsw i32 %j, 1
%cmp = icmp slt i32 %inc, %k
br i1 %cmp, label %for.body, label %for.end
for.end:
ret void
}
define void @test6(i32 %k) {
; CHECK-LABEL: @test6(
; CHECK-NEXT: for.body.lr.ph:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_BEGIN:%.*]]
; CHECK: for.body.peel.begin:
; CHECK-NEXT: br label [[FOR_BODY_PEEL:%.*]]
; CHECK: for.body.peel:
; CHECK-NEXT: [[CMP1_PEEL:%.*]] = icmp ne i32 0, 3
; CHECK-NEXT: br i1 [[CMP1_PEEL]], label [[IF_THEN_PEEL:%.*]], label [[FOR_INC_PEEL:%.*]]
; CHECK: if.then.peel:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL]]
; CHECK: for.inc.peel:
; CHECK-NEXT: [[INC_PEEL:%.*]] = add nsw i32 0, 1
; CHECK-NEXT: [[CMP_PEEL:%.*]] = icmp slt i32 [[INC_PEEL]], [[K:%.*]]
; CHECK-NEXT: br i1 [[CMP_PEEL]], label [[FOR_BODY_PEEL_NEXT:%.*]], label [[FOR_END:%.*]]
; CHECK: for.body.peel.next:
; CHECK-NEXT: br label [[FOR_BODY_PEEL2:%.*]]
; CHECK: for.body.peel2:
; CHECK-NEXT: [[CMP1_PEEL3:%.*]] = icmp ne i32 [[INC_PEEL]], 3
; CHECK-NEXT: br i1 [[CMP1_PEEL3]], label [[IF_THEN_PEEL4:%.*]], label [[FOR_INC_PEEL5:%.*]]
; CHECK: if.then.peel4:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL5]]
; CHECK: for.inc.peel5:
; CHECK-NEXT: [[INC_PEEL6:%.*]] = add nsw i32 [[INC_PEEL]], 1
; CHECK-NEXT: [[CMP_PEEL7:%.*]] = icmp slt i32 [[INC_PEEL6]], [[K]]
; CHECK-NEXT: br i1 [[CMP_PEEL7]], label [[FOR_BODY_PEEL_NEXT1:%.*]], label [[FOR_END]]
; CHECK: for.body.peel.next1:
; CHECK-NEXT: br label [[FOR_BODY_PEEL9:%.*]]
; CHECK: for.body.peel9:
; CHECK-NEXT: [[CMP1_PEEL10:%.*]] = icmp ne i32 [[INC_PEEL6]], 3
; CHECK-NEXT: br i1 [[CMP1_PEEL10]], label [[IF_THEN_PEEL11:%.*]], label [[FOR_INC_PEEL12:%.*]]
; CHECK: if.then.peel11:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL12]]
; CHECK: for.inc.peel12:
; CHECK-NEXT: [[INC_PEEL13:%.*]] = add nsw i32 [[INC_PEEL6]], 1
; CHECK-NEXT: [[CMP_PEEL14:%.*]] = icmp slt i32 [[INC_PEEL13]], [[K]]
; CHECK-NEXT: br i1 [[CMP_PEEL14]], label [[FOR_BODY_PEEL_NEXT8:%.*]], label [[FOR_END]]
; CHECK: for.body.peel.next8:
; CHECK-NEXT: br label [[FOR_BODY_PEEL16:%.*]]
; CHECK: for.body.peel16:
; CHECK-NEXT: [[CMP1_PEEL17:%.*]] = icmp ne i32 [[INC_PEEL13]], 3
; CHECK-NEXT: br i1 [[CMP1_PEEL17]], label [[IF_THEN_PEEL18:%.*]], label [[FOR_INC_PEEL19:%.*]]
; CHECK: if.then.peel18:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL19]]
; CHECK: for.inc.peel19:
; CHECK-NEXT: [[INC_PEEL20:%.*]] = add nsw i32 [[INC_PEEL13]], 1
; CHECK-NEXT: [[CMP_PEEL21:%.*]] = icmp slt i32 [[INC_PEEL20]], [[K]]
; CHECK-NEXT: br i1 [[CMP_PEEL21]], label [[FOR_BODY_PEEL_NEXT15:%.*]], label [[FOR_END]]
; CHECK: for.body.peel.next15:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_NEXT22:%.*]]
; CHECK: for.body.peel.next22:
; CHECK-NEXT: br label [[FOR_BODY_LR_PH_PEEL_NEWPH:%.*]]
; CHECK: for.body.lr.ph.peel.newph:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[I_05:%.*]] = phi i32 [ [[INC_PEEL20]], [[FOR_BODY_LR_PH_PEEL_NEWPH]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: br i1 true, label [[IF_THEN:%.*]], label [[FOR_INC]]
; CHECK: if.then:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_05]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[K]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]], !llvm.loop !6
; CHECK: for.end.loopexit:
; CHECK-NEXT: br label [[FOR_END]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
for.body.lr.ph:
br label %for.body
for.body:
%i.05 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.inc ]
%cmp1 = icmp ne i32 %i.05, 3
br i1 %cmp1, label %if.then, label %for.inc
if.then:
call void @f1()
br label %for.inc
for.inc:
%inc = add nsw i32 %i.05, 1
%cmp = icmp slt i32 %inc, %k
br i1 %cmp, label %for.body, label %for.end
for.end:
ret void
}
define void @test7(i32 %k) {
; CHECK-LABEL: @test7(
; CHECK-NEXT: for.body.lr.ph:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_BEGIN:%.*]]
; CHECK: for.body.peel.begin:
; CHECK-NEXT: br label [[FOR_BODY_PEEL:%.*]]
; CHECK: for.body.peel:
; CHECK-NEXT: [[CMP1_PEEL:%.*]] = icmp eq i32 0, 3
; CHECK-NEXT: br i1 [[CMP1_PEEL]], label [[IF_THEN_PEEL:%.*]], label [[FOR_INC_PEEL:%.*]]
; CHECK: if.then.peel:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL]]
; CHECK: for.inc.peel:
; CHECK-NEXT: [[INC_PEEL:%.*]] = add nsw i32 0, 1
; CHECK-NEXT: [[CMP_PEEL:%.*]] = icmp slt i32 [[INC_PEEL]], [[K:%.*]]
; CHECK-NEXT: br i1 [[CMP_PEEL]], label [[FOR_BODY_PEEL_NEXT:%.*]], label [[FOR_END:%.*]]
; CHECK: for.body.peel.next:
; CHECK-NEXT: br label [[FOR_BODY_PEEL2:%.*]]
; CHECK: for.body.peel2:
; CHECK-NEXT: [[CMP1_PEEL3:%.*]] = icmp eq i32 [[INC_PEEL]], 3
; CHECK-NEXT: br i1 [[CMP1_PEEL3]], label [[IF_THEN_PEEL4:%.*]], label [[FOR_INC_PEEL5:%.*]]
; CHECK: if.then.peel4:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL5]]
; CHECK: for.inc.peel5:
; CHECK-NEXT: [[INC_PEEL6:%.*]] = add nsw i32 [[INC_PEEL]], 1
; CHECK-NEXT: [[CMP_PEEL7:%.*]] = icmp slt i32 [[INC_PEEL6]], [[K]]
; CHECK-NEXT: br i1 [[CMP_PEEL7]], label [[FOR_BODY_PEEL_NEXT1:%.*]], label [[FOR_END]]
; CHECK: for.body.peel.next1:
; CHECK-NEXT: br label [[FOR_BODY_PEEL9:%.*]]
; CHECK: for.body.peel9:
; CHECK-NEXT: [[CMP1_PEEL10:%.*]] = icmp eq i32 [[INC_PEEL6]], 3
; CHECK-NEXT: br i1 [[CMP1_PEEL10]], label [[IF_THEN_PEEL11:%.*]], label [[FOR_INC_PEEL12:%.*]]
; CHECK: if.then.peel11:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL12]]
; CHECK: for.inc.peel12:
; CHECK-NEXT: [[INC_PEEL13:%.*]] = add nsw i32 [[INC_PEEL6]], 1
; CHECK-NEXT: [[CMP_PEEL14:%.*]] = icmp slt i32 [[INC_PEEL13]], [[K]]
; CHECK-NEXT: br i1 [[CMP_PEEL14]], label [[FOR_BODY_PEEL_NEXT8:%.*]], label [[FOR_END]]
; CHECK: for.body.peel.next8:
; CHECK-NEXT: br label [[FOR_BODY_PEEL16:%.*]]
; CHECK: for.body.peel16:
; CHECK-NEXT: [[CMP1_PEEL17:%.*]] = icmp eq i32 [[INC_PEEL13]], 3
; CHECK-NEXT: br i1 [[CMP1_PEEL17]], label [[IF_THEN_PEEL18:%.*]], label [[FOR_INC_PEEL19:%.*]]
; CHECK: if.then.peel18:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC_PEEL19]]
; CHECK: for.inc.peel19:
; CHECK-NEXT: [[INC_PEEL20:%.*]] = add nsw i32 [[INC_PEEL13]], 1
; CHECK-NEXT: [[CMP_PEEL21:%.*]] = icmp slt i32 [[INC_PEEL20]], [[K]]
; CHECK-NEXT: br i1 [[CMP_PEEL21]], label [[FOR_BODY_PEEL_NEXT15:%.*]], label [[FOR_END]]
; CHECK: for.body.peel.next15:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_NEXT22:%.*]]
; CHECK: for.body.peel.next22:
; CHECK-NEXT: br label [[FOR_BODY_LR_PH_PEEL_NEWPH:%.*]]
; CHECK: for.body.lr.ph.peel.newph:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[I_05:%.*]] = phi i32 [ [[INC_PEEL20]], [[FOR_BODY_LR_PH_PEEL_NEWPH]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[FOR_INC]]
; CHECK: if.then:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_05]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[K]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]], !llvm.loop !7
; CHECK: for.end.loopexit:
; CHECK-NEXT: br label [[FOR_END]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
for.body.lr.ph:
br label %for.body
for.body:
%i.05 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.inc ]
%cmp1 = icmp eq i32 %i.05, 3
br i1 %cmp1, label %if.then, label %for.inc
if.then:
call void @f1()
br label %for.inc
for.inc:
%inc = add nsw i32 %i.05, 1
%cmp = icmp slt i32 %inc, %k
br i1 %cmp, label %for.body, label %for.end
for.end:
ret void
}
; Comparison with non-monotonic predicate due to possible wrapping, loop
; body cannot be simplified.
define void @test8(i32 %k) {
; CHECK-LABEL: @test8(
; CHECK-NEXT: for.body.lr.ph:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[I_05:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[I_05]], 3
; CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN:%.*]], label [[FOR_INC]]
; CHECK: if.then:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add i32 [[I_05]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[K:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
for.body.lr.ph:
br label %for.body
for.body:
%i.05 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.inc ]
%cmp1 = icmp slt i32 %i.05, 3
br i1 %cmp1, label %if.then, label %for.inc
if.then:
call void @f1()
br label %for.inc
for.inc:
%inc = add i32 %i.05, 1
%cmp = icmp slt i32 %inc, %k
br i1 %cmp, label %for.body, label %for.end
for.end:
ret void
}
; CHECK-NOT: llvm.loop.unroll.disable
define void @test_9__peel_first_iter_via_slt_pred(i32 %len) {
; CHECK-LABEL: @test_9__peel_first_iter_via_slt_pred(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[LEN:%.*]], 0
; CHECK-NEXT: br i1 [[CMP5]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.body.preheader:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_BEGIN:%.*]]
; CHECK: for.body.peel.begin:
; CHECK-NEXT: br label [[FOR_BODY_PEEL:%.*]]
; CHECK: for.body.peel:
; CHECK-NEXT: [[CMP1_PEEL:%.*]] = icmp slt i32 0, 1
; CHECK-NEXT: br i1 [[CMP1_PEEL]], label [[IF_THEN_PEEL:%.*]], label [[IF_END_PEEL:%.*]]
; CHECK: if.then.peel:
; CHECK-NEXT: call void @init()
; CHECK-NEXT: br label [[IF_END_PEEL]]
; CHECK: if.end.peel:
; CHECK-NEXT: call void @sink()
; CHECK-NEXT: [[INC_PEEL:%.*]] = add nuw nsw i32 0, 1
; CHECK-NEXT: [[EXITCOND_PEEL:%.*]] = icmp eq i32 [[INC_PEEL]], [[LEN]]
; CHECK-NEXT: br i1 [[EXITCOND_PEEL]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY_PEEL_NEXT:%.*]]
; CHECK: for.body.peel.next:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_NEXT1:%.*]]
; CHECK: for.body.peel.next1:
; CHECK-NEXT: br label [[FOR_BODY_PREHEADER_PEEL_NEWPH:%.*]]
; CHECK: for.body.preheader.peel.newph:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.cond.cleanup.loopexit.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT]]
; CHECK: for.cond.cleanup.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret void
; CHECK: for.body:
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[INC:%.*]], [[IF_END:%.*]] ], [ [[INC_PEEL]], [[FOR_BODY_PREHEADER_PEEL_NEWPH]] ]
; CHECK-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END]]
; CHECK: if.then:
; CHECK-NEXT: call void @init()
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: call void @sink()
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_06]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], [[LEN]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP_LOOPEXIT_LOOPEXIT:%.*]], label [[FOR_BODY]], !llvm.loop !8
;
entry:
%cmp5 = icmp sgt i32 %len, 0
br i1 %cmp5, label %for.body, label %for.cond.cleanup
for.cond.cleanup: ; preds = %if.end, %entry
ret void
for.body: ; preds = %entry, %if.end
%i.06 = phi i32 [ %inc, %if.end ], [ 0, %entry ]
%cmp1 = icmp slt i32 %i.06, 1
br i1 %cmp1, label %if.then, label %if.end
if.then: ; preds = %for.body
call void @init()
br label %if.end
if.end: ; preds = %if.then, %for.body
call void @sink()
%inc = add nuw nsw i32 %i.06, 1
%exitcond = icmp eq i32 %inc, %len
br i1 %exitcond, label %for.cond.cleanup, label %for.body
}
define void @test_10__peel_first_iter_via_sgt_pred(i32 %len) {
; CHECK-LABEL: @test_10__peel_first_iter_via_sgt_pred(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[LEN:%.*]], 0
; CHECK-NEXT: br i1 [[CMP5]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.body.preheader:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_BEGIN:%.*]]
; CHECK: for.body.peel.begin:
; CHECK-NEXT: br label [[FOR_BODY_PEEL:%.*]]
; CHECK: for.body.peel:
; CHECK-NEXT: [[CMP1_PEEL:%.*]] = icmp sgt i32 0, 0
; CHECK-NEXT: br i1 [[CMP1_PEEL]], label [[IF_END_PEEL:%.*]], label [[IF_THEN_PEEL:%.*]]
; CHECK: if.then.peel:
; CHECK-NEXT: call void @init()
; CHECK-NEXT: br label [[IF_END_PEEL]]
; CHECK: if.end.peel:
; CHECK-NEXT: call void @sink()
; CHECK-NEXT: [[INC_PEEL:%.*]] = add nuw nsw i32 0, 1
; CHECK-NEXT: [[EXITCOND_PEEL:%.*]] = icmp eq i32 [[INC_PEEL]], [[LEN]]
; CHECK-NEXT: br i1 [[EXITCOND_PEEL]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY_PEEL_NEXT:%.*]]
; CHECK: for.body.peel.next:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_NEXT1:%.*]]
; CHECK: for.body.peel.next1:
; CHECK-NEXT: br label [[FOR_BODY_PREHEADER_PEEL_NEWPH:%.*]]
; CHECK: for.body.preheader.peel.newph:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.cond.cleanup.loopexit.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT]]
; CHECK: for.cond.cleanup.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret void
; CHECK: for.body:
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[INC:%.*]], [[IF_END:%.*]] ], [ [[INC_PEEL]], [[FOR_BODY_PREHEADER_PEEL_NEWPH]] ]
; CHECK-NEXT: br i1 true, label [[IF_END]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @init()
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: call void @sink()
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_06]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], [[LEN]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP_LOOPEXIT_LOOPEXIT:%.*]], label [[FOR_BODY]], !llvm.loop !10
;
entry:
%cmp5 = icmp sgt i32 %len, 0
br i1 %cmp5, label %for.body, label %for.cond.cleanup
for.cond.cleanup: ; preds = %if.end, %entry
ret void
for.body: ; preds = %entry, %if.end
%i.06 = phi i32 [ %inc, %if.end ], [ 0, %entry ]
%cmp1 = icmp sgt i32 %i.06, 0
br i1 %cmp1, label %if.end, label %if.then
if.then: ; preds = %for.body
call void @init()
br label %if.end
if.end: ; preds = %if.then, %for.body
call void @sink()
%inc = add nuw nsw i32 %i.06, 1
%exitcond = icmp eq i32 %inc, %len
br i1 %exitcond, label %for.cond.cleanup, label %for.body
}
; NOTE: here we should only peel the first iteration,
; i.e. all calls to sink() must stay in loop.
define void @test11__peel_first_iter_via_eq_pred(i32 %len) {
; CHECK-LABEL: @test11__peel_first_iter_via_eq_pred(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[LEN:%.*]], 0
; CHECK-NEXT: br i1 [[CMP5]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.body.preheader:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_BEGIN:%.*]]
; CHECK: for.body.peel.begin:
; CHECK-NEXT: br label [[FOR_BODY_PEEL:%.*]]
; CHECK: for.body.peel:
; CHECK-NEXT: [[CMP1_PEEL:%.*]] = icmp eq i32 0, 0
; CHECK-NEXT: br i1 [[CMP1_PEEL]], label [[IF_THEN_PEEL:%.*]], label [[IF_END_PEEL:%.*]]
; CHECK: if.then.peel:
; CHECK-NEXT: call void @init()
; CHECK-NEXT: br label [[IF_END_PEEL]]
; CHECK: if.end.peel:
; CHECK-NEXT: call void @sink()
; CHECK-NEXT: [[INC_PEEL:%.*]] = add nuw nsw i32 0, 1
; CHECK-NEXT: [[EXITCOND_PEEL:%.*]] = icmp eq i32 [[INC_PEEL]], [[LEN]]
; CHECK-NEXT: br i1 [[EXITCOND_PEEL]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY_PEEL_NEXT:%.*]]
; CHECK: for.body.peel.next:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_NEXT1:%.*]]
; CHECK: for.body.peel.next1:
; CHECK-NEXT: br label [[FOR_BODY_PREHEADER_PEEL_NEWPH:%.*]]
; CHECK: for.body.preheader.peel.newph:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.cond.cleanup.loopexit.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT]]
; CHECK: for.cond.cleanup.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret void
; CHECK: for.body:
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[INC:%.*]], [[IF_END:%.*]] ], [ [[INC_PEEL]], [[FOR_BODY_PREHEADER_PEEL_NEWPH]] ]
; CHECK-NEXT: br i1 false, label [[IF_THEN:%.*]], label [[IF_END]]
; CHECK: if.then:
; CHECK-NEXT: call void @init()
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: call void @sink()
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_06]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], [[LEN]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP_LOOPEXIT_LOOPEXIT:%.*]], label [[FOR_BODY]], !llvm.loop !11
;
entry:
%cmp5 = icmp sgt i32 %len, 0
br i1 %cmp5, label %for.body, label %for.cond.cleanup
for.cond.cleanup: ; preds = %if.end, %entry
ret void
for.body: ; preds = %entry, %if.end
%i.06 = phi i32 [ %inc, %if.end ], [ 0, %entry ]
%cmp1 = icmp eq i32 %i.06, 0
br i1 %cmp1, label %if.then, label %if.end
if.then: ; preds = %for.body
call void @init()
br label %if.end
if.end: ; preds = %if.then, %for.body
call void @sink()
%inc = add nuw nsw i32 %i.06, 1
%exitcond = icmp eq i32 %inc, %len
br i1 %exitcond, label %for.cond.cleanup, label %for.body
}
; NOTE: here we should only peel the first iteration,
; i.e. all calls to sink() must stay in loop.
define void @test12__peel_first_iter_via_ne_pred(i32 %len) {
; CHECK-LABEL: @test12__peel_first_iter_via_ne_pred(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[LEN:%.*]], 0
; CHECK-NEXT: br i1 [[CMP5]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.body.preheader:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_BEGIN:%.*]]
; CHECK: for.body.peel.begin:
; CHECK-NEXT: br label [[FOR_BODY_PEEL:%.*]]
; CHECK: for.body.peel:
; CHECK-NEXT: [[CMP1_PEEL:%.*]] = icmp ne i32 0, 0
; CHECK-NEXT: br i1 [[CMP1_PEEL]], label [[IF_END_PEEL:%.*]], label [[IF_THEN_PEEL:%.*]]
; CHECK: if.then.peel:
; CHECK-NEXT: call void @init()
; CHECK-NEXT: br label [[IF_END_PEEL]]
; CHECK: if.end.peel:
; CHECK-NEXT: call void @sink()
; CHECK-NEXT: [[INC_PEEL:%.*]] = add nuw nsw i32 0, 1
; CHECK-NEXT: [[EXITCOND_PEEL:%.*]] = icmp eq i32 [[INC_PEEL]], [[LEN]]
; CHECK-NEXT: br i1 [[EXITCOND_PEEL]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY_PEEL_NEXT:%.*]]
; CHECK: for.body.peel.next:
; CHECK-NEXT: br label [[FOR_BODY_PEEL_NEXT1:%.*]]
; CHECK: for.body.peel.next1:
; CHECK-NEXT: br label [[FOR_BODY_PREHEADER_PEEL_NEWPH:%.*]]
; CHECK: for.body.preheader.peel.newph:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.cond.cleanup.loopexit.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP_LOOPEXIT]]
; CHECK: for.cond.cleanup.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret void
; CHECK: for.body:
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[INC:%.*]], [[IF_END:%.*]] ], [ [[INC_PEEL]], [[FOR_BODY_PREHEADER_PEEL_NEWPH]] ]
; CHECK-NEXT: br i1 true, label [[IF_END]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @init()
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: call void @sink()
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_06]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], [[LEN]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP_LOOPEXIT_LOOPEXIT:%.*]], label [[FOR_BODY]], !llvm.loop !12
;
entry:
%cmp5 = icmp sgt i32 %len, 0
br i1 %cmp5, label %for.body, label %for.cond.cleanup
for.cond.cleanup: ; preds = %if.end, %entry
ret void
for.body: ; preds = %entry, %if.end
%i.06 = phi i32 [ %inc, %if.end ], [ 0, %entry ]
%cmp1 = icmp ne i32 %i.06, 0
br i1 %cmp1, label %if.end, label %if.then
if.then: ; preds = %for.body
call void @init()
br label %if.end
if.end: ; preds = %if.then, %for.body
call void @sink()
%inc = add nuw nsw i32 %i.06, 1
%exitcond = icmp eq i32 %inc, %len
br i1 %exitcond, label %for.cond.cleanup, label %for.body
}
; No peeling is profitable here.
define void @test13__ivar_mod2_is_1(i32 %len) {
; CHECK-LABEL: @test13__ivar_mod2_is_1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[LEN:%.*]], 0
; CHECK-NEXT: br i1 [[CMP5]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.body.preheader:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.cond.cleanup.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret void
; CHECK: for.body:
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[INC:%.*]], [[IF_END:%.*]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I_06]], 1
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[AND]], 1
; CHECK-NEXT: br i1 [[CMP1]], label [[IF_END]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @init()
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: call void @sink()
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_06]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], [[LEN]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY]]
;
entry:
%cmp5 = icmp sgt i32 %len, 0
br i1 %cmp5, label %for.body, label %for.cond.cleanup
for.cond.cleanup: ; preds = %if.end, %entry
ret void
for.body: ; preds = %entry, %if.end
%i.06 = phi i32 [ %inc, %if.end ], [ 0, %entry ]
%and = and i32 %i.06, 1
%cmp1 = icmp eq i32 %and, 1
br i1 %cmp1, label %if.end, label %if.then
if.then: ; preds = %for.body
call void @init()
br label %if.end
if.end: ; preds = %if.then, %for.body
call void @sink()
%inc = add nuw nsw i32 %i.06, 1
%exitcond = icmp eq i32 %inc, %len
br i1 %exitcond, label %for.cond.cleanup, label %for.body
}
; No peeling is profitable here.
define void @test14__ivar_mod2_is_0(i32 %len) {
; CHECK-LABEL: @test14__ivar_mod2_is_0(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[LEN:%.*]], 0
; CHECK-NEXT: br i1 [[CMP5]], label [[FOR_BODY_PREHEADER:%.*]], label [[FOR_COND_CLEANUP:%.*]]
; CHECK: for.body.preheader:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.cond.cleanup.loopexit:
; CHECK-NEXT: br label [[FOR_COND_CLEANUP]]
; CHECK: for.cond.cleanup:
; CHECK-NEXT: ret void
; CHECK: for.body:
; CHECK-NEXT: [[I_06:%.*]] = phi i32 [ [[INC:%.*]], [[IF_END:%.*]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I_06]], 1
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[AND]], 0
; CHECK-NEXT: br i1 [[CMP1]], label [[IF_END]], label [[IF_THEN:%.*]]
; CHECK: if.then:
; CHECK-NEXT: call void @init()
; CHECK-NEXT: br label [[IF_END]]
; CHECK: if.end:
; CHECK-NEXT: call void @sink()
; CHECK-NEXT: [[INC]] = add nuw nsw i32 [[I_06]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], [[LEN]]
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP_LOOPEXIT:%.*]], label [[FOR_BODY]]
;
entry:
%cmp5 = icmp sgt i32 %len, 0
br i1 %cmp5, label %for.body, label %for.cond.cleanup
for.cond.cleanup: ; preds = %if.end, %entry
ret void
for.body: ; preds = %entry, %if.end
%i.06 = phi i32 [ %inc, %if.end ], [ 0, %entry ]
%and = and i32 %i.06, 1
%cmp1 = icmp eq i32 %and, 0
br i1 %cmp1, label %if.end, label %if.then
if.then: ; preds = %for.body
call void @init()
br label %if.end
if.end: ; preds = %if.then, %for.body
call void @sink()
%inc = add nuw nsw i32 %i.06, 1
%exitcond = icmp eq i32 %inc, %len
br i1 %exitcond, label %for.cond.cleanup, label %for.body
}
; Similar to @test6, we need to peel one extra iteration, and we can't do that
; as per the -unroll-peel-max-count=4, so this shouldn't be peeled at all.
define void @test15(i32 %k) {
; CHECK-LABEL: @test15(
; CHECK-NEXT: for.body.lr.ph:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[I_05:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i32 [[I_05]], 4
; CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN:%.*]], label [[FOR_INC]]
; CHECK: if.then:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nsw i32 [[I_05]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[K:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
for.body.lr.ph:
br label %for.body
for.body:
%i.05 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.inc ]
%cmp1 = icmp ne i32 %i.05, 4
br i1 %cmp1, label %if.then, label %for.inc
if.then:
call void @f1()
br label %for.inc
for.inc:
%inc = add nsw i32 %i.05, 1
%cmp = icmp slt i32 %inc, %k
br i1 %cmp, label %for.body, label %for.end
for.end:
ret void
}
; Similar to @test7, we need to peel one extra iteration, and we can't do that
; as per the -unroll-peel-max-count=4, so this shouldn't be peeled at all.
define void @test16(i32 %k) {
; CHECK-LABEL: @test16(
; CHECK-NEXT: for.body.lr.ph:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[I_05:%.*]] = phi i32 [ 0, [[FOR_BODY_LR_PH:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[I_05]], 4
; CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN:%.*]], label [[FOR_INC]]
; CHECK: if.then:
; CHECK-NEXT: call void @f1()
; CHECK-NEXT: br label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[INC]] = add nsw i32 [[I_05]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[INC]], [[K:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
; CHECK: for.end:
; CHECK-NEXT: ret void
;
for.body.lr.ph:
br label %for.body
for.body:
%i.05 = phi i32 [ 0, %for.body.lr.ph ], [ %inc, %for.inc ]
%cmp1 = icmp eq i32 %i.05, 4
br i1 %cmp1, label %if.then, label %for.inc
if.then:
call void @f1()
br label %for.inc
for.inc:
%inc = add nsw i32 %i.05, 1
%cmp = icmp slt i32 %inc, %k
br i1 %cmp, label %for.body, label %for.end
for.end:
ret void
}
define void @test17() personality i8* undef{
; CHECK-LABEL: @test17(
; CHECK-NEXT: body:
; CHECK-NEXT: br label [[LOOP_PEEL_BEGIN:%.*]]
; CHECK: loop.peel.begin:
; CHECK-NEXT: br label [[LOOP_PEEL:%.*]]
; CHECK: loop.peel:
; CHECK-NEXT: invoke void @f1()
; CHECK-NEXT: to label [[LOOP_PEEL_NEXT:%.*]] unwind label [[EH_UNW_LOOPEXIT_LOOPEXIT_SPLIT_LP:%.*]]
; CHECK: loop.peel.next:
; CHECK-NEXT: br label [[LOOP_PEEL_NEXT1:%.*]]
; CHECK: loop.peel.next1:
; CHECK-NEXT: br label [[BODY_PEEL_NEWPH:%.*]]
; CHECK: body.peel.newph:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: invoke void @f1()
; CHECK-NEXT: to label [[LOOP]] unwind label [[EH_UNW_LOOPEXIT_LOOPEXIT:%.*]], !llvm.loop [[LOOP13:![0-9]+]]
; CHECK: eh.Unw.loopexit.loopexit:
; CHECK-NEXT: [[LPAD_LOOPEXIT2:%.*]] = landingpad { i8*, i32 }
; CHECK-NEXT: catch i8* null
; CHECK-NEXT: br label [[EH_UNW_LOOPEXIT:%.*]]
; CHECK: eh.Unw.loopexit.loopexit.split-lp:
; CHECK-NEXT: [[LPAD_LOOPEXIT_SPLIT_LP:%.*]] = landingpad { i8*, i32 }
; CHECK-NEXT: catch i8* null
; CHECK-NEXT: br label [[EH_UNW_LOOPEXIT]]
; CHECK: eh.Unw.loopexit:
; CHECK-NEXT: ret void
;
body:
br label %loop
loop:
%const = phi i64 [ -33, %loop ], [ -20, %body ]
invoke void @f1()
to label %loop unwind label %eh.Unw.loopexit
eh.Unw.loopexit:
%lpad.loopexit = landingpad { i8*, i32 }
catch i8* null
ret void
}
; Testcase reduced from PR48812.
define void @test18(i32* %p) {
; CHECK-LABEL: @test18(
; CHECK-NEXT: init:
; CHECK-NEXT: br label [[LOOP_PEEL_BEGIN:%.*]]
; CHECK: loop.peel.begin:
; CHECK-NEXT: br label [[LOOP_PEEL:%.*]]
; CHECK: loop.peel:
; CHECK-NEXT: br label [[LATCH_PEEL:%.*]]
; CHECK: latch.peel:
; CHECK-NEXT: [[CONTROL_PEEL:%.*]] = load volatile i32, i32* [[P:%.*]], align 4
; CHECK-NEXT: switch i32 [[CONTROL_PEEL]], label [[EXIT:%.*]] [
; CHECK-NEXT: i32 2, label [[LOOP_PEEL_NEXT:%.*]]
; CHECK-NEXT: ]
; CHECK: loop.peel.next:
; CHECK-NEXT: br label [[LOOP_PEEL_NEXT1:%.*]]
; CHECK: loop.peel.next1:
; CHECK-NEXT: br label [[INIT_PEEL_NEWPH:%.*]]
; CHECK: init.peel.newph:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: br label [[LATCH:%.*]]
; CHECK: latch:
; CHECK-NEXT: [[CONTROL:%.*]] = load volatile i32, i32* [[P]], align 4
; CHECK-NEXT: switch i32 [[CONTROL]], label [[EXIT_LOOPEXIT:%.*]] [
; CHECK-NEXT: i32 2, label [[LOOP]]
; CHECK-NEXT: ], !llvm.loop [[LOOP14:![0-9]+]]
; CHECK: exit.loopexit:
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
init:
br label %loop
loop:
%const = phi i32 [ 40, %init ], [ 0, %latch ]
br label %latch
latch:
%control = load volatile i32, i32* %p
switch i32 %control, label %exit [
i32 2, label %loop
]
exit:
ret void
}
declare void @init()
declare void @sink()