diff --git a/llvm/test/Transforms/LoopUnroll/nonlatchcondbr.ll b/llvm/test/Transforms/LoopUnroll/nonlatchcondbr.ll --- a/llvm/test/Transforms/LoopUnroll/nonlatchcondbr.ll +++ b/llvm/test/Transforms/LoopUnroll/nonlatchcondbr.ll @@ -1,9 +1,12 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt < %s -loop-unroll -S | FileCheck %s -; RUN: opt < %s -passes='require,unroll' -S | FileCheck %s +; RUN: opt < %s -loop-unroll -unroll-runtime -unroll-count=4 -S | FileCheck %s +; RUN: opt < %s -passes='require,unroll' -unroll-runtime -unroll-count=4 -S | FileCheck %s -define void @foo(i32* noalias %A) { -; CHECK-LABEL: @foo( +; Check that loop unroll pass correctly handle loops with +; single exiting block not the loop header or latch. + +define void @test1(i32* noalias %A) { +; CHECK-LABEL: @test1( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[A:%.*]], align 4 ; CHECK-NEXT: call void @bar(i32 [[TMP0]]) @@ -66,4 +69,91 @@ ret void } +; Check that loop unroll pass correctly handle loops with +; (1) exiting block not dominating the loop latch; and +; (2) exiting terminator instructions cannot be simplified to unconditional. + +define void @test2(i32* noalias %A) { +; CHECK-LABEL: @test2( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 true, label [[FOR_PREHEADER:%.*]], label [[FOR_END:%.*]] +; CHECK: for.preheader: +; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[A:%.*]], align 4 +; CHECK-NEXT: call void @bar(i32 [[TMP0]]) +; CHECK-NEXT: br label [[FOR_HEADER:%.*]] +; CHECK: for.header: +; CHECK-NEXT: [[TMP1:%.*]] = phi i32 [ [[TMP0]], [[FOR_PREHEADER]] ], [ [[DOTPRE_3:%.*]], [[FOR_BODY_FOR_BODY_CRIT_EDGE_3:%.*]] ] +; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, [[FOR_PREHEADER]] ], [ [[INC_3:%.*]], [[FOR_BODY_FOR_BODY_CRIT_EDGE_3]] ] +; CHECK-NEXT: call void @bar(i32 [[TMP1]]) +; CHECK-NEXT: [[INC:%.*]] = add nuw nsw i64 [[I]], 1 +; CHECK-NEXT: br i1 true, label [[FOR_BODY:%.*]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE:%.*]] +; CHECK: for.body: +; CHECK-NEXT: [[CMP:%.*]] = call i1 @foo(i64 [[I]]) +; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE]], label [[FOR_END_LOOPEXIT:%.*]] +; CHECK: for.body.for.body_crit_edge: +; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC]] +; CHECK-NEXT: [[DOTPRE:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT]], align 4 +; CHECK-NEXT: call void @bar(i32 [[DOTPRE]]) +; CHECK-NEXT: [[INC_1:%.*]] = add nuw nsw i64 [[INC]], 1 +; CHECK-NEXT: br i1 true, label [[FOR_BODY_1:%.*]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_1:%.*]] +; CHECK: for.end.loopexit: +; CHECK-NEXT: br label [[FOR_END]] +; CHECK: for.end: +; CHECK-NEXT: ret void +; CHECK: for.body.1: +; CHECK-NEXT: [[CMP_1:%.*]] = call i1 @foo(i64 [[INC]]) +; CHECK-NEXT: br i1 [[CMP_1]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_1]], label [[FOR_END_LOOPEXIT]] +; CHECK: for.body.for.body_crit_edge.1: +; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_1:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC_1]] +; CHECK-NEXT: [[DOTPRE_1:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_1]], align 4 +; CHECK-NEXT: call void @bar(i32 [[DOTPRE_1]]) +; CHECK-NEXT: [[INC_2:%.*]] = add nuw nsw i64 [[INC_1]], 1 +; CHECK-NEXT: br i1 true, label [[FOR_BODY_2:%.*]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_2:%.*]] +; CHECK: for.body.2: +; CHECK-NEXT: [[CMP_2:%.*]] = call i1 @foo(i64 [[INC_1]]) +; CHECK-NEXT: br i1 [[CMP_2]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_2]], label [[FOR_END_LOOPEXIT]] +; CHECK: for.body.for.body_crit_edge.2: +; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_2:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC_2]] +; CHECK-NEXT: [[DOTPRE_2:%.*]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_2]], align 4 +; CHECK-NEXT: call void @bar(i32 [[DOTPRE_2]]) +; CHECK-NEXT: [[INC_3]] = add nsw i64 [[INC_2]], 1 +; CHECK-NEXT: br i1 true, label [[FOR_BODY_3:%.*]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_3]] +; CHECK: for.body.3: +; CHECK-NEXT: [[CMP_3:%.*]] = call i1 @foo(i64 [[INC_2]]) +; CHECK-NEXT: br i1 [[CMP_3]], label [[FOR_BODY_FOR_BODY_CRIT_EDGE_3]], label [[FOR_END_LOOPEXIT]] +; CHECK: for.body.for.body_crit_edge.3: +; CHECK-NEXT: [[ARRAYIDX_PHI_TRANS_INSERT_3:%.*]] = getelementptr inbounds i32, i32* [[A]], i64 [[INC_3]] +; CHECK-NEXT: [[DOTPRE_3]] = load i32, i32* [[ARRAYIDX_PHI_TRANS_INSERT_3]], align 4 +; CHECK-NEXT: br label [[FOR_HEADER]], !llvm.loop !0 +; +entry: + br i1 true, label %for.preheader, label %for.end + +for.preheader: + %0 = load i32, i32* %A, align 4 + call void @bar(i32 %0) + br label %for.header + +for.header: + %1 = phi i32 [ %0, %for.preheader ], [ %.pre, %for.body.for.body_crit_edge ] + %i = phi i64 [ 0, %for.preheader ], [ %inc, %for.body.for.body_crit_edge ] + %arrayidx = getelementptr inbounds i32, i32* %A, i64 %i + call void @bar(i32 %1) + %inc = add nsw i64 %i, 1 + br i1 true, label %for.body, label %for.body.for.body_crit_edge + +for.body: + %cmp = call i1 @foo(i64 %i) + br i1 %cmp, label %for.body.for.body_crit_edge, label %for.end + +for.body.for.body_crit_edge: + %arrayidx.phi.trans.insert = getelementptr inbounds i32, i32* %A, i64 %inc + %.pre = load i32, i32* %arrayidx.phi.trans.insert, align 4 + br label %for.header + +for.end: + ret void +} + declare void @bar(i32) +declare i1 @foo(i64)