| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals none --version 6 | |
| ; Runtime/partial unrolling and peeling are suppressed for loops whose outermost | |
| ; nest contains more than -unroll-max-nest-loops loops, since each such | |
| ; transform forces a whole-nest SCEV invalidation (quadratic compile time) with | |
| ; little benefit. The default limit is 128, so ordinary small nests are | |
| ; unaffected, and an explicit unroll pragma still forces unrolling over the | |
| ; limit. | |
| ; | |
| ; RUN: opt < %s -S -passes=loop-unroll -unroll-runtime=true \ | |
| ; RUN: -unroll-max-nest-loops=0 | FileCheck %s -check-prefix=UNROLL | |
| ; RUN: opt < %s -S -passes=loop-unroll -unroll-runtime=true \ | |
| ; RUN: -unroll-max-nest-loops=1 | FileCheck %s -check-prefix=CAPPED | |
| ; RUN: opt < %s -S -passes=loop-unroll -unroll-runtime=true \ | |
| ; RUN: | FileCheck %s -check-prefix=DEFAULT | |
| target datalayout = "e-p:64:64:64-i64:64:64-n8:16:32:64-S128" | |
| ; A plain two-loop nest whose inner loop has a runtime trip count. With the cap | |
| ; disabled (0) the inner loop is runtime-unrolled with a remainder; with the | |
| ; cap at 1 the nest (2 loops) is over the limit and unrolling is suppressed. | |
| define void @nest(ptr %a, i64 %n, i64 %m) { | |
| ; UNROLL-LABEL: define void @nest( | |
| ; UNROLL-SAME: ptr [[A:%.*]], i64 [[N:%.*]], i64 [[M:%.*]]) { | |
| ; UNROLL-NEXT: [[ENTRY:.*]]: | |
| ; UNROLL-NEXT: [[UMAX:%.*]] = call i64 @llvm.umax.i64(i64 [[M]], i64 1) | |
| ; UNROLL-NEXT: [[TMP0:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[M]], i64 1) | |
| ; UNROLL-NEXT: br label %[[OUTER:.*]] | |
| ; UNROLL: [[OUTER]]: | |
| ; UNROLL-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ] | |
| ; UNROLL-NEXT: [[XTRAITER:%.*]] = and i64 [[UMAX]], 7 | |
| ; UNROLL-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 7 | |
| ; UNROLL-NEXT: br i1 [[TMP1]], label %[[INNER_EPIL_PREHEADER:.*]], label %[[OUTER_NEW:.*]] | |
| ; UNROLL: [[OUTER_NEW]]: | |
| ; UNROLL-NEXT: [[UNROLL_ITER:%.*]] = sub i64 [[UMAX]], [[XTRAITER]] | |
| ; UNROLL-NEXT: br label %[[INNER:.*]] | |
| ; UNROLL: [[INNER]]: | |
| ; UNROLL-NEXT: [[J:%.*]] = phi i64 [ 0, %[[OUTER_NEW]] ], [ [[J_NEXT_7:%.*]], %[[INNER]] ] | |
| ; UNROLL-NEXT: [[NITER:%.*]] = phi i64 [ 0, %[[OUTER_NEW]] ], [ [[NITER_NEXT_7:%.*]], %[[INNER]] ] | |
| ; UNROLL-NEXT: [[IDX:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J]] | |
| ; UNROLL-NEXT: [[V:%.*]] = load i32, ptr [[IDX]], align 4 | |
| ; UNROLL-NEXT: [[V2:%.*]] = add i32 [[V]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2]], ptr [[IDX]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT:%.*]] = add nuw nsw i64 [[J]], 1 | |
| ; UNROLL-NEXT: [[IDX_1:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT]] | |
| ; UNROLL-NEXT: [[V_1:%.*]] = load i32, ptr [[IDX_1]], align 4 | |
| ; UNROLL-NEXT: [[V2_1:%.*]] = add i32 [[V_1]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_1]], ptr [[IDX_1]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_1:%.*]] = add nuw nsw i64 [[J]], 2 | |
| ; UNROLL-NEXT: [[IDX_2:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_1]] | |
| ; UNROLL-NEXT: [[V_2:%.*]] = load i32, ptr [[IDX_2]], align 4 | |
| ; UNROLL-NEXT: [[V2_2:%.*]] = add i32 [[V_2]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_2]], ptr [[IDX_2]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_2:%.*]] = add nuw nsw i64 [[J]], 3 | |
| ; UNROLL-NEXT: [[IDX_3:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_2]] | |
| ; UNROLL-NEXT: [[V_3:%.*]] = load i32, ptr [[IDX_3]], align 4 | |
| ; UNROLL-NEXT: [[V2_3:%.*]] = add i32 [[V_3]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_3]], ptr [[IDX_3]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_3:%.*]] = add nuw nsw i64 [[J]], 4 | |
| ; UNROLL-NEXT: [[IDX_4:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_3]] | |
| ; UNROLL-NEXT: [[V_4:%.*]] = load i32, ptr [[IDX_4]], align 4 | |
| ; UNROLL-NEXT: [[V2_4:%.*]] = add i32 [[V_4]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_4]], ptr [[IDX_4]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_4:%.*]] = add nuw nsw i64 [[J]], 5 | |
| ; UNROLL-NEXT: [[IDX_5:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_4]] | |
| ; UNROLL-NEXT: [[V_5:%.*]] = load i32, ptr [[IDX_5]], align 4 | |
| ; UNROLL-NEXT: [[V2_5:%.*]] = add i32 [[V_5]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_5]], ptr [[IDX_5]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_5:%.*]] = add nuw nsw i64 [[J]], 6 | |
| ; UNROLL-NEXT: [[IDX_6:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_5]] | |
| ; UNROLL-NEXT: [[V_6:%.*]] = load i32, ptr [[IDX_6]], align 4 | |
| ; UNROLL-NEXT: [[V2_6:%.*]] = add i32 [[V_6]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_6]], ptr [[IDX_6]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_6:%.*]] = add nuw nsw i64 [[J]], 7 | |
| ; UNROLL-NEXT: [[IDX_7:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_6]] | |
| ; UNROLL-NEXT: [[V_7:%.*]] = load i32, ptr [[IDX_7]], align 4 | |
| ; UNROLL-NEXT: [[V2_7:%.*]] = add i32 [[V_7]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_7]], ptr [[IDX_7]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_7]] = add i64 [[J]], 8 | |
| ; UNROLL-NEXT: [[NITER_NEXT_7]] = add i64 [[NITER]], 8 | |
| ; UNROLL-NEXT: [[NITER_NCMP_7:%.*]] = icmp ne i64 [[NITER_NEXT_7]], [[UNROLL_ITER]] | |
| ; UNROLL-NEXT: br i1 [[NITER_NCMP_7]], label %[[INNER]], label %[[OUTER_LATCH_UNR_LCSSA:.*]] | |
| ; UNROLL: [[OUTER_LATCH_UNR_LCSSA]]: | |
| ; UNROLL-NEXT: [[J_UNR:%.*]] = phi i64 [ [[J_NEXT_7]], %[[INNER]] ] | |
| ; UNROLL-NEXT: [[LCMP_MOD:%.*]] = icmp ne i64 [[XTRAITER]], 0 | |
| ; UNROLL-NEXT: br i1 [[LCMP_MOD]], label %[[INNER_EPIL_PREHEADER]], label %[[OUTER_LATCH]] | |
| ; UNROLL: [[INNER_EPIL_PREHEADER]]: | |
| ; UNROLL-NEXT: [[J_EPIL_INIT:%.*]] = phi i64 [ 0, %[[OUTER]] ], [ [[J_UNR]], %[[OUTER_LATCH_UNR_LCSSA]] ] | |
| ; UNROLL-NEXT: [[LCMP_MOD1:%.*]] = icmp ne i64 [[XTRAITER]], 0 | |
| ; UNROLL-NEXT: call void @llvm.assume(i1 [[LCMP_MOD1]]) | |
| ; UNROLL-NEXT: br label %[[INNER_EPIL:.*]] | |
| ; UNROLL: [[INNER_EPIL]]: | |
| ; UNROLL-NEXT: [[J_EPIL:%.*]] = phi i64 [ [[J_EPIL_INIT]], %[[INNER_EPIL_PREHEADER]] ], [ [[J_NEXT_EPIL:%.*]], %[[INNER_EPIL]] ] | |
| ; UNROLL-NEXT: [[EPIL_ITER:%.*]] = phi i64 [ 0, %[[INNER_EPIL_PREHEADER]] ], [ [[EPIL_ITER_NEXT:%.*]], %[[INNER_EPIL]] ] | |
| ; UNROLL-NEXT: [[IDX_EPIL:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_EPIL]] | |
| ; UNROLL-NEXT: [[V_EPIL:%.*]] = load i32, ptr [[IDX_EPIL]], align 4 | |
| ; UNROLL-NEXT: [[V2_EPIL:%.*]] = add i32 [[V_EPIL]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_EPIL]], ptr [[IDX_EPIL]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_EPIL]] = add i64 [[J_EPIL]], 1 | |
| ; UNROLL-NEXT: [[INNER_COND_EPIL:%.*]] = icmp ult i64 [[J_NEXT_EPIL]], [[M]] | |
| ; UNROLL-NEXT: [[EPIL_ITER_NEXT]] = add i64 [[EPIL_ITER]], 1 | |
| ; UNROLL-NEXT: [[EPIL_ITER_CMP:%.*]] = icmp ne i64 [[EPIL_ITER_NEXT]], [[XTRAITER]] | |
| ; UNROLL-NEXT: br i1 [[EPIL_ITER_CMP]], label %[[INNER_EPIL]], label %[[OUTER_LATCH_EPILOG_LCSSA:.*]], !llvm.loop [[LOOP0:![0-9]+]] | |
| ; UNROLL: [[OUTER_LATCH_EPILOG_LCSSA]]: | |
| ; UNROLL-NEXT: br label %[[OUTER_LATCH]] | |
| ; UNROLL: [[OUTER_LATCH]]: | |
| ; UNROLL-NEXT: [[I_NEXT]] = add i64 [[I]], 1 | |
| ; UNROLL-NEXT: [[OUTER_COND:%.*]] = icmp ult i64 [[I_NEXT]], [[N]] | |
| ; UNROLL-NEXT: br i1 [[OUTER_COND]], label %[[OUTER]], label %[[EXIT:.*]], !llvm.loop [[LOOP2:![0-9]+]] | |
| ; UNROLL: [[EXIT]]: | |
| ; UNROLL-NEXT: ret void | |
| ; | |
| ; CAPPED-LABEL: define void @nest( | |
| ; CAPPED-SAME: ptr [[A:%.*]], i64 [[N:%.*]], i64 [[M:%.*]]) { | |
| ; CAPPED-NEXT: [[ENTRY:.*]]: | |
| ; CAPPED-NEXT: br label %[[OUTER:.*]] | |
| ; CAPPED: [[OUTER]]: | |
| ; CAPPED-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ] | |
| ; CAPPED-NEXT: br label %[[INNER:.*]] | |
| ; CAPPED: [[INNER]]: | |
| ; CAPPED-NEXT: [[J:%.*]] = phi i64 [ 0, %[[OUTER]] ], [ [[J_NEXT:%.*]], %[[INNER]] ] | |
| ; CAPPED-NEXT: [[IDX:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J]] | |
| ; CAPPED-NEXT: [[V:%.*]] = load i32, ptr [[IDX]], align 4 | |
| ; CAPPED-NEXT: [[V2:%.*]] = add i32 [[V]], 1 | |
| ; CAPPED-NEXT: store i32 [[V2]], ptr [[IDX]], align 4 | |
| ; CAPPED-NEXT: [[J_NEXT]] = add i64 [[J]], 1 | |
| ; CAPPED-NEXT: [[INNER_COND:%.*]] = icmp ult i64 [[J_NEXT]], [[M]] | |
| ; CAPPED-NEXT: br i1 [[INNER_COND]], label %[[INNER]], label %[[OUTER_LATCH]] | |
| ; CAPPED: [[OUTER_LATCH]]: | |
| ; CAPPED-NEXT: [[I_NEXT]] = add i64 [[I]], 1 | |
| ; CAPPED-NEXT: [[OUTER_COND:%.*]] = icmp ult i64 [[I_NEXT]], [[N]] | |
| ; CAPPED-NEXT: br i1 [[OUTER_COND]], label %[[OUTER]], label %[[EXIT:.*]], !llvm.loop [[LOOP0:![0-9]+]] | |
| ; CAPPED: [[EXIT]]: | |
| ; CAPPED-NEXT: ret void | |
| ; | |
| ; DEFAULT-LABEL: define void @nest( | |
| ; DEFAULT-SAME: ptr [[A:%.*]], i64 [[N:%.*]], i64 [[M:%.*]]) { | |
| ; DEFAULT-NEXT: [[ENTRY:.*]]: | |
| ; DEFAULT-NEXT: [[UMAX:%.*]] = call i64 @llvm.umax.i64(i64 [[M]], i64 1) | |
| ; DEFAULT-NEXT: [[TMP0:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[M]], i64 1) | |
| ; DEFAULT-NEXT: br label %[[OUTER:.*]] | |
| ; DEFAULT: [[OUTER]]: | |
| ; DEFAULT-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ] | |
| ; DEFAULT-NEXT: [[XTRAITER:%.*]] = and i64 [[UMAX]], 7 | |
| ; DEFAULT-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 7 | |
| ; DEFAULT-NEXT: br i1 [[TMP1]], label %[[INNER_EPIL_PREHEADER:.*]], label %[[OUTER_NEW:.*]] | |
| ; DEFAULT: [[OUTER_NEW]]: | |
| ; DEFAULT-NEXT: [[UNROLL_ITER:%.*]] = sub i64 [[UMAX]], [[XTRAITER]] | |
| ; DEFAULT-NEXT: br label %[[INNER:.*]] | |
| ; DEFAULT: [[INNER]]: | |
| ; DEFAULT-NEXT: [[J:%.*]] = phi i64 [ 0, %[[OUTER_NEW]] ], [ [[J_NEXT_7:%.*]], %[[INNER]] ] | |
| ; DEFAULT-NEXT: [[NITER:%.*]] = phi i64 [ 0, %[[OUTER_NEW]] ], [ [[NITER_NEXT_7:%.*]], %[[INNER]] ] | |
| ; DEFAULT-NEXT: [[IDX:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J]] | |
| ; DEFAULT-NEXT: [[V:%.*]] = load i32, ptr [[IDX]], align 4 | |
| ; DEFAULT-NEXT: [[V2:%.*]] = add i32 [[V]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2]], ptr [[IDX]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT:%.*]] = add nuw nsw i64 [[J]], 1 | |
| ; DEFAULT-NEXT: [[IDX_1:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT]] | |
| ; DEFAULT-NEXT: [[V_1:%.*]] = load i32, ptr [[IDX_1]], align 4 | |
| ; DEFAULT-NEXT: [[V2_1:%.*]] = add i32 [[V_1]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_1]], ptr [[IDX_1]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_1:%.*]] = add nuw nsw i64 [[J]], 2 | |
| ; DEFAULT-NEXT: [[IDX_2:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_1]] | |
| ; DEFAULT-NEXT: [[V_2:%.*]] = load i32, ptr [[IDX_2]], align 4 | |
| ; DEFAULT-NEXT: [[V2_2:%.*]] = add i32 [[V_2]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_2]], ptr [[IDX_2]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_2:%.*]] = add nuw nsw i64 [[J]], 3 | |
| ; DEFAULT-NEXT: [[IDX_3:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_2]] | |
| ; DEFAULT-NEXT: [[V_3:%.*]] = load i32, ptr [[IDX_3]], align 4 | |
| ; DEFAULT-NEXT: [[V2_3:%.*]] = add i32 [[V_3]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_3]], ptr [[IDX_3]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_3:%.*]] = add nuw nsw i64 [[J]], 4 | |
| ; DEFAULT-NEXT: [[IDX_4:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_3]] | |
| ; DEFAULT-NEXT: [[V_4:%.*]] = load i32, ptr [[IDX_4]], align 4 | |
| ; DEFAULT-NEXT: [[V2_4:%.*]] = add i32 [[V_4]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_4]], ptr [[IDX_4]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_4:%.*]] = add nuw nsw i64 [[J]], 5 | |
| ; DEFAULT-NEXT: [[IDX_5:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_4]] | |
| ; DEFAULT-NEXT: [[V_5:%.*]] = load i32, ptr [[IDX_5]], align 4 | |
| ; DEFAULT-NEXT: [[V2_5:%.*]] = add i32 [[V_5]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_5]], ptr [[IDX_5]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_5:%.*]] = add nuw nsw i64 [[J]], 6 | |
| ; DEFAULT-NEXT: [[IDX_6:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_5]] | |
| ; DEFAULT-NEXT: [[V_6:%.*]] = load i32, ptr [[IDX_6]], align 4 | |
| ; DEFAULT-NEXT: [[V2_6:%.*]] = add i32 [[V_6]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_6]], ptr [[IDX_6]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_6:%.*]] = add nuw nsw i64 [[J]], 7 | |
| ; DEFAULT-NEXT: [[IDX_7:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_6]] | |
| ; DEFAULT-NEXT: [[V_7:%.*]] = load i32, ptr [[IDX_7]], align 4 | |
| ; DEFAULT-NEXT: [[V2_7:%.*]] = add i32 [[V_7]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_7]], ptr [[IDX_7]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_7]] = add i64 [[J]], 8 | |
| ; DEFAULT-NEXT: [[NITER_NEXT_7]] = add i64 [[NITER]], 8 | |
| ; DEFAULT-NEXT: [[NITER_NCMP_7:%.*]] = icmp ne i64 [[NITER_NEXT_7]], [[UNROLL_ITER]] | |
| ; DEFAULT-NEXT: br i1 [[NITER_NCMP_7]], label %[[INNER]], label %[[OUTER_LATCH_UNR_LCSSA:.*]] | |
| ; DEFAULT: [[OUTER_LATCH_UNR_LCSSA]]: | |
| ; DEFAULT-NEXT: [[J_UNR:%.*]] = phi i64 [ [[J_NEXT_7]], %[[INNER]] ] | |
| ; DEFAULT-NEXT: [[LCMP_MOD:%.*]] = icmp ne i64 [[XTRAITER]], 0 | |
| ; DEFAULT-NEXT: br i1 [[LCMP_MOD]], label %[[INNER_EPIL_PREHEADER]], label %[[OUTER_LATCH]] | |
| ; DEFAULT: [[INNER_EPIL_PREHEADER]]: | |
| ; DEFAULT-NEXT: [[J_EPIL_INIT:%.*]] = phi i64 [ 0, %[[OUTER]] ], [ [[J_UNR]], %[[OUTER_LATCH_UNR_LCSSA]] ] | |
| ; DEFAULT-NEXT: [[LCMP_MOD1:%.*]] = icmp ne i64 [[XTRAITER]], 0 | |
| ; DEFAULT-NEXT: call void @llvm.assume(i1 [[LCMP_MOD1]]) | |
| ; DEFAULT-NEXT: br label %[[INNER_EPIL:.*]] | |
| ; DEFAULT: [[INNER_EPIL]]: | |
| ; DEFAULT-NEXT: [[J_EPIL:%.*]] = phi i64 [ [[J_EPIL_INIT]], %[[INNER_EPIL_PREHEADER]] ], [ [[J_NEXT_EPIL:%.*]], %[[INNER_EPIL]] ] | |
| ; DEFAULT-NEXT: [[EPIL_ITER:%.*]] = phi i64 [ 0, %[[INNER_EPIL_PREHEADER]] ], [ [[EPIL_ITER_NEXT:%.*]], %[[INNER_EPIL]] ] | |
| ; DEFAULT-NEXT: [[IDX_EPIL:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_EPIL]] | |
| ; DEFAULT-NEXT: [[V_EPIL:%.*]] = load i32, ptr [[IDX_EPIL]], align 4 | |
| ; DEFAULT-NEXT: [[V2_EPIL:%.*]] = add i32 [[V_EPIL]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_EPIL]], ptr [[IDX_EPIL]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_EPIL]] = add i64 [[J_EPIL]], 1 | |
| ; DEFAULT-NEXT: [[INNER_COND_EPIL:%.*]] = icmp ult i64 [[J_NEXT_EPIL]], [[M]] | |
| ; DEFAULT-NEXT: [[EPIL_ITER_NEXT]] = add i64 [[EPIL_ITER]], 1 | |
| ; DEFAULT-NEXT: [[EPIL_ITER_CMP:%.*]] = icmp ne i64 [[EPIL_ITER_NEXT]], [[XTRAITER]] | |
| ; DEFAULT-NEXT: br i1 [[EPIL_ITER_CMP]], label %[[INNER_EPIL]], label %[[OUTER_LATCH_EPILOG_LCSSA:.*]], !llvm.loop [[LOOP0:![0-9]+]] | |
| ; DEFAULT: [[OUTER_LATCH_EPILOG_LCSSA]]: | |
| ; DEFAULT-NEXT: br label %[[OUTER_LATCH]] | |
| ; DEFAULT: [[OUTER_LATCH]]: | |
| ; DEFAULT-NEXT: [[I_NEXT]] = add i64 [[I]], 1 | |
| ; DEFAULT-NEXT: [[OUTER_COND:%.*]] = icmp ult i64 [[I_NEXT]], [[N]] | |
| ; DEFAULT-NEXT: br i1 [[OUTER_COND]], label %[[OUTER]], label %[[EXIT:.*]], !llvm.loop [[LOOP2:![0-9]+]] | |
| ; DEFAULT: [[EXIT]]: | |
| ; DEFAULT-NEXT: ret void | |
| ; | |
| entry: | |
| br label %outer | |
| outer: ; preds = %outer.latch, %entry | |
| %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ] | |
| br label %inner | |
| inner: ; preds = %inner, %outer | |
| %j = phi i64 [ 0, %outer ], [ %j.next, %inner ] | |
| %idx = getelementptr inbounds i32, ptr %a, i64 %j | |
| %v = load i32, ptr %idx | |
| %v2 = add i32 %v, 1 | |
| store i32 %v2, ptr %idx | |
| %j.next = add i64 %j, 1 | |
| %inner.cond = icmp ult i64 %j.next, %m | |
| br i1 %inner.cond, label %inner, label %outer.latch | |
| outer.latch: ; preds = %inner | |
| %i.next = add i64 %i, 1 | |
| %outer.cond = icmp ult i64 %i.next, %n | |
| br i1 %outer.cond, label %outer, label %exit, !llvm.loop !0 | |
| exit: ; preds = %outer.latch | |
| ret void | |
| } | |
| ; Same nest, but the inner loop carries llvm.loop.unroll.enable. The explicit | |
| ; pragma re-enables runtime unrolling in computeUnrollCount, so the loop is | |
| ; still unrolled even though the nest is over the cap (checked under CAPPED). | |
| define void @nest_pragma(ptr %a, i64 %n, i64 %m) { | |
| ; UNROLL-LABEL: define void @nest_pragma( | |
| ; UNROLL-SAME: ptr [[A:%.*]], i64 [[N:%.*]], i64 [[M:%.*]]) { | |
| ; UNROLL-NEXT: [[ENTRY:.*]]: | |
| ; UNROLL-NEXT: [[UMAX:%.*]] = call i64 @llvm.umax.i64(i64 [[M]], i64 1) | |
| ; UNROLL-NEXT: [[TMP0:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[M]], i64 1) | |
| ; UNROLL-NEXT: br label %[[OUTER:.*]] | |
| ; UNROLL: [[OUTER]]: | |
| ; UNROLL-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ] | |
| ; UNROLL-NEXT: [[XTRAITER:%.*]] = and i64 [[UMAX]], 7 | |
| ; UNROLL-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 7 | |
| ; UNROLL-NEXT: br i1 [[TMP1]], label %[[INNER_EPIL_PREHEADER:.*]], label %[[OUTER_NEW:.*]] | |
| ; UNROLL: [[OUTER_NEW]]: | |
| ; UNROLL-NEXT: [[UNROLL_ITER:%.*]] = sub i64 [[UMAX]], [[XTRAITER]] | |
| ; UNROLL-NEXT: br label %[[INNER:.*]] | |
| ; UNROLL: [[INNER]]: | |
| ; UNROLL-NEXT: [[J:%.*]] = phi i64 [ 0, %[[OUTER_NEW]] ], [ [[J_NEXT_7:%.*]], %[[INNER]] ] | |
| ; UNROLL-NEXT: [[NITER:%.*]] = phi i64 [ 0, %[[OUTER_NEW]] ], [ [[NITER_NEXT_7:%.*]], %[[INNER]] ] | |
| ; UNROLL-NEXT: [[IDX:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J]] | |
| ; UNROLL-NEXT: [[V:%.*]] = load i32, ptr [[IDX]], align 4 | |
| ; UNROLL-NEXT: [[V2:%.*]] = add i32 [[V]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2]], ptr [[IDX]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT:%.*]] = add nuw nsw i64 [[J]], 1 | |
| ; UNROLL-NEXT: [[IDX_1:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT]] | |
| ; UNROLL-NEXT: [[V_1:%.*]] = load i32, ptr [[IDX_1]], align 4 | |
| ; UNROLL-NEXT: [[V2_1:%.*]] = add i32 [[V_1]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_1]], ptr [[IDX_1]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_1:%.*]] = add nuw nsw i64 [[J]], 2 | |
| ; UNROLL-NEXT: [[IDX_2:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_1]] | |
| ; UNROLL-NEXT: [[V_2:%.*]] = load i32, ptr [[IDX_2]], align 4 | |
| ; UNROLL-NEXT: [[V2_2:%.*]] = add i32 [[V_2]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_2]], ptr [[IDX_2]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_2:%.*]] = add nuw nsw i64 [[J]], 3 | |
| ; UNROLL-NEXT: [[IDX_3:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_2]] | |
| ; UNROLL-NEXT: [[V_3:%.*]] = load i32, ptr [[IDX_3]], align 4 | |
| ; UNROLL-NEXT: [[V2_3:%.*]] = add i32 [[V_3]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_3]], ptr [[IDX_3]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_3:%.*]] = add nuw nsw i64 [[J]], 4 | |
| ; UNROLL-NEXT: [[IDX_4:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_3]] | |
| ; UNROLL-NEXT: [[V_4:%.*]] = load i32, ptr [[IDX_4]], align 4 | |
| ; UNROLL-NEXT: [[V2_4:%.*]] = add i32 [[V_4]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_4]], ptr [[IDX_4]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_4:%.*]] = add nuw nsw i64 [[J]], 5 | |
| ; UNROLL-NEXT: [[IDX_5:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_4]] | |
| ; UNROLL-NEXT: [[V_5:%.*]] = load i32, ptr [[IDX_5]], align 4 | |
| ; UNROLL-NEXT: [[V2_5:%.*]] = add i32 [[V_5]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_5]], ptr [[IDX_5]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_5:%.*]] = add nuw nsw i64 [[J]], 6 | |
| ; UNROLL-NEXT: [[IDX_6:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_5]] | |
| ; UNROLL-NEXT: [[V_6:%.*]] = load i32, ptr [[IDX_6]], align 4 | |
| ; UNROLL-NEXT: [[V2_6:%.*]] = add i32 [[V_6]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_6]], ptr [[IDX_6]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_6:%.*]] = add nuw nsw i64 [[J]], 7 | |
| ; UNROLL-NEXT: [[IDX_7:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_6]] | |
| ; UNROLL-NEXT: [[V_7:%.*]] = load i32, ptr [[IDX_7]], align 4 | |
| ; UNROLL-NEXT: [[V2_7:%.*]] = add i32 [[V_7]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_7]], ptr [[IDX_7]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_7]] = add i64 [[J]], 8 | |
| ; UNROLL-NEXT: [[NITER_NEXT_7]] = add i64 [[NITER]], 8 | |
| ; UNROLL-NEXT: [[NITER_NCMP_7:%.*]] = icmp ne i64 [[NITER_NEXT_7]], [[UNROLL_ITER]] | |
| ; UNROLL-NEXT: br i1 [[NITER_NCMP_7]], label %[[INNER]], label %[[OUTER_LATCH_UNR_LCSSA:.*]], !llvm.loop [[LOOP3:![0-9]+]] | |
| ; UNROLL: [[OUTER_LATCH_UNR_LCSSA]]: | |
| ; UNROLL-NEXT: [[J_UNR:%.*]] = phi i64 [ [[J_NEXT_7]], %[[INNER]] ] | |
| ; UNROLL-NEXT: [[LCMP_MOD:%.*]] = icmp ne i64 [[XTRAITER]], 0 | |
| ; UNROLL-NEXT: br i1 [[LCMP_MOD]], label %[[INNER_EPIL_PREHEADER]], label %[[OUTER_LATCH]] | |
| ; UNROLL: [[INNER_EPIL_PREHEADER]]: | |
| ; UNROLL-NEXT: [[J_EPIL_INIT:%.*]] = phi i64 [ 0, %[[OUTER]] ], [ [[J_UNR]], %[[OUTER_LATCH_UNR_LCSSA]] ] | |
| ; UNROLL-NEXT: [[LCMP_MOD1:%.*]] = icmp ne i64 [[XTRAITER]], 0 | |
| ; UNROLL-NEXT: call void @llvm.assume(i1 [[LCMP_MOD1]]) | |
| ; UNROLL-NEXT: br label %[[INNER_EPIL:.*]] | |
| ; UNROLL: [[INNER_EPIL]]: | |
| ; UNROLL-NEXT: [[J_EPIL:%.*]] = phi i64 [ [[J_EPIL_INIT]], %[[INNER_EPIL_PREHEADER]] ], [ [[J_NEXT_EPIL:%.*]], %[[INNER_EPIL]] ] | |
| ; UNROLL-NEXT: [[EPIL_ITER:%.*]] = phi i64 [ 0, %[[INNER_EPIL_PREHEADER]] ], [ [[EPIL_ITER_NEXT:%.*]], %[[INNER_EPIL]] ] | |
| ; UNROLL-NEXT: [[IDX_EPIL:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_EPIL]] | |
| ; UNROLL-NEXT: [[V_EPIL:%.*]] = load i32, ptr [[IDX_EPIL]], align 4 | |
| ; UNROLL-NEXT: [[V2_EPIL:%.*]] = add i32 [[V_EPIL]], 1 | |
| ; UNROLL-NEXT: store i32 [[V2_EPIL]], ptr [[IDX_EPIL]], align 4 | |
| ; UNROLL-NEXT: [[J_NEXT_EPIL]] = add i64 [[J_EPIL]], 1 | |
| ; UNROLL-NEXT: [[INNER_COND_EPIL:%.*]] = icmp ult i64 [[J_NEXT_EPIL]], [[M]] | |
| ; UNROLL-NEXT: [[EPIL_ITER_NEXT]] = add i64 [[EPIL_ITER]], 1 | |
| ; UNROLL-NEXT: [[EPIL_ITER_CMP:%.*]] = icmp ne i64 [[EPIL_ITER_NEXT]], [[XTRAITER]] | |
| ; UNROLL-NEXT: br i1 [[EPIL_ITER_CMP]], label %[[INNER_EPIL]], label %[[OUTER_LATCH_EPILOG_LCSSA:.*]], !llvm.loop [[LOOP4:![0-9]+]] | |
| ; UNROLL: [[OUTER_LATCH_EPILOG_LCSSA]]: | |
| ; UNROLL-NEXT: br label %[[OUTER_LATCH]] | |
| ; UNROLL: [[OUTER_LATCH]]: | |
| ; UNROLL-NEXT: [[I_NEXT]] = add i64 [[I]], 1 | |
| ; UNROLL-NEXT: [[OUTER_COND:%.*]] = icmp ult i64 [[I_NEXT]], [[N]] | |
| ; UNROLL-NEXT: br i1 [[OUTER_COND]], label %[[OUTER]], label %[[EXIT:.*]], !llvm.loop [[LOOP5:![0-9]+]] | |
| ; UNROLL: [[EXIT]]: | |
| ; UNROLL-NEXT: ret void | |
| ; | |
| ; CAPPED-LABEL: define void @nest_pragma( | |
| ; CAPPED-SAME: ptr [[A:%.*]], i64 [[N:%.*]], i64 [[M:%.*]]) { | |
| ; CAPPED-NEXT: [[ENTRY:.*]]: | |
| ; CAPPED-NEXT: [[UMAX:%.*]] = call i64 @llvm.umax.i64(i64 [[M]], i64 1) | |
| ; CAPPED-NEXT: [[TMP0:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[M]], i64 1) | |
| ; CAPPED-NEXT: br label %[[OUTER:.*]] | |
| ; CAPPED: [[OUTER]]: | |
| ; CAPPED-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ] | |
| ; CAPPED-NEXT: [[XTRAITER:%.*]] = and i64 [[UMAX]], 7 | |
| ; CAPPED-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 7 | |
| ; CAPPED-NEXT: br i1 [[TMP1]], label %[[INNER_EPIL_PREHEADER:.*]], label %[[OUTER_NEW:.*]] | |
| ; CAPPED: [[OUTER_NEW]]: | |
| ; CAPPED-NEXT: [[UNROLL_ITER:%.*]] = sub i64 [[UMAX]], [[XTRAITER]] | |
| ; CAPPED-NEXT: br label %[[INNER:.*]] | |
| ; CAPPED: [[INNER]]: | |
| ; CAPPED-NEXT: [[J:%.*]] = phi i64 [ 0, %[[OUTER_NEW]] ], [ [[J_NEXT_7:%.*]], %[[INNER]] ] | |
| ; CAPPED-NEXT: [[NITER:%.*]] = phi i64 [ 0, %[[OUTER_NEW]] ], [ [[NITER_NEXT_7:%.*]], %[[INNER]] ] | |
| ; CAPPED-NEXT: [[IDX:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J]] | |
| ; CAPPED-NEXT: [[V:%.*]] = load i32, ptr [[IDX]], align 4 | |
| ; CAPPED-NEXT: [[V2:%.*]] = add i32 [[V]], 1 | |
| ; CAPPED-NEXT: store i32 [[V2]], ptr [[IDX]], align 4 | |
| ; CAPPED-NEXT: [[J_NEXT:%.*]] = add nuw nsw i64 [[J]], 1 | |
| ; CAPPED-NEXT: [[IDX_1:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT]] | |
| ; CAPPED-NEXT: [[V_1:%.*]] = load i32, ptr [[IDX_1]], align 4 | |
| ; CAPPED-NEXT: [[V2_1:%.*]] = add i32 [[V_1]], 1 | |
| ; CAPPED-NEXT: store i32 [[V2_1]], ptr [[IDX_1]], align 4 | |
| ; CAPPED-NEXT: [[J_NEXT_1:%.*]] = add nuw nsw i64 [[J]], 2 | |
| ; CAPPED-NEXT: [[IDX_2:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_1]] | |
| ; CAPPED-NEXT: [[V_2:%.*]] = load i32, ptr [[IDX_2]], align 4 | |
| ; CAPPED-NEXT: [[V2_2:%.*]] = add i32 [[V_2]], 1 | |
| ; CAPPED-NEXT: store i32 [[V2_2]], ptr [[IDX_2]], align 4 | |
| ; CAPPED-NEXT: [[J_NEXT_2:%.*]] = add nuw nsw i64 [[J]], 3 | |
| ; CAPPED-NEXT: [[IDX_3:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_2]] | |
| ; CAPPED-NEXT: [[V_3:%.*]] = load i32, ptr [[IDX_3]], align 4 | |
| ; CAPPED-NEXT: [[V2_3:%.*]] = add i32 [[V_3]], 1 | |
| ; CAPPED-NEXT: store i32 [[V2_3]], ptr [[IDX_3]], align 4 | |
| ; CAPPED-NEXT: [[J_NEXT_3:%.*]] = add nuw nsw i64 [[J]], 4 | |
| ; CAPPED-NEXT: [[IDX_4:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_3]] | |
| ; CAPPED-NEXT: [[V_4:%.*]] = load i32, ptr [[IDX_4]], align 4 | |
| ; CAPPED-NEXT: [[V2_4:%.*]] = add i32 [[V_4]], 1 | |
| ; CAPPED-NEXT: store i32 [[V2_4]], ptr [[IDX_4]], align 4 | |
| ; CAPPED-NEXT: [[J_NEXT_4:%.*]] = add nuw nsw i64 [[J]], 5 | |
| ; CAPPED-NEXT: [[IDX_5:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_4]] | |
| ; CAPPED-NEXT: [[V_5:%.*]] = load i32, ptr [[IDX_5]], align 4 | |
| ; CAPPED-NEXT: [[V2_5:%.*]] = add i32 [[V_5]], 1 | |
| ; CAPPED-NEXT: store i32 [[V2_5]], ptr [[IDX_5]], align 4 | |
| ; CAPPED-NEXT: [[J_NEXT_5:%.*]] = add nuw nsw i64 [[J]], 6 | |
| ; CAPPED-NEXT: [[IDX_6:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_5]] | |
| ; CAPPED-NEXT: [[V_6:%.*]] = load i32, ptr [[IDX_6]], align 4 | |
| ; CAPPED-NEXT: [[V2_6:%.*]] = add i32 [[V_6]], 1 | |
| ; CAPPED-NEXT: store i32 [[V2_6]], ptr [[IDX_6]], align 4 | |
| ; CAPPED-NEXT: [[J_NEXT_6:%.*]] = add nuw nsw i64 [[J]], 7 | |
| ; CAPPED-NEXT: [[IDX_7:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_6]] | |
| ; CAPPED-NEXT: [[V_7:%.*]] = load i32, ptr [[IDX_7]], align 4 | |
| ; CAPPED-NEXT: [[V2_7:%.*]] = add i32 [[V_7]], 1 | |
| ; CAPPED-NEXT: store i32 [[V2_7]], ptr [[IDX_7]], align 4 | |
| ; CAPPED-NEXT: [[J_NEXT_7]] = add i64 [[J]], 8 | |
| ; CAPPED-NEXT: [[NITER_NEXT_7]] = add i64 [[NITER]], 8 | |
| ; CAPPED-NEXT: [[NITER_NCMP_7:%.*]] = icmp ne i64 [[NITER_NEXT_7]], [[UNROLL_ITER]] | |
| ; CAPPED-NEXT: br i1 [[NITER_NCMP_7]], label %[[INNER]], label %[[OUTER_LATCH_UNR_LCSSA:.*]], !llvm.loop [[LOOP2:![0-9]+]] | |
| ; CAPPED: [[OUTER_LATCH_UNR_LCSSA]]: | |
| ; CAPPED-NEXT: [[J_UNR:%.*]] = phi i64 [ [[J_NEXT_7]], %[[INNER]] ] | |
| ; CAPPED-NEXT: [[LCMP_MOD:%.*]] = icmp ne i64 [[XTRAITER]], 0 | |
| ; CAPPED-NEXT: br i1 [[LCMP_MOD]], label %[[INNER_EPIL_PREHEADER]], label %[[OUTER_LATCH]] | |
| ; CAPPED: [[INNER_EPIL_PREHEADER]]: | |
| ; CAPPED-NEXT: [[J_EPIL_INIT:%.*]] = phi i64 [ 0, %[[OUTER]] ], [ [[J_UNR]], %[[OUTER_LATCH_UNR_LCSSA]] ] | |
| ; CAPPED-NEXT: [[LCMP_MOD1:%.*]] = icmp ne i64 [[XTRAITER]], 0 | |
| ; CAPPED-NEXT: call void @llvm.assume(i1 [[LCMP_MOD1]]) | |
| ; CAPPED-NEXT: br label %[[INNER_EPIL:.*]] | |
| ; CAPPED: [[INNER_EPIL]]: | |
| ; CAPPED-NEXT: [[J_EPIL:%.*]] = phi i64 [ [[J_EPIL_INIT]], %[[INNER_EPIL_PREHEADER]] ], [ [[J_NEXT_EPIL:%.*]], %[[INNER_EPIL]] ] | |
| ; CAPPED-NEXT: [[EPIL_ITER:%.*]] = phi i64 [ 0, %[[INNER_EPIL_PREHEADER]] ], [ [[EPIL_ITER_NEXT:%.*]], %[[INNER_EPIL]] ] | |
| ; CAPPED-NEXT: [[IDX_EPIL:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_EPIL]] | |
| ; CAPPED-NEXT: [[V_EPIL:%.*]] = load i32, ptr [[IDX_EPIL]], align 4 | |
| ; CAPPED-NEXT: [[V2_EPIL:%.*]] = add i32 [[V_EPIL]], 1 | |
| ; CAPPED-NEXT: store i32 [[V2_EPIL]], ptr [[IDX_EPIL]], align 4 | |
| ; CAPPED-NEXT: [[J_NEXT_EPIL]] = add i64 [[J_EPIL]], 1 | |
| ; CAPPED-NEXT: [[INNER_COND_EPIL:%.*]] = icmp ult i64 [[J_NEXT_EPIL]], [[M]] | |
| ; CAPPED-NEXT: [[EPIL_ITER_NEXT]] = add i64 [[EPIL_ITER]], 1 | |
| ; CAPPED-NEXT: [[EPIL_ITER_CMP:%.*]] = icmp ne i64 [[EPIL_ITER_NEXT]], [[XTRAITER]] | |
| ; CAPPED-NEXT: br i1 [[EPIL_ITER_CMP]], label %[[INNER_EPIL]], label %[[OUTER_LATCH_EPILOG_LCSSA:.*]], !llvm.loop [[LOOP3:![0-9]+]] | |
| ; CAPPED: [[OUTER_LATCH_EPILOG_LCSSA]]: | |
| ; CAPPED-NEXT: br label %[[OUTER_LATCH]] | |
| ; CAPPED: [[OUTER_LATCH]]: | |
| ; CAPPED-NEXT: [[I_NEXT]] = add i64 [[I]], 1 | |
| ; CAPPED-NEXT: [[OUTER_COND:%.*]] = icmp ult i64 [[I_NEXT]], [[N]] | |
| ; CAPPED-NEXT: br i1 [[OUTER_COND]], label %[[OUTER]], label %[[EXIT:.*]], !llvm.loop [[LOOP4:![0-9]+]] | |
| ; CAPPED: [[EXIT]]: | |
| ; CAPPED-NEXT: ret void | |
| ; | |
| ; DEFAULT-LABEL: define void @nest_pragma( | |
| ; DEFAULT-SAME: ptr [[A:%.*]], i64 [[N:%.*]], i64 [[M:%.*]]) { | |
| ; DEFAULT-NEXT: [[ENTRY:.*]]: | |
| ; DEFAULT-NEXT: [[UMAX:%.*]] = call i64 @llvm.umax.i64(i64 [[M]], i64 1) | |
| ; DEFAULT-NEXT: [[TMP0:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[M]], i64 1) | |
| ; DEFAULT-NEXT: br label %[[OUTER:.*]] | |
| ; DEFAULT: [[OUTER]]: | |
| ; DEFAULT-NEXT: [[I:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[I_NEXT:%.*]], %[[OUTER_LATCH:.*]] ] | |
| ; DEFAULT-NEXT: [[XTRAITER:%.*]] = and i64 [[UMAX]], 7 | |
| ; DEFAULT-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], 7 | |
| ; DEFAULT-NEXT: br i1 [[TMP1]], label %[[INNER_EPIL_PREHEADER:.*]], label %[[OUTER_NEW:.*]] | |
| ; DEFAULT: [[OUTER_NEW]]: | |
| ; DEFAULT-NEXT: [[UNROLL_ITER:%.*]] = sub i64 [[UMAX]], [[XTRAITER]] | |
| ; DEFAULT-NEXT: br label %[[INNER:.*]] | |
| ; DEFAULT: [[INNER]]: | |
| ; DEFAULT-NEXT: [[J:%.*]] = phi i64 [ 0, %[[OUTER_NEW]] ], [ [[J_NEXT_7:%.*]], %[[INNER]] ] | |
| ; DEFAULT-NEXT: [[NITER:%.*]] = phi i64 [ 0, %[[OUTER_NEW]] ], [ [[NITER_NEXT_7:%.*]], %[[INNER]] ] | |
| ; DEFAULT-NEXT: [[IDX:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J]] | |
| ; DEFAULT-NEXT: [[V:%.*]] = load i32, ptr [[IDX]], align 4 | |
| ; DEFAULT-NEXT: [[V2:%.*]] = add i32 [[V]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2]], ptr [[IDX]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT:%.*]] = add nuw nsw i64 [[J]], 1 | |
| ; DEFAULT-NEXT: [[IDX_1:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT]] | |
| ; DEFAULT-NEXT: [[V_1:%.*]] = load i32, ptr [[IDX_1]], align 4 | |
| ; DEFAULT-NEXT: [[V2_1:%.*]] = add i32 [[V_1]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_1]], ptr [[IDX_1]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_1:%.*]] = add nuw nsw i64 [[J]], 2 | |
| ; DEFAULT-NEXT: [[IDX_2:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_1]] | |
| ; DEFAULT-NEXT: [[V_2:%.*]] = load i32, ptr [[IDX_2]], align 4 | |
| ; DEFAULT-NEXT: [[V2_2:%.*]] = add i32 [[V_2]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_2]], ptr [[IDX_2]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_2:%.*]] = add nuw nsw i64 [[J]], 3 | |
| ; DEFAULT-NEXT: [[IDX_3:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_2]] | |
| ; DEFAULT-NEXT: [[V_3:%.*]] = load i32, ptr [[IDX_3]], align 4 | |
| ; DEFAULT-NEXT: [[V2_3:%.*]] = add i32 [[V_3]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_3]], ptr [[IDX_3]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_3:%.*]] = add nuw nsw i64 [[J]], 4 | |
| ; DEFAULT-NEXT: [[IDX_4:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_3]] | |
| ; DEFAULT-NEXT: [[V_4:%.*]] = load i32, ptr [[IDX_4]], align 4 | |
| ; DEFAULT-NEXT: [[V2_4:%.*]] = add i32 [[V_4]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_4]], ptr [[IDX_4]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_4:%.*]] = add nuw nsw i64 [[J]], 5 | |
| ; DEFAULT-NEXT: [[IDX_5:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_4]] | |
| ; DEFAULT-NEXT: [[V_5:%.*]] = load i32, ptr [[IDX_5]], align 4 | |
| ; DEFAULT-NEXT: [[V2_5:%.*]] = add i32 [[V_5]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_5]], ptr [[IDX_5]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_5:%.*]] = add nuw nsw i64 [[J]], 6 | |
| ; DEFAULT-NEXT: [[IDX_6:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_5]] | |
| ; DEFAULT-NEXT: [[V_6:%.*]] = load i32, ptr [[IDX_6]], align 4 | |
| ; DEFAULT-NEXT: [[V2_6:%.*]] = add i32 [[V_6]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_6]], ptr [[IDX_6]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_6:%.*]] = add nuw nsw i64 [[J]], 7 | |
| ; DEFAULT-NEXT: [[IDX_7:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_NEXT_6]] | |
| ; DEFAULT-NEXT: [[V_7:%.*]] = load i32, ptr [[IDX_7]], align 4 | |
| ; DEFAULT-NEXT: [[V2_7:%.*]] = add i32 [[V_7]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_7]], ptr [[IDX_7]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_7]] = add i64 [[J]], 8 | |
| ; DEFAULT-NEXT: [[NITER_NEXT_7]] = add i64 [[NITER]], 8 | |
| ; DEFAULT-NEXT: [[NITER_NCMP_7:%.*]] = icmp ne i64 [[NITER_NEXT_7]], [[UNROLL_ITER]] | |
| ; DEFAULT-NEXT: br i1 [[NITER_NCMP_7]], label %[[INNER]], label %[[OUTER_LATCH_UNR_LCSSA:.*]], !llvm.loop [[LOOP3:![0-9]+]] | |
| ; DEFAULT: [[OUTER_LATCH_UNR_LCSSA]]: | |
| ; DEFAULT-NEXT: [[J_UNR:%.*]] = phi i64 [ [[J_NEXT_7]], %[[INNER]] ] | |
| ; DEFAULT-NEXT: [[LCMP_MOD:%.*]] = icmp ne i64 [[XTRAITER]], 0 | |
| ; DEFAULT-NEXT: br i1 [[LCMP_MOD]], label %[[INNER_EPIL_PREHEADER]], label %[[OUTER_LATCH]] | |
| ; DEFAULT: [[INNER_EPIL_PREHEADER]]: | |
| ; DEFAULT-NEXT: [[J_EPIL_INIT:%.*]] = phi i64 [ 0, %[[OUTER]] ], [ [[J_UNR]], %[[OUTER_LATCH_UNR_LCSSA]] ] | |
| ; DEFAULT-NEXT: [[LCMP_MOD1:%.*]] = icmp ne i64 [[XTRAITER]], 0 | |
| ; DEFAULT-NEXT: call void @llvm.assume(i1 [[LCMP_MOD1]]) | |
| ; DEFAULT-NEXT: br label %[[INNER_EPIL:.*]] | |
| ; DEFAULT: [[INNER_EPIL]]: | |
| ; DEFAULT-NEXT: [[J_EPIL:%.*]] = phi i64 [ [[J_EPIL_INIT]], %[[INNER_EPIL_PREHEADER]] ], [ [[J_NEXT_EPIL:%.*]], %[[INNER_EPIL]] ] | |
| ; DEFAULT-NEXT: [[EPIL_ITER:%.*]] = phi i64 [ 0, %[[INNER_EPIL_PREHEADER]] ], [ [[EPIL_ITER_NEXT:%.*]], %[[INNER_EPIL]] ] | |
| ; DEFAULT-NEXT: [[IDX_EPIL:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[J_EPIL]] | |
| ; DEFAULT-NEXT: [[V_EPIL:%.*]] = load i32, ptr [[IDX_EPIL]], align 4 | |
| ; DEFAULT-NEXT: [[V2_EPIL:%.*]] = add i32 [[V_EPIL]], 1 | |
| ; DEFAULT-NEXT: store i32 [[V2_EPIL]], ptr [[IDX_EPIL]], align 4 | |
| ; DEFAULT-NEXT: [[J_NEXT_EPIL]] = add i64 [[J_EPIL]], 1 | |
| ; DEFAULT-NEXT: [[INNER_COND_EPIL:%.*]] = icmp ult i64 [[J_NEXT_EPIL]], [[M]] | |
| ; DEFAULT-NEXT: [[EPIL_ITER_NEXT]] = add i64 [[EPIL_ITER]], 1 | |
| ; DEFAULT-NEXT: [[EPIL_ITER_CMP:%.*]] = icmp ne i64 [[EPIL_ITER_NEXT]], [[XTRAITER]] | |
| ; DEFAULT-NEXT: br i1 [[EPIL_ITER_CMP]], label %[[INNER_EPIL]], label %[[OUTER_LATCH_EPILOG_LCSSA:.*]], !llvm.loop [[LOOP4:![0-9]+]] | |
| ; DEFAULT: [[OUTER_LATCH_EPILOG_LCSSA]]: | |
| ; DEFAULT-NEXT: br label %[[OUTER_LATCH]] | |
| ; DEFAULT: [[OUTER_LATCH]]: | |
| ; DEFAULT-NEXT: [[I_NEXT]] = add i64 [[I]], 1 | |
| ; DEFAULT-NEXT: [[OUTER_COND:%.*]] = icmp ult i64 [[I_NEXT]], [[N]] | |
| ; DEFAULT-NEXT: br i1 [[OUTER_COND]], label %[[OUTER]], label %[[EXIT:.*]], !llvm.loop [[LOOP5:![0-9]+]] | |
| ; DEFAULT: [[EXIT]]: | |
| ; DEFAULT-NEXT: ret void | |
| ; | |
| entry: | |
| br label %outer | |
| outer: ; preds = %outer.latch, %entry | |
| %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ] | |
| br label %inner | |
| inner: ; preds = %inner, %outer | |
| %j = phi i64 [ 0, %outer ], [ %j.next, %inner ] | |
| %idx = getelementptr inbounds i32, ptr %a, i64 %j | |
| %v = load i32, ptr %idx | |
| %v2 = add i32 %v, 1 | |
| store i32 %v2, ptr %idx | |
| %j.next = add i64 %j, 1 | |
| %inner.cond = icmp ult i64 %j.next, %m | |
| br i1 %inner.cond, label %inner, label %outer.latch, !llvm.loop !2 | |
| outer.latch: ; preds = %inner | |
| %i.next = add i64 %i, 1 | |
| %outer.cond = icmp ult i64 %i.next, %n | |
| br i1 %outer.cond, label %outer, label %exit, !llvm.loop !4 | |
| exit: ; preds = %outer.latch | |
| ret void | |
| } | |
| !0 = distinct !{!0, !1} | |
| !1 = !{!"llvm.loop.unroll.disable"} | |
| !2 = distinct !{!2, !3} | |
| !3 = !{!"llvm.loop.unroll.enable"} | |
| !4 = distinct !{!4, !1} |