blob: d7a69922a06f9ad3d368e81f1251297bfab3ec13 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=indvars -indvars-predicate-loops=1 -S | FileCheck %s
; Predication must be skipped if an observable infinite loop may exist in the
; loop nest.
define void @infinite_subloop_skips_predication() {
; CHECK-LABEL: @infinite_subloop_skips_predication(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer.header:
; CHECK-NEXT: [[IV:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[OUTER_LATCH:%.*]] ]
; CHECK-NEXT: br label [[INNER_HEADER:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
; CHECK: inner.header:
; CHECK-NEXT: [[INNER_COND:%.*]] = icmp eq i8 [[IV]], 1
; CHECK-NEXT: br i1 [[INNER_COND]], label [[INNER_HEADER]], label [[OUTER_LATCH]]
; CHECK: outer.latch:
; CHECK-NEXT: [[IV_NEXT]] = add nuw i8 [[IV]], 1
; CHECK-NEXT: [[OUTER_COND:%.*]] = icmp eq i8 [[IV_NEXT]], -1
; CHECK-NEXT: br i1 [[OUTER_COND]], label [[EXIT:%.*]], label [[OUTER_HEADER]]
;
entry:
br label %outer.header
outer.header:
%iv = phi i8 [ 0, %entry ], [ %iv.next, %outer.latch ]
br label %inner.header
exit:
ret void
inner.header:
%inner.cond = icmp eq i8 %iv, 1
br i1 %inner.cond, label %inner.header, label %outer.latch
outer.latch:
%iv.next = add nuw i8 %iv, 1
%outer.cond = icmp eq i8 %iv.next, -1
br i1 %outer.cond, label %exit, label %outer.header
}
; !llvm.loop.mustprogress makes the side-effect-free inner loop finite.
define void @mustprogress_subloop_still_predicated() {
; CHECK-LABEL: @mustprogress_subloop_still_predicated(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer.header:
; CHECK-NEXT: [[IV:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[OUTER_LATCH:%.*]] ]
; CHECK-NEXT: br label [[INNER_HEADER:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
; CHECK: inner.header:
; CHECK-NEXT: [[INNER_COND:%.*]] = icmp eq i8 [[IV]], 1
; CHECK-NEXT: br i1 [[INNER_COND]], label [[INNER_HEADER]], label [[OUTER_LATCH]], !llvm.loop [[LOOP0:![0-9]+]]
; CHECK: outer.latch:
; CHECK-NEXT: [[IV_NEXT]] = add nuw i8 [[IV]], 1
; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[OUTER_HEADER]]
;
entry:
br label %outer.header
outer.header:
%iv = phi i8 [ 0, %entry ], [ %iv.next, %outer.latch ]
br label %inner.header
exit:
ret void
inner.header:
%inner.cond = icmp eq i8 %iv, 1
br i1 %inner.cond, label %inner.header, label %outer.latch, !llvm.loop !0
outer.latch:
%iv.next = add nuw i8 %iv, 1
%outer.cond = icmp eq i8 %iv.next, -1
br i1 %outer.cond, label %exit, label %outer.header
}
; A mustprogress function makes the side-effect-free nest finite.
define void @mustprogress_function_subloop_predicated() mustprogress {
; CHECK-LABEL: @mustprogress_function_subloop_predicated(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer.header:
; CHECK-NEXT: [[IV:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[OUTER_LATCH:%.*]] ]
; CHECK-NEXT: br label [[INNER_HEADER:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
; CHECK: inner.header:
; CHECK-NEXT: [[INNER_COND:%.*]] = icmp eq i8 [[IV]], 1
; CHECK-NEXT: br i1 [[INNER_COND]], label [[INNER_HEADER]], label [[OUTER_LATCH]]
; CHECK: outer.latch:
; CHECK-NEXT: [[IV_NEXT]] = add nuw i8 [[IV]], 1
; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[OUTER_HEADER]]
;
entry:
br label %outer.header
outer.header:
%iv = phi i8 [ 0, %entry ], [ %iv.next, %outer.latch ]
br label %inner.header
exit:
ret void
inner.header:
%inner.cond = icmp eq i8 %iv, 1
br i1 %inner.cond, label %inner.header, label %outer.latch
outer.latch:
%iv.next = add nuw i8 %iv, 1
%outer.cond = icmp eq i8 %iv.next, -1
br i1 %outer.cond, label %exit, label %outer.header
}
; Likewise for willreturn.
define void @willreturn_function_subloop_predicated() willreturn {
; CHECK-LABEL: @willreturn_function_subloop_predicated(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer.header:
; CHECK-NEXT: [[IV:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[OUTER_LATCH:%.*]] ]
; CHECK-NEXT: br label [[INNER_HEADER:%.*]]
; CHECK: exit:
; CHECK-NEXT: ret void
; CHECK: inner.header:
; CHECK-NEXT: [[INNER_COND:%.*]] = icmp eq i8 [[IV]], 1
; CHECK-NEXT: br i1 [[INNER_COND]], label [[INNER_HEADER]], label [[OUTER_LATCH]]
; CHECK: outer.latch:
; CHECK-NEXT: [[IV_NEXT]] = add nuw i8 [[IV]], 1
; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[OUTER_HEADER]]
;
entry:
br label %outer.header
outer.header:
%iv = phi i8 [ 0, %entry ], [ %iv.next, %outer.latch ]
br label %inner.header
exit:
ret void
inner.header:
%inner.cond = icmp eq i8 %iv, 1
br i1 %inner.cond, label %inner.header, label %outer.latch
outer.latch:
%iv.next = add nuw i8 %iv, 1
%outer.cond = icmp eq i8 %iv.next, -1
br i1 %outer.cond, label %exit, label %outer.header
}
; The irreducible cycle may run forever (iv == 1), so predication is skipped.
define void @irreducible_cycle_skips_predication() {
; CHECK-LABEL: @irreducible_cycle_skips_predication(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer.header:
; CHECK-NEXT: [[IV:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[OUTER_LATCH:%.*]] ]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[IV]], 1
; CHECK-NEXT: br i1 [[C]], label [[IRR_A:%.*]], label [[IRR_B:%.*]]
; CHECK: irr.a:
; CHECK-NEXT: br i1 [[C]], label [[IRR_B]], label [[OUTER_LATCH]]
; CHECK: irr.b:
; CHECK-NEXT: br i1 [[C]], label [[IRR_A]], label [[OUTER_LATCH]]
; CHECK: exit:
; CHECK-NEXT: ret void
; CHECK: outer.latch:
; CHECK-NEXT: [[IV_NEXT]] = add nuw i8 [[IV]], 1
; CHECK-NEXT: [[OUTER_COND:%.*]] = icmp eq i8 [[IV_NEXT]], -1
; CHECK-NEXT: br i1 [[OUTER_COND]], label [[EXIT:%.*]], label [[OUTER_HEADER]]
;
entry:
br label %outer.header
outer.header:
%iv = phi i8 [ 0, %entry ], [ %iv.next, %outer.latch ]
%c = icmp eq i8 %iv, 1
br i1 %c, label %irr.a, label %irr.b
irr.a:
br i1 %c, label %irr.b, label %outer.latch
irr.b:
br i1 %c, label %irr.a, label %outer.latch
exit:
ret void
outer.latch:
%iv.next = add nuw i8 %iv, 1
%outer.cond = icmp eq i8 %iv.next, -1
br i1 %outer.cond, label %exit, label %outer.header
}
; !llvm.loop.mustprogress on the outer loop also covers the irreducible cycle.
define void @mustprogress_outer_irreducible_cycle_predicated() {
; CHECK-LABEL: @mustprogress_outer_irreducible_cycle_predicated(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer.header:
; CHECK-NEXT: [[IV:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[OUTER_LATCH:%.*]] ]
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[IV]], 1
; CHECK-NEXT: br i1 [[C]], label [[IRR_A:%.*]], label [[IRR_B:%.*]]
; CHECK: irr.a:
; CHECK-NEXT: br i1 [[C]], label [[IRR_B]], label [[OUTER_LATCH]]
; CHECK: irr.b:
; CHECK-NEXT: br i1 [[C]], label [[IRR_A]], label [[OUTER_LATCH]]
; CHECK: exit:
; CHECK-NEXT: ret void
; CHECK: outer.latch:
; CHECK-NEXT: [[IV_NEXT]] = add nuw i8 [[IV]], 1
; CHECK-NEXT: br i1 true, label [[EXIT:%.*]], label [[OUTER_HEADER]], !llvm.loop [[LOOP2:![0-9]+]]
;
entry:
br label %outer.header
outer.header:
%iv = phi i8 [ 0, %entry ], [ %iv.next, %outer.latch ]
%c = icmp eq i8 %iv, 1
br i1 %c, label %irr.a, label %irr.b
irr.a:
br i1 %c, label %irr.b, label %outer.latch
irr.b:
br i1 %c, label %irr.a, label %outer.latch
exit:
ret void
outer.latch:
%iv.next = add nuw i8 %iv, 1
%outer.cond = icmp eq i8 %iv.next, -1
br i1 %outer.cond, label %exit, label %outer.header, !llvm.loop !2
}
!0 = distinct !{!0, !1}
!1 = !{!"llvm.loop.mustprogress"}
!2 = distinct !{!2, !1}