| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| ; RUN: opt -passes=loop-unroll -S %s -verify-loop-info -verify-dom-info -verify-loop-lcssa | FileCheck %s |
| |
| %struct.spam = type { double, double, double, double, double, double, double } |
| |
| define void @test2(ptr %arg, ptr %out) { |
| ; CHECK-LABEL: @test2( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[FOR_HEADER:%.*]] |
| ; CHECK: for.header: |
| ; CHECK-NEXT: store i32 0, ptr [[ARG:%.*]], align 4 |
| ; CHECK-NEXT: br label [[FOR_LATCH:%.*]] |
| ; CHECK: for.latch: |
| ; CHECK-NEXT: store volatile i64 0, ptr [[OUT:%.*]], align 4 |
| ; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 1 |
| ; CHECK-NEXT: store i32 0, ptr [[PTR_1]], align 4 |
| ; CHECK-NEXT: br label [[FOR_LATCH_1:%.*]] |
| ; CHECK: for.latch.1: |
| ; CHECK-NEXT: store volatile i64 1, ptr [[OUT]], align 4 |
| ; CHECK-NEXT: [[PTR_2:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 2 |
| ; CHECK-NEXT: store i32 0, ptr [[PTR_2]], align 4 |
| ; CHECK-NEXT: br label [[FOR_LATCH_2:%.*]] |
| ; CHECK: for.latch.2: |
| ; CHECK-NEXT: store volatile i64 2, ptr [[OUT]], align 4 |
| ; CHECK-NEXT: [[PTR_3:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 3 |
| ; CHECK-NEXT: store i32 0, ptr [[PTR_3]], align 4 |
| ; CHECK-NEXT: br i1 true, label [[IF_END_LOOPEXIT:%.*]], label [[FOR_LATCH_3:%.*]] |
| ; CHECK: for.latch.3: |
| ; CHECK-NEXT: store volatile i64 3, ptr [[OUT]], align 4 |
| ; CHECK-NEXT: unreachable |
| ; CHECK: if.end.loopexit: |
| ; CHECK-NEXT: ret void |
| ; |
| |
| entry: |
| br label %for.header |
| |
| for.header: ; preds = %for.latch, %entry |
| %indvars.iv800 = phi i64 [ 0, %entry ], [ %indvars.iv.next801, %for.latch ] |
| %ptr = getelementptr inbounds i32, ptr %arg, i64 %indvars.iv800 |
| store i32 0, ptr %ptr, align 4 |
| %indvars.iv.next801 = add nuw nsw i64 %indvars.iv800, 1 |
| %exitcond802 = icmp eq i64 %indvars.iv.next801, 4 |
| br i1 %exitcond802, label %if.end.loopexit, label %for.latch |
| |
| for.latch: ; preds = %for.header |
| store volatile i64 %indvars.iv800, ptr %out |
| br label %for.header |
| |
| if.end.loopexit: ; preds = %for.header |
| ret void |
| } |
| |
| define double @test_with_lcssa(double %arg1, ptr %arg2) { |
| ; CHECK-LABEL: @test_with_lcssa( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[LOOP_HEADER:%.*]] |
| ; CHECK: loop.header: |
| ; CHECK-NEXT: [[RES:%.*]] = fsub double [[ARG1:%.*]], 3.000000e+00 |
| ; CHECK-NEXT: br label [[LOOP_LATCH:%.*]] |
| ; CHECK: loop.latch: |
| ; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds double, ptr [[ARG2:%.*]], i64 1 |
| ; CHECK-NEXT: [[LV:%.*]] = load double, ptr [[PTR]], align 8 |
| ; CHECK-NEXT: [[RES_1:%.*]] = fsub double [[LV]], [[RES]] |
| ; CHECK-NEXT: br i1 true, label [[LOOP_EXIT:%.*]], label [[LOOP_LATCH_1:%.*]] |
| ; CHECK: loop.latch.1: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: loop.exit: |
| ; CHECK-NEXT: [[RES_LCSSA:%.*]] = phi double [ [[RES_1]], [[LOOP_LATCH]] ] |
| ; CHECK-NEXT: ret double [[RES_LCSSA]] |
| ; |
| |
| entry: |
| br label %loop.header |
| |
| loop.header: ; preds = %entry, %loop.latch |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ] |
| %d1 = phi double [ %arg1, %entry ], [ %lv, %loop.latch ] |
| %d2 = phi double [ 3.0, %entry ], [ %res, %loop.latch ] |
| %res = fsub double %d1, %d2 |
| %iv.next = add nuw nsw i64 %iv, 1 |
| %cond = icmp eq i64 %iv.next, 2 |
| br i1 %cond, label %loop.exit, label %loop.latch |
| |
| loop.latch: ; preds = %bb366 |
| %ptr = getelementptr inbounds double, ptr %arg2, i64 %iv.next |
| %lv = load double, ptr %ptr, align 8 |
| br label %loop.header |
| |
| loop.exit: ; preds = %bb366 |
| %res.lcssa = phi double [ %res, %loop.header ] |
| ret double %res.lcssa |
| } |
| |
| ; We unroll the outer loop and need to preserve LI for the inner loop. |
| define void @test_with_nested_loop(ptr %arg) { |
| ; CHECK-LABEL: @test_with_nested_loop( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[OUTER_HEADER:%.*]] |
| ; CHECK: outer.header: |
| ; CHECK-NEXT: br label [[INNER_BODY_PREHEADER:%.*]] |
| ; CHECK: inner.body.preheader: |
| ; CHECK-NEXT: br label [[INNER_BODY:%.*]] |
| ; CHECK: inner.body: |
| ; CHECK-NEXT: [[J_IV:%.*]] = phi i64 [ [[J_IV_NEXT:%.*]], [[INNER_BODY]] ], [ 0, [[INNER_BODY_PREHEADER]] ] |
| ; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i32, ptr [[ARG:%.*]], i64 [[J_IV]] |
| ; CHECK-NEXT: store i32 0, ptr [[PTR]], align 4 |
| ; CHECK-NEXT: [[J_IV_NEXT]] = add nuw nsw i64 [[J_IV]], 1 |
| ; CHECK-NEXT: [[INNER_COND:%.*]] = icmp eq i64 [[J_IV_NEXT]], 40000 |
| ; CHECK-NEXT: br i1 [[INNER_COND]], label [[OUTER_LATCH:%.*]], label [[INNER_BODY]] |
| ; CHECK: outer.latch: |
| ; CHECK-NEXT: br label [[INNER_BODY_PREHEADER_1:%.*]] |
| ; CHECK: inner.body.preheader.1: |
| ; CHECK-NEXT: br label [[INNER_BODY_1:%.*]] |
| ; CHECK: inner.body.1: |
| ; CHECK-NEXT: [[J_IV_1:%.*]] = phi i64 [ [[J_IV_NEXT_1:%.*]], [[INNER_BODY_1]] ], [ 0, [[INNER_BODY_PREHEADER_1]] ] |
| ; CHECK-NEXT: [[IDX_1:%.*]] = add i64 1, [[J_IV_1]] |
| ; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 [[IDX_1]] |
| ; CHECK-NEXT: store i32 0, ptr [[PTR_1]], align 4 |
| ; CHECK-NEXT: [[J_IV_NEXT_1]] = add nuw nsw i64 [[J_IV_1]], 1 |
| ; CHECK-NEXT: [[INNER_COND_1:%.*]] = icmp eq i64 [[J_IV_NEXT_1]], 40000 |
| ; CHECK-NEXT: br i1 [[INNER_COND_1]], label [[OUTER_LATCH_1:%.*]], label [[INNER_BODY_1]] |
| ; CHECK: outer.latch.1: |
| ; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[INNER_BODY_PREHEADER_2:%.*]] |
| ; CHECK: inner.body.preheader.2: |
| ; CHECK-NEXT: br label [[INNER_BODY_2:%.*]] |
| ; CHECK: inner.body.2: |
| ; CHECK-NEXT: [[J_IV_2:%.*]] = phi i64 [ [[J_IV_NEXT_2:%.*]], [[INNER_BODY_2]] ], [ 0, [[INNER_BODY_PREHEADER_2]] ] |
| ; CHECK-NEXT: [[IDX_2:%.*]] = add i64 2, [[J_IV_2]] |
| ; CHECK-NEXT: [[PTR_2:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 [[IDX_2]] |
| ; CHECK-NEXT: store i32 0, ptr [[PTR_2]], align 4 |
| ; CHECK-NEXT: [[J_IV_NEXT_2]] = add nuw nsw i64 [[J_IV_2]], 1 |
| ; CHECK-NEXT: [[INNER_COND_2:%.*]] = icmp eq i64 [[J_IV_NEXT_2]], 40000 |
| ; CHECK-NEXT: br i1 [[INNER_COND_2]], label [[OUTER_LATCH_2:%.*]], label [[INNER_BODY_2]] |
| ; CHECK: outer.latch.2: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| |
| entry: |
| br label %outer.header |
| |
| outer.header: ; preds = %outer.latch, %entry |
| %outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %outer.latch ] |
| %outer.iv.next = add nuw nsw i64 %outer.iv, 1 |
| %outer.cond = icmp eq i64 %outer.iv, 2 |
| br i1 %outer.cond, label %exit, label %inner.body |
| |
| inner.body: |
| %j.iv = phi i64 [ 0, %outer.header ], [ %j.iv.next, %inner.body ] |
| %idx = add i64 %outer.iv, %j.iv |
| %ptr = getelementptr inbounds i32, ptr %arg, i64 %idx |
| store i32 0, ptr %ptr, align 4 |
| %j.iv.next = add nuw nsw i64 %j.iv, 1 |
| %inner.cond = icmp eq i64 %j.iv.next, 40000 |
| br i1 %inner.cond, label %outer.latch, label %inner.body |
| |
| outer.latch: ; preds = %inner.body |
| br label %outer.header |
| |
| exit: ; preds = %outer.header |
| ret void |
| } |
| |
| ; We unroll the inner loop and need to preserve LI for the outer loop. |
| define void @test_with_nested_loop_unroll_inner(ptr %arg) { |
| ; CHECK-LABEL: @test_with_nested_loop_unroll_inner( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[OUTER_HEADER:%.*]] |
| ; CHECK: outer.header: |
| ; CHECK-NEXT: [[OUTER_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[OUTER_IV_NEXT:%.*]], [[INNER_BODY:%.*]] ] |
| ; CHECK-NEXT: [[OUTER_IV_NEXT]] = add nuw nsw i64 [[OUTER_IV]], 1 |
| ; CHECK-NEXT: [[OUTER_COND:%.*]] = icmp eq i64 [[OUTER_IV]], 40000 |
| ; CHECK-NEXT: br i1 [[OUTER_COND]], label [[EXIT:%.*]], label [[INNER_BODY_PREHEADER:%.*]] |
| ; CHECK: inner.body.preheader: |
| ; CHECK-NEXT: br label [[INNER_BODY]] |
| ; CHECK: inner.body: |
| ; CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds i32, ptr [[ARG:%.*]], i64 [[OUTER_IV]] |
| ; CHECK-NEXT: store i32 0, ptr [[PTR]], align 4 |
| ; CHECK-NEXT: [[IDX_1:%.*]] = add i64 [[OUTER_IV]], 1 |
| ; CHECK-NEXT: [[PTR_1:%.*]] = getelementptr inbounds i32, ptr [[ARG]], i64 [[IDX_1]] |
| ; CHECK-NEXT: store i32 0, ptr [[PTR_1]], align 4 |
| ; CHECK-NEXT: br label [[OUTER_HEADER]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| |
| entry: |
| br label %outer.header |
| |
| outer.header: ; preds = %outer.latch, %entry |
| %outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %outer.latch ] |
| %outer.iv.next = add nuw nsw i64 %outer.iv, 1 |
| %outer.cond = icmp eq i64 %outer.iv, 40000 |
| br i1 %outer.cond, label %exit, label %inner.body |
| |
| inner.body: |
| %j.iv = phi i64 [ 0, %outer.header ], [ %j.iv.next, %inner.body ] |
| %idx = add i64 %outer.iv, %j.iv |
| %ptr = getelementptr inbounds i32, ptr %arg, i64 %idx |
| store i32 0, ptr %ptr, align 4 |
| %j.iv.next = add nuw nsw i64 %j.iv, 1 |
| %inner.cond = icmp eq i64 %j.iv.next, 2 |
| br i1 %inner.cond, label %outer.latch, label %inner.body |
| |
| outer.latch: ; preds = %inner.body |
| br label %outer.header |
| |
| exit: ; preds = %outer.header |
| ret void |
| } |
| |
| |
| |
| ; Check that we do not crash for headers with non-branch instructions, e.g. |
| ; switch. We do not unroll in those cases. |
| define void @test_switchinst_in_header() { |
| ; CHECK-LABEL: @test_switchinst_in_header( |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: br label [[WHILE_HEADER:%.*]] |
| ; CHECK: while.header: |
| ; CHECK-NEXT: switch i32 undef, label [[EXIT:%.*]] [ |
| ; CHECK-NEXT: i32 11, label [[WHILE_BODY1:%.*]] |
| ; CHECK-NEXT: i32 5, label [[WHILE_BODY2:%.*]] |
| ; CHECK-NEXT: ] |
| ; CHECK: while.body1: |
| ; CHECK-NEXT: unreachable |
| ; CHECK: while.body2: |
| ; CHECK-NEXT: br label [[WHILE_LATCH:%.*]] |
| ; CHECK: while.latch: |
| ; CHECK-NEXT: br label [[WHILE_HEADER]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| |
| entry: |
| br label %while.header |
| |
| while.header: ; preds = %while.latch, %entry |
| switch i32 undef, label %exit [ |
| i32 11, label %while.body1 |
| i32 5, label %while.body2 |
| ] |
| |
| while.body1: ; preds = %while.header |
| unreachable |
| |
| while.body2: ; preds = %while.header |
| br label %while.latch |
| |
| while.latch: ; preds = %while.body2 |
| br label %while.header |
| |
| exit: ; preds = %while.header |
| ret void |
| } |