blob: b9ebd7dd90dcdb2741e2257aada5ab00f05cdb93 [file] [edit]
; 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}