| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt < %s -passes=loop-unroll -S -unroll-count=4 | FileCheck %s |
| ; Test phi update after partial unroll. |
| |
| declare i1 @check() nounwind |
| |
| define void @test1(i32 %i, i32 %j) nounwind uwtable ssp { |
| ; |
| ; CHECK-LABEL: @test1( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[COND1:%.*]] = call zeroext i1 @check() |
| ; CHECK-NEXT: br i1 [[COND1]], label [[IF_THEN:%.*]], label [[IF_ELSE_LR_PH:%.*]] |
| ; CHECK: if.else.lr.ph: |
| ; CHECK-NEXT: br label [[IF_ELSE:%.*]] |
| ; CHECK: if.else: |
| ; CHECK-NEXT: [[SUB:%.*]] = phi i32 [ [[I:%.*]], [[IF_ELSE_LR_PH]] ], [ [[SUB5_3:%.*]], [[IF_ELSE_3:%.*]] ] |
| ; CHECK-NEXT: [[SUB5:%.*]] = sub i32 [[SUB]], [[J:%.*]] |
| ; CHECK-NEXT: [[COND2:%.*]] = call zeroext i1 @check() |
| ; CHECK-NEXT: br i1 [[COND2]], label [[IF_THEN_LOOPEXIT:%.*]], label [[IF_ELSE_1:%.*]] |
| ; CHECK: if.else.1: |
| ; CHECK-NEXT: [[SUB5_1:%.*]] = sub i32 [[SUB5]], [[J]] |
| ; CHECK-NEXT: [[COND2_1:%.*]] = call zeroext i1 @check() |
| ; CHECK-NEXT: br i1 [[COND2_1]], label [[IF_THEN_LOOPEXIT]], label [[IF_ELSE_2:%.*]] |
| ; CHECK: if.else.2: |
| ; CHECK-NEXT: [[SUB5_2:%.*]] = sub i32 [[SUB5_1]], [[J]] |
| ; CHECK-NEXT: [[COND2_2:%.*]] = call zeroext i1 @check() |
| ; CHECK-NEXT: br i1 [[COND2_2]], label [[IF_THEN_LOOPEXIT]], label [[IF_ELSE_3]] |
| ; CHECK: if.else.3: |
| ; CHECK-NEXT: [[SUB5_3]] = sub i32 [[SUB5_2]], [[J]] |
| ; CHECK-NEXT: [[COND2_3:%.*]] = call zeroext i1 @check() |
| ; CHECK-NEXT: br i1 [[COND2_3]], label [[IF_THEN_LOOPEXIT]], label [[IF_ELSE]], !llvm.loop [[LOOP0:![0-9]+]] |
| ; CHECK: if.then.loopexit: |
| ; CHECK-NEXT: [[SUB5_LCSSA:%.*]] = phi i32 [ [[SUB5]], [[IF_ELSE]] ], [ [[SUB5_1]], [[IF_ELSE_1]] ], [ [[SUB5_2]], [[IF_ELSE_2]] ], [ [[SUB5_3]], [[IF_ELSE_3]] ] |
| ; CHECK-NEXT: br label [[IF_THEN]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[I_TR:%.*]] = phi i32 [ [[I]], [[ENTRY:%.*]] ], [ [[SUB5_LCSSA]], [[IF_THEN_LOOPEXIT]] ] |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %cond1 = call zeroext i1 @check() |
| br i1 %cond1, label %if.then, label %if.else.lr.ph |
| |
| if.else.lr.ph: ; preds = %entry |
| br label %if.else |
| |
| if.else: ; preds = %if.else, %if.else.lr.ph |
| %sub = phi i32 [ %i, %if.else.lr.ph ], [ %sub5, %if.else ] |
| %sub5 = sub i32 %sub, %j |
| %cond2 = call zeroext i1 @check() |
| br i1 %cond2, label %if.then, label %if.else |
| |
| if.then: ; preds = %if.else, %entry |
| %i.tr = phi i32 [ %i, %entry ], [ %sub5, %if.else ] |
| ret void |
| |
| } |
| |
| ; PR7318: assertion failure after doing a simple loop unroll |
| ; |
| define i32 @test2(ptr nocapture %p, i32 %n) nounwind readonly { |
| ; |
| ; CHECK-LABEL: @test2( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[N:%.*]], 0 |
| ; CHECK-NEXT: br i1 [[TMP0]], label [[BB_NPH:%.*]], label [[BB2:%.*]] |
| ; CHECK: bb.nph: |
| ; CHECK-NEXT: [[TMP:%.*]] = zext i32 [[N]] to i64 |
| ; CHECK-NEXT: br label [[BB:%.*]] |
| ; CHECK: bb: |
| ; CHECK-NEXT: [[INDVAR:%.*]] = phi i64 [ 0, [[BB_NPH]] ], [ [[INDVAR_NEXT_3:%.*]], [[BB1_3:%.*]] ] |
| ; CHECK-NEXT: [[S_01:%.*]] = phi i32 [ 0, [[BB_NPH]] ], [ [[TMP8:%.*]], [[BB1_3]] ] |
| ; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[INDVAR]] |
| ; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[SCEVGEP]], align 1 |
| ; CHECK-NEXT: [[TMP2:%.*]] = add nsw i32 [[TMP1]], [[S_01]] |
| ; CHECK-NEXT: br label [[BB1:%.*]] |
| ; CHECK: bb1: |
| ; CHECK-NEXT: [[INDVAR_NEXT:%.*]] = add nuw nsw i64 [[INDVAR]], 1 |
| ; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDVAR_NEXT]], [[TMP]] |
| ; CHECK-NEXT: br i1 [[EXITCOND]], label [[BB_1:%.*]], label [[BB1_BB2_CRIT_EDGE:%.*]] |
| ; CHECK: bb.1: |
| ; CHECK-NEXT: [[SCEVGEP_1:%.*]] = getelementptr i32, ptr [[P]], i64 [[INDVAR_NEXT]] |
| ; CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[SCEVGEP_1]], align 1 |
| ; CHECK-NEXT: [[TMP4:%.*]] = add nsw i32 [[TMP3]], [[TMP2]] |
| ; CHECK-NEXT: br label [[BB1_1:%.*]] |
| ; CHECK: bb1.1: |
| ; CHECK-NEXT: [[INDVAR_NEXT_1:%.*]] = add nuw nsw i64 [[INDVAR]], 2 |
| ; CHECK-NEXT: [[EXITCOND_1:%.*]] = icmp ne i64 [[INDVAR_NEXT_1]], [[TMP]] |
| ; CHECK-NEXT: br i1 [[EXITCOND_1]], label [[BB_2:%.*]], label [[BB1_BB2_CRIT_EDGE]] |
| ; CHECK: bb.2: |
| ; CHECK-NEXT: [[SCEVGEP_2:%.*]] = getelementptr i32, ptr [[P]], i64 [[INDVAR_NEXT_1]] |
| ; CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[SCEVGEP_2]], align 1 |
| ; CHECK-NEXT: [[TMP6:%.*]] = add nsw i32 [[TMP5]], [[TMP4]] |
| ; CHECK-NEXT: br label [[BB1_2:%.*]] |
| ; CHECK: bb1.2: |
| ; CHECK-NEXT: [[INDVAR_NEXT_2:%.*]] = add nuw nsw i64 [[INDVAR]], 3 |
| ; CHECK-NEXT: [[EXITCOND_2:%.*]] = icmp ne i64 [[INDVAR_NEXT_2]], [[TMP]] |
| ; CHECK-NEXT: br i1 [[EXITCOND_2]], label [[BB_3:%.*]], label [[BB1_BB2_CRIT_EDGE]] |
| ; CHECK: bb.3: |
| ; CHECK-NEXT: [[SCEVGEP_3:%.*]] = getelementptr i32, ptr [[P]], i64 [[INDVAR_NEXT_2]] |
| ; CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[SCEVGEP_3]], align 1 |
| ; CHECK-NEXT: [[TMP8]] = add nsw i32 [[TMP7]], [[TMP6]] |
| ; CHECK-NEXT: br label [[BB1_3]] |
| ; CHECK: bb1.3: |
| ; CHECK-NEXT: [[INDVAR_NEXT_3]] = add i64 [[INDVAR]], 4 |
| ; CHECK-NEXT: [[EXITCOND_3:%.*]] = icmp ne i64 [[INDVAR_NEXT_3]], [[TMP]] |
| ; CHECK-NEXT: br i1 [[EXITCOND_3]], label [[BB]], label [[BB1_BB2_CRIT_EDGE]], !llvm.loop [[LOOP2:![0-9]+]] |
| ; CHECK: bb1.bb2_crit_edge: |
| ; CHECK-NEXT: [[DOTLCSSA:%.*]] = phi i32 [ [[TMP2]], [[BB1]] ], [ [[TMP4]], [[BB1_1]] ], [ [[TMP6]], [[BB1_2]] ], [ [[TMP8]], [[BB1_3]] ] |
| ; CHECK-NEXT: br label [[BB2]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: [[S_0_LCSSA:%.*]] = phi i32 [ [[DOTLCSSA]], [[BB1_BB2_CRIT_EDGE]] ], [ 0, [[ENTRY:%.*]] ] |
| ; CHECK-NEXT: ret i32 [[S_0_LCSSA]] |
| ; |
| entry: |
| %0 = icmp sgt i32 %n, 0 ; <i1> [#uses=1] |
| br i1 %0, label %bb.nph, label %bb2 |
| |
| bb.nph: ; preds = %entry |
| %tmp = zext i32 %n to i64 ; <i64> [#uses=1] |
| br label %bb |
| |
| bb: ; preds = %bb.nph, %bb1 |
| %indvar = phi i64 [ 0, %bb.nph ], [ %indvar.next, %bb1 ] ; <i64> [#uses=2] |
| %s.01 = phi i32 [ 0, %bb.nph ], [ %2, %bb1 ] ; <i32> [#uses=1] |
| %scevgep = getelementptr i32, ptr %p, i64 %indvar ; <ptr> [#uses=1] |
| %1 = load i32, ptr %scevgep, align 1 ; <i32> [#uses=1] |
| %2 = add nsw i32 %1, %s.01 ; <i32> [#uses=2] |
| br label %bb1 |
| |
| bb1: ; preds = %bb |
| %indvar.next = add i64 %indvar, 1 ; <i64> [#uses=2] |
| %exitcond = icmp ne i64 %indvar.next, %tmp ; <i1> [#uses=1] |
| br i1 %exitcond, label %bb, label %bb1.bb2_crit_edge |
| |
| bb1.bb2_crit_edge: ; preds = %bb1 |
| %.lcssa = phi i32 [ %2, %bb1 ] ; <i32> [#uses=1] |
| br label %bb2 |
| |
| bb2: ; preds = %bb1.bb2_crit_edge, %entry |
| %s.0.lcssa = phi i32 [ %.lcssa, %bb1.bb2_crit_edge ], [ 0, %entry ] ; <i32> [#uses=1] |
| ret i32 %s.0.lcssa |
| } |
| |
| ; Check phi update for loop with an early-exit. |
| ; |
| define i32 @test3() nounwind uwtable ssp align 2 { |
| ; |
| ; CHECK-LABEL: @test3( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[COND1:%.*]] = call zeroext i1 @check() |
| ; CHECK-NEXT: br i1 [[COND1]], label [[RETURN:%.*]], label [[IF_END:%.*]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: br label [[DO_BODY:%.*]] |
| ; CHECK: do.body: |
| ; CHECK-NEXT: [[COND2:%.*]] = call zeroext i1 @check() |
| ; CHECK-NEXT: br i1 [[COND2]], label [[EXIT:%.*]], label [[DO_COND:%.*]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: [[TMP7_I:%.*]] = load i32, ptr undef, align 8 |
| ; CHECK-NEXT: br i1 undef, label [[DO_COND]], label [[LAND_LHS_TRUE:%.*]] |
| ; CHECK: land.lhs.true: |
| ; CHECK-NEXT: br i1 true, label [[RETURN_LOOPEXIT:%.*]], label [[DO_COND]] |
| ; CHECK: do.cond: |
| ; CHECK-NEXT: [[COND3:%.*]] = call zeroext i1 @check() |
| ; CHECK-NEXT: br i1 [[COND3]], label [[DO_END:%.*]], label [[DO_BODY_1:%.*]] |
| ; CHECK: do.body.1: |
| ; CHECK-NEXT: [[COND2_1:%.*]] = call zeroext i1 @check() |
| ; CHECK-NEXT: br i1 [[COND2_1]], label [[EXIT_1:%.*]], label [[DO_COND_1:%.*]] |
| ; CHECK: exit.1: |
| ; CHECK-NEXT: [[TMP7_I_1:%.*]] = load i32, ptr undef, align 8 |
| ; CHECK-NEXT: br i1 undef, label [[DO_COND_1]], label [[LAND_LHS_TRUE_1:%.*]] |
| ; CHECK: land.lhs.true.1: |
| ; CHECK-NEXT: br i1 true, label [[RETURN_LOOPEXIT]], label [[DO_COND_1]] |
| ; CHECK: do.cond.1: |
| ; CHECK-NEXT: [[COND3_1:%.*]] = call zeroext i1 @check() |
| ; CHECK-NEXT: br i1 [[COND3_1]], label [[DO_END]], label [[DO_BODY_2:%.*]] |
| ; CHECK: do.body.2: |
| ; CHECK-NEXT: [[COND2_2:%.*]] = call zeroext i1 @check() |
| ; CHECK-NEXT: br i1 [[COND2_2]], label [[EXIT_2:%.*]], label [[DO_COND_2:%.*]] |
| ; CHECK: exit.2: |
| ; CHECK-NEXT: [[TMP7_I_2:%.*]] = load i32, ptr undef, align 8 |
| ; CHECK-NEXT: br i1 undef, label [[DO_COND_2]], label [[LAND_LHS_TRUE_2:%.*]] |
| ; CHECK: land.lhs.true.2: |
| ; CHECK-NEXT: br i1 true, label [[RETURN_LOOPEXIT]], label [[DO_COND_2]] |
| ; CHECK: do.cond.2: |
| ; CHECK-NEXT: [[COND3_2:%.*]] = call zeroext i1 @check() |
| ; CHECK-NEXT: br i1 [[COND3_2]], label [[DO_END]], label [[DO_BODY_3:%.*]] |
| ; CHECK: do.body.3: |
| ; CHECK-NEXT: [[COND2_3:%.*]] = call zeroext i1 @check() |
| ; CHECK-NEXT: br i1 [[COND2_3]], label [[EXIT_3:%.*]], label [[DO_COND_3:%.*]] |
| ; CHECK: exit.3: |
| ; CHECK-NEXT: [[TMP7_I_3:%.*]] = load i32, ptr undef, align 8 |
| ; CHECK-NEXT: br i1 undef, label [[DO_COND_3]], label [[LAND_LHS_TRUE_3:%.*]] |
| ; CHECK: land.lhs.true.3: |
| ; CHECK-NEXT: br i1 true, label [[RETURN_LOOPEXIT]], label [[DO_COND_3]] |
| ; CHECK: do.cond.3: |
| ; CHECK-NEXT: [[COND3_3:%.*]] = call zeroext i1 @check() |
| ; CHECK-NEXT: br i1 [[COND3_3]], label [[DO_END]], label [[DO_BODY]], !llvm.loop [[LOOP3:![0-9]+]] |
| ; CHECK: do.end: |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: return.loopexit: |
| ; CHECK-NEXT: [[TMP7_I_LCSSA:%.*]] = phi i32 [ [[TMP7_I]], [[LAND_LHS_TRUE]] ], [ [[TMP7_I_1]], [[LAND_LHS_TRUE_1]] ], [ [[TMP7_I_2]], [[LAND_LHS_TRUE_2]] ], [ [[TMP7_I_3]], [[LAND_LHS_TRUE_3]] ] |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: return: |
| ; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i32 [ 0, [[DO_END]] ], [ 0, [[ENTRY:%.*]] ], [ [[TMP7_I_LCSSA]], [[RETURN_LOOPEXIT]] ] |
| ; CHECK-NEXT: ret i32 [[RETVAL_0]] |
| ; |
| entry: |
| %cond1 = call zeroext i1 @check() |
| br i1 %cond1, label %return, label %if.end |
| |
| if.end: ; preds = %entry |
| br label %do.body |
| |
| do.body: ; preds = %do.cond, %if.end |
| %cond2 = call zeroext i1 @check() |
| br i1 %cond2, label %exit, label %do.cond |
| |
| exit: ; preds = %do.body |
| %tmp7.i = load i32, ptr undef, align 8 |
| br i1 undef, label %do.cond, label %land.lhs.true |
| |
| land.lhs.true: ; preds = %exit |
| br i1 undef, label %return, label %do.cond |
| |
| do.cond: ; preds = %land.lhs.true, %exit, %do.body |
| %cond3 = call zeroext i1 @check() |
| br i1 %cond3, label %do.end, label %do.body |
| |
| do.end: ; preds = %do.cond |
| br label %return |
| |
| return: ; preds = %do.end, %land.lhs.true, %entry |
| %retval.0 = phi i32 [ 0, %do.end ], [ 0, %entry ], [ %tmp7.i, %land.lhs.true ] |
| ret i32 %retval.0 |
| } |