1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00
llvm-mirror/test/Transforms/IndVarSimplify/eliminate-exit.ll
Florian Hahn df7e45dd98 [SCEV] By more careful when traversing phis in isImpliedViaMerge.
I think currently isImpliedViaMerge can incorrectly return true for phis
in a loop/cycle, if the found condition involves the previous value of

Consider the case in exit_cond_depends_on_inner_loop.

At some point, we call (modulo simplifications)
isImpliedViaMerge(<=, %x.lcssa, -1, %call, -1).

The existing code tries to prove IncV <= -1 for all incoming values
InvV using the found condition (%call <= -1). At the moment this succeeds,
but only because it does not compare the same runtime value. The found
condition checks the value of the last iteration, but the incoming value
is from the *previous* iteration.

Hence we incorrectly determine that the *previous* value was <= -1,
which may not be true.

I think we need to be more careful when looking at the incoming values
here. In particular, we need to rule out that a found condition refers to
any value that may refer to one of the previous iterations. I'm not sure
there's a reliable way to do so (that also works of irreducible control
flow).

So for now this patch adds an additional requirement that the incoming
value must properly dominate the phi block. This should ensure the
values do not change in a cycle. I am not entirely sure if will catch
all cases and I appreciate a through second look in that regard.

Alternatively we could also unconditionally bail out in this case,
instead of checking the incoming values

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D101829
2021-05-07 19:52:29 +01:00

495 lines
16 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -indvars -S < %s | FileCheck %s
define void @ult(i64 %n, i64 %m) {
; CHECK-LABEL: @ult(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP0:%.*]] = icmp ult i64 [[N:%.*]], [[M:%.*]]
; CHECK-NEXT: br i1 [[CMP0]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i64 [[IV]], [[N]]
; CHECK-NEXT: br i1 [[CMP1]], label [[LATCH]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: latch:
; CHECK-NEXT: call void @side_effect()
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[EXIT_LOOPEXIT]]
; CHECK: exit.loopexit:
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp0 = icmp ult i64 %n, %m
br i1 %cmp0, label %loop, label %exit
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ]
%iv.next = add i64 %iv, 1
%cmp1 = icmp ult i64 %iv, %n
br i1 %cmp1, label %latch, label %exit
latch:
call void @side_effect()
%cmp2 = icmp ult i64 %iv, %m
br i1 %cmp2, label %loop, label %exit
exit:
ret void
}
define void @ugt(i64 %n, i64 %m) {
; CHECK-LABEL: @ugt(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP0:%.*]] = icmp ugt i64 [[N:%.*]], [[M:%.*]]
; CHECK-NEXT: br i1 [[CMP0]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: br i1 true, label [[LATCH]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: latch:
; CHECK-NEXT: call void @side_effect()
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i64 [[IV]], [[M]]
; CHECK-NEXT: br i1 [[CMP2]], label [[LOOP]], label [[EXIT_LOOPEXIT]]
; CHECK: exit.loopexit:
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp0 = icmp ugt i64 %n, %m
br i1 %cmp0, label %loop, label %exit
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ]
%iv.next = add i64 %iv, 1
%cmp1 = icmp ult i64 %iv, %n
br i1 %cmp1, label %latch, label %exit
latch:
call void @side_effect()
%cmp2 = icmp ult i64 %iv, %m
br i1 %cmp2, label %loop, label %exit
exit:
ret void
}
define void @ule(i64 %n, i64 %m) {
; CHECK-LABEL: @ule(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP0:%.*]] = icmp ule i64 [[N:%.*]], [[M:%.*]]
; CHECK-NEXT: br i1 [[CMP0]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i64 [[IV]], [[N]]
; CHECK-NEXT: br i1 [[CMP1]], label [[LATCH]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: latch:
; CHECK-NEXT: call void @side_effect()
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i64 [[IV]], [[M]]
; CHECK-NEXT: br i1 [[CMP2]], label [[LOOP]], label [[EXIT_LOOPEXIT]]
; CHECK: exit.loopexit:
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp0 = icmp ule i64 %n, %m
br i1 %cmp0, label %loop, label %exit
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ]
%iv.next = add i64 %iv, 1
%cmp1 = icmp ult i64 %iv, %n
br i1 %cmp1, label %latch, label %exit
latch:
call void @side_effect()
%cmp2 = icmp ult i64 %iv, %m
br i1 %cmp2, label %loop, label %exit
exit:
ret void
}
define void @uge(i64 %n, i64 %m) {
; CHECK-LABEL: @uge(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP0:%.*]] = icmp uge i64 [[N:%.*]], [[M:%.*]]
; CHECK-NEXT: br i1 [[CMP0]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i64 [[IV]], [[N]]
; CHECK-NEXT: br i1 [[CMP1]], label [[LATCH]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: latch:
; CHECK-NEXT: call void @side_effect()
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i64 [[IV]], [[M]]
; CHECK-NEXT: br i1 [[CMP2]], label [[LOOP]], label [[EXIT_LOOPEXIT]]
; CHECK: exit.loopexit:
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp0 = icmp uge i64 %n, %m
br i1 %cmp0, label %loop, label %exit
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ]
%iv.next = add i64 %iv, 1
%cmp1 = icmp ult i64 %iv, %n
br i1 %cmp1, label %latch, label %exit
latch:
call void @side_effect()
%cmp2 = icmp ult i64 %iv, %m
br i1 %cmp2, label %loop, label %exit
exit:
ret void
}
define void @ult_const_max(i64 %n) {
; CHECK-LABEL: @ult_const_max(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP0:%.*]] = icmp ult i64 [[N:%.*]], 20
; CHECK-NEXT: br i1 [[CMP0]], label [[LOOP_PREHEADER:%.*]], label [[EXIT:%.*]]
; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: br i1 true, label [[LATCH]], label [[EXIT_LOOPEXIT:%.*]]
; CHECK: latch:
; CHECK-NEXT: call void @side_effect()
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i64 [[IV]], [[N]]
; CHECK-NEXT: br i1 [[CMP2]], label [[LOOP]], label [[EXIT_LOOPEXIT]]
; CHECK: exit.loopexit:
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%cmp0 = icmp ult i64 %n, 20
br i1 %cmp0, label %loop, label %exit
loop:
%iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ]
%iv.next = add i64 %iv, 1
%udiv = udiv i64 %iv, 10
%cmp1 = icmp ult i64 %udiv, 2
br i1 %cmp1, label %latch, label %exit
latch:
call void @side_effect()
%cmp2 = icmp ult i64 %iv, %n
br i1 %cmp2, label %loop, label %exit
exit:
ret void
}
define void @mixed_width(i32 %len) {
; CHECK-LABEL: @mixed_width(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[LEN_ZEXT:%.*]] = zext i32 [[LEN:%.*]] to i64
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i64 [[IV]], [[LEN_ZEXT]]
; CHECK-NEXT: br i1 [[CMP1]], label [[BACKEDGE]], label [[EXIT:%.*]]
; CHECK: backedge:
; CHECK-NEXT: call void @side_effect()
; CHECK-NEXT: br i1 true, label [[LOOP]], label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
%len.zext = zext i32 %len to i64
br label %loop
loop:
%iv = phi i64 [0, %entry], [%iv.next, %backedge]
%iv2 = phi i32 [0, %entry], [%iv2.next, %backedge]
%iv.next = add i64 %iv, 1
%iv2.next = add i32 %iv2, 1
%cmp1 = icmp ult i64 %iv, %len.zext
br i1 %cmp1, label %backedge, label %exit
backedge:
call void @side_effect()
%cmp2 = icmp ult i32 %iv2, %len
br i1 %cmp2, label %loop, label %exit
exit:
ret void
}
define void @many_exits([100 x i64] %len) {
entry:
br label %loop
loop:
%iv = phi i64 [0, %entry], [%iv.next, %backedge]
%len0 = extractvalue [100 x i64] %len, 0
%early0 = icmp eq i64 %iv, %len0
call void @side_effect()
br i1 %early0, label %exit, label %cont0
cont0:
%len1 = extractvalue [100 x i64] %len, 1
%early1 = icmp eq i64 %iv, %len1
call void @side_effect()
br i1 %early1, label %exit, label %cont1
cont1:
%len2 = extractvalue [100 x i64] %len, 2
%early2 = icmp eq i64 %iv, %len2
call void @side_effect()
br i1 %early2, label %exit, label %cont2
cont2:
%len3 = extractvalue [100 x i64] %len, 3
%early3 = icmp eq i64 %iv, %len3
call void @side_effect()
br i1 %early3, label %exit, label %cont3
cont3:
%len4 = extractvalue [100 x i64] %len, 4
%early4 = icmp eq i64 %iv, %len4
call void @side_effect()
br i1 %early4, label %exit, label %cont4
cont4:
%len5 = extractvalue [100 x i64] %len, 5
%early5 = icmp eq i64 %iv, %len5
call void @side_effect()
br i1 %early5, label %exit, label %cont5
cont5:
%len6 = extractvalue [100 x i64] %len, 6
%early6 = icmp eq i64 %iv, %len6
call void @side_effect()
br i1 %early6, label %exit, label %cont6
cont6:
%len7 = extractvalue [100 x i64] %len, 7
%early7 = icmp eq i64 %iv, %len7
call void @side_effect()
br i1 %early7, label %exit, label %cont7
cont7:
%len8 = extractvalue [100 x i64] %len, 8
%early8 = icmp eq i64 %iv, %len8
call void @side_effect()
br i1 %early8, label %exit, label %cont8
cont8:
%len9 = extractvalue [100 x i64] %len, 9
%early9 = icmp eq i64 %iv, %len9
call void @side_effect()
br i1 %early9, label %exit, label %cont9
cont9:
%len10 = extractvalue [100 x i64] %len, 10
%early10 = icmp eq i64 %iv, %len10
call void @side_effect()
br i1 %early10, label %exit, label %cont10
cont10:
%len11 = extractvalue [100 x i64] %len, 11
%early11 = icmp eq i64 %iv, %len11
call void @side_effect()
br i1 %early11, label %exit, label %cont11
cont11:
%len12 = extractvalue [100 x i64] %len, 12
%early12 = icmp eq i64 %iv, %len12
call void @side_effect()
br i1 %early12, label %exit, label %cont12
cont12:
%len13 = extractvalue [100 x i64] %len, 13
%early13 = icmp eq i64 %iv, %len13
call void @side_effect()
br i1 %early13, label %exit, label %cont13
cont13:
%len14 = extractvalue [100 x i64] %len, 14
%early14 = icmp eq i64 %iv, %len14
call void @side_effect()
br i1 %early14, label %exit, label %cont14
cont14:
%len15 = extractvalue [100 x i64] %len, 15
%early15 = icmp eq i64 %iv, %len15
call void @side_effect()
br i1 %early15, label %exit, label %cont15
cont15:
%len16 = extractvalue [100 x i64] %len, 16
%early16 = icmp eq i64 %iv, %len16
call void @side_effect()
br i1 %early16, label %exit, label %cont16
cont16:
%len17 = extractvalue [100 x i64] %len, 17
%early17 = icmp eq i64 %iv, %len17
call void @side_effect()
br i1 %early17, label %exit, label %cont17
cont17:
%len18 = extractvalue [100 x i64] %len, 18
%early18 = icmp eq i64 %iv, %len18
call void @side_effect()
br i1 %early18, label %exit, label %cont18
cont18:
%len19 = extractvalue [100 x i64] %len, 19
%early19 = icmp eq i64 %iv, %len19
call void @side_effect()
br i1 %early19, label %exit, label %cont19
cont19:
%len20 = extractvalue [100 x i64] %len, 20
%early20 = icmp eq i64 %iv, %len20
call void @side_effect()
br i1 %early20, label %exit, label %cont20
cont20:
%len21 = extractvalue [100 x i64] %len, 21
%early21 = icmp eq i64 %iv, %len21
call void @side_effect()
br i1 %early21, label %exit, label %cont21
cont21:
%len22 = extractvalue [100 x i64] %len, 22
%early22 = icmp eq i64 %iv, %len22
call void @side_effect()
br i1 %early22, label %exit, label %cont22
cont22:
%len23 = extractvalue [100 x i64] %len, 23
%early23 = icmp eq i64 %iv, %len23
call void @side_effect()
br i1 %early23, label %exit, label %cont23
cont23:
%len24 = extractvalue [100 x i64] %len, 24
%early24 = icmp eq i64 %iv, %len24
call void @side_effect()
br i1 %early24, label %exit, label %cont24
cont24:
%len25 = extractvalue [100 x i64] %len, 25
%early25 = icmp eq i64 %iv, %len25
call void @side_effect()
br i1 %early25, label %exit, label %cont25
cont25:
%len26 = extractvalue [100 x i64] %len, 26
%early26 = icmp eq i64 %iv, %len26
call void @side_effect()
br i1 %early26, label %exit, label %cont26
cont26:
%len27 = extractvalue [100 x i64] %len, 27
%early27 = icmp eq i64 %iv, %len27
call void @side_effect()
br i1 %early27, label %exit, label %cont27
cont27:
%len28 = extractvalue [100 x i64] %len, 28
%early28 = icmp eq i64 %iv, %len28
call void @side_effect()
br i1 %early28, label %exit, label %cont28
cont28:
%len29 = extractvalue [100 x i64] %len, 29
%early29 = icmp eq i64 %iv, %len29
call void @side_effect()
br i1 %early29, label %exit, label %cont29
cont29:
%len30 = extractvalue [100 x i64] %len, 30
%early30 = icmp eq i64 %iv, %len30
call void @side_effect()
br i1 %early30, label %exit, label %cont30
cont30:
%len31 = extractvalue [100 x i64] %len, 31
%early31 = icmp eq i64 %iv, %len31
call void @side_effect()
br i1 %early31, label %exit, label %cont31
cont31:
%len32 = extractvalue [100 x i64] %len, 32
%early32 = icmp eq i64 %iv, %len32
call void @side_effect()
br i1 %early32, label %exit, label %cont32
cont32:
%len33 = extractvalue [100 x i64] %len, 33
%early33 = icmp eq i64 %iv, %len33
call void @side_effect()
br i1 %early33, label %exit, label %cont33
cont33:
%len34 = extractvalue [100 x i64] %len, 34
%early34 = icmp eq i64 %iv, %len34
call void @side_effect()
br i1 %early34, label %exit, label %cont34
cont34:
%len35 = extractvalue [100 x i64] %len, 35
%early35 = icmp eq i64 %iv, %len35
call void @side_effect()
br i1 %early35, label %exit, label %cont35
cont35:
%len36 = extractvalue [100 x i64] %len, 36
%early36 = icmp eq i64 %iv, %len36
call void @side_effect()
br i1 %early36, label %exit, label %cont36
cont36:
%len37 = extractvalue [100 x i64] %len, 37
%early37 = icmp eq i64 %iv, %len37
call void @side_effect()
br i1 %early37, label %exit, label %cont37
cont37:
%len38 = extractvalue [100 x i64] %len, 38
%early38 = icmp eq i64 %iv, %len38
call void @side_effect()
br i1 %early38, label %exit, label %cont38
cont38:
%len39 = extractvalue [100 x i64] %len, 39
%early39 = icmp eq i64 %iv, %len39
call void @side_effect()
br i1 %early39, label %exit, label %cont39
cont39:
br label %backedge
backedge:
call void @side_effect()
%cmp2 = icmp ult i64 %iv, 999
%iv.next = add i64 %iv, 1
br i1 %cmp2, label %loop, label %exit
exit:
ret void
}
declare void @side_effect()
; The exit condition %outer.cond.1 depends on a phi in %inner. Make sure we do
; not incorrectly determine %x.lcssa <= -1.
define i32 @exit_cond_depends_on_inner_loop() {
; CHECK-LABEL: @exit_cond_depends_on_inner_loop(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer.header:
; CHECK-NEXT: [[IV_OUTER:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_OUTER_NEXT:%.*]], [[OUTER_LATCH:%.*]] ]
; CHECK-NEXT: br label [[INNER:%.*]]
; CHECK: inner:
; CHECK-NEXT: [[X:%.*]] = phi i32 [ -1, [[OUTER_HEADER]] ], [ [[CALL:%.*]], [[INNER]] ]
; CHECK-NEXT: [[CALL]] = call i32 @match()
; CHECK-NEXT: [[INNER_COND:%.*]] = icmp sgt i32 [[CALL]], -1
; CHECK-NEXT: br i1 [[INNER_COND]], label [[INNER]], label [[OUTER_EXITING_1:%.*]]
; CHECK: outer.exiting.1:
; CHECK-NEXT: [[X_LCSSA:%.*]] = phi i32 [ [[X]], [[INNER]] ]
; CHECK-NEXT: [[OUTER_COND_1:%.*]] = icmp sgt i32 [[X_LCSSA]], -1
; CHECK-NEXT: br i1 [[OUTER_COND_1]], label [[EXIT:%.*]], label [[OUTER_LATCH]]
; CHECK: outer.latch:
; CHECK-NEXT: [[IV_OUTER_NEXT]] = add nuw nsw i32 [[IV_OUTER]], 1
; CHECK-NEXT: [[OUTER_COND_2:%.*]] = icmp ult i32 [[IV_OUTER]], 100
; CHECK-NEXT: br i1 [[OUTER_COND_2]], label [[OUTER_HEADER]], label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[X_RES:%.*]] = phi i32 [ [[X_LCSSA]], [[OUTER_EXITING_1]] ], [ -1, [[OUTER_LATCH]] ]
; CHECK-NEXT: ret i32 [[X_RES]]
;
entry:
br label %outer.header
outer.header:
%iv.outer = phi i32 [ 0, %entry ], [ %iv.outer.next , %outer.latch ]
br label %inner
inner:
%x = phi i32 [ -1, %outer.header ], [ %call, %inner ]
%call = call i32 @match()
%inner.cond = icmp sgt i32 %call, -1
br i1 %inner.cond, label %inner, label %outer.exiting.1
outer.exiting.1:
%x.lcssa = phi i32 [ %x, %inner ]
%outer.cond.1 = icmp sgt i32 %x.lcssa, -1
br i1 %outer.cond.1, label %exit, label %outer.latch
outer.latch:
%iv.outer.next = add nuw nsw i32 %iv.outer, 1
%outer.cond.2 = icmp ult i32 %iv.outer, 100
br i1 %outer.cond.2, label %outer.header, label %exit
exit:
%x.res = phi i32 [ %x.lcssa, %outer.exiting.1 ], [ -1, %outer.latch ]
ret i32 %x.res
}
declare i32 @match()