1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 04:02:41 +01:00
llvm-mirror/test/Transforms/IndVarSimplify/exit_value_tests.ll
Philip Reames 98ed51c042 [LoopPred] Enable new transformation by default
The basic idea of the transform is to convert variant loop exit conditions into invariant exit conditions by changing the iteration on which the exit is taken when we know that the trip count is unobservable.  See the original patch which introduced the code for a more complete explanation.

The individual parts of this have been reviewed, the result has been fuzzed, and then further analyzed by hand, but despite all of that, I will not be suprised to see breakage here.  If you see problems, please don't hesitate to revert - though please do provide a test case.  The most likely class of issues are latent SCEV bugs and without a reduced test case, I'll be essentially stuck on reducing them.

(Note: A bunch of tests were opted out of the new transform to preserve coverage.  That landed in a previous commit to simplify revert cycles if they turn out to be needed.)
2019-11-06 15:41:57 -08:00

246 lines
6.6 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -indvars -loop-deletion -simplifycfg -S | FileCheck %s
; Test that we can evaluate the exit values of various expression types. Since
; these loops all have predictable exit values we can replace the use outside
; of the loop with a closed-form computation.
define i32 @polynomial_constant() {
; <label>:0
; CHECK-LABEL: @polynomial_constant(
; CHECK-NEXT: Out:
; CHECK-NEXT: ret i32 500500
;
br label %Loop
Loop: ; preds = %Loop, %0
%A1 = phi i32 [ 0, %0 ], [ %A2, %Loop ] ; <i32> [#uses=3]
%B1 = phi i32 [ 0, %0 ], [ %B2, %Loop ] ; <i32> [#uses=1]
%A2 = add i32 %A1, 1 ; <i32> [#uses=1]
%B2 = add i32 %B1, %A1 ; <i32> [#uses=2]
%C = icmp eq i32 %A1, 1000 ; <i1> [#uses=1]
br i1 %C, label %Out, label %Loop
Out: ; preds = %Loop
ret i32 %B2
}
define i32 @NSquare(i32 %N) {
; <label>:0
; CHECK-LABEL: @NSquare(
; CHECK-NEXT: Out:
; CHECK-NEXT: [[Y:%.*]] = mul i32 [[N:%.*]], [[N]]
; CHECK-NEXT: ret i32 [[Y]]
;
br label %Loop
Loop: ; preds = %Loop, %0
%X = phi i32 [ 0, %0 ], [ %X2, %Loop ] ; <i32> [#uses=4]
%X2 = add i32 %X, 1 ; <i32> [#uses=1]
%c = icmp eq i32 %X, %N ; <i1> [#uses=1]
br i1 %c, label %Out, label %Loop
Out: ; preds = %Loop
%Y = mul i32 %X, %X ; <i32> [#uses=1]
ret i32 %Y
}
define i32 @NSquareOver2(i32 %N) {
; <label>:0
; CHECK-LABEL: @NSquareOver2(
; CHECK-NEXT: Out:
; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[N:%.*]] to i33
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[N]], -1
; CHECK-NEXT: [[TMP2:%.*]] = zext i32 [[TMP1]] to i33
; CHECK-NEXT: [[TMP3:%.*]] = mul i33 [[TMP0]], [[TMP2]]
; CHECK-NEXT: [[TMP4:%.*]] = lshr i33 [[TMP3]], 1
; CHECK-NEXT: [[TMP5:%.*]] = trunc i33 [[TMP4]] to i32
; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[N]], [[TMP5]]
; CHECK-NEXT: [[TMP7:%.*]] = add i32 [[TMP6]], 15
; CHECK-NEXT: ret i32 [[TMP7]]
;
br label %Loop
Loop: ; preds = %Loop, %0
%X = phi i32 [ 0, %0 ], [ %X2, %Loop ] ; <i32> [#uses=3]
%Y = phi i32 [ 15, %0 ], [ %Y2, %Loop ] ; <i32> [#uses=1]
%Y2 = add i32 %Y, %X ; <i32> [#uses=2]
%X2 = add i32 %X, 1 ; <i32> [#uses=1]
%c = icmp eq i32 %X, %N ; <i1> [#uses=1]
br i1 %c, label %Out, label %Loop
Out: ; preds = %Loop
ret i32 %Y2
}
define i32 @strength_reduced() {
; <label>:0
; CHECK-LABEL: @strength_reduced(
; CHECK-NEXT: Out:
; CHECK-NEXT: ret i32 500500
;
br label %Loop
Loop: ; preds = %Loop, %0
%A1 = phi i32 [ 0, %0 ], [ %A2, %Loop ] ; <i32> [#uses=3]
%B1 = phi i32 [ 0, %0 ], [ %B2, %Loop ] ; <i32> [#uses=1]
%A2 = add i32 %A1, 1 ; <i32> [#uses=1]
%B2 = add i32 %B1, %A1 ; <i32> [#uses=2]
%C = icmp eq i32 %A1, 1000 ; <i1> [#uses=1]
br i1 %C, label %Out, label %Loop
Out: ; preds = %Loop
ret i32 %B2
}
define i32 @chrec_equals() {
; CHECK-LABEL: @chrec_equals(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 101
;
entry:
br label %no_exit
no_exit: ; preds = %no_exit, %entry
%i0 = phi i32 [ 0, %entry ], [ %i1, %no_exit ] ; <i32> [#uses=3]
%ISq = mul i32 %i0, %i0 ; <i32> [#uses=1]
%i1 = add i32 %i0, 1 ; <i32> [#uses=2]
%tmp.1 = icmp ne i32 %ISq, 10000 ; <i1> [#uses=1]
br i1 %tmp.1, label %no_exit, label %loopexit
loopexit: ; preds = %no_exit
ret i32 %i1
}
define i16 @cast_chrec_test() {
; <label>:0
; CHECK-LABEL: @cast_chrec_test(
; CHECK-NEXT: Out:
; CHECK-NEXT: ret i16 1000
;
br label %Loop
Loop: ; preds = %Loop, %0
%A1 = phi i32 [ 0, %0 ], [ %A2, %Loop ] ; <i32> [#uses=2]
%B1 = trunc i32 %A1 to i16 ; <i16> [#uses=2]
%A2 = add i32 %A1, 1 ; <i32> [#uses=1]
%C = icmp eq i16 %B1, 1000 ; <i1> [#uses=1]
br i1 %C, label %Out, label %Loop
Out: ; preds = %Loop
ret i16 %B1
}
define i32 @linear_div_fold() {
; CHECK-LABEL: @linear_div_fold(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 34
;
entry:
br label %loop
loop: ; preds = %loop, %entry
%i = phi i32 [ 4, %entry ], [ %i.next, %loop ] ; <i32> [#uses=3]
%i.next = add i32 %i, 8 ; <i32> [#uses=1]
%RV = udiv i32 %i, 2 ; <i32> [#uses=1]
%c = icmp ne i32 %i, 68 ; <i1> [#uses=1]
br i1 %c, label %loop, label %loopexit
loopexit: ; preds = %loop
ret i32 %RV
}
define i32 @unroll_phi_select_constant_nonzero(i32 %arg1, i32 %arg2) {
; CHECK-LABEL: @unroll_phi_select_constant_nonzero(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 [[ARG2:%.*]]
;
entry:
br label %loop
loop:
%i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
%selector = phi i32 [%arg1, %entry], [%arg2, %loop]
%i.next = add nsw nuw i32 %i, 1
%c = icmp ult i32 %i, 4
br i1 %c, label %loop, label %loopexit
loopexit:
ret i32 %selector
}
declare i32 @f()
; After LCSSA formation, there's no LCSSA phi for %f since it isn't directly
; used outside the loop, and thus we can't directly replace %selector w/ %f.
define i32 @neg_unroll_phi_select_constant_nonzero(i32 %arg) {
; CHECK-LABEL: @neg_unroll_phi_select_constant_nonzero(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[SELECTOR:%.*]] = phi i32 [ [[ARG:%.*]], [[ENTRY]] ], [ [[F:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[F]] = call i32 @f()
; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i32 [[I]], 1
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[I]], 4
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[LOOPEXIT:%.*]]
; CHECK: loopexit:
; CHECK-NEXT: [[SELECTOR_LCSSA:%.*]] = phi i32 [ [[SELECTOR]], [[LOOP]] ]
; CHECK-NEXT: ret i32 [[SELECTOR_LCSSA]]
;
entry:
br label %loop
loop:
%i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
%selector = phi i32 [%arg, %entry], [%f, %loop]
%f = call i32 @f()
%i.next = add nsw nuw i32 %i, 1
%c = icmp ult i32 %i, 4
br i1 %c, label %loop, label %loopexit
loopexit:
ret i32 %selector
}
define i32 @unroll_phi_select_constant_zero(i32 %arg1, i32 %arg2) {
; CHECK-LABEL: @unroll_phi_select_constant_zero(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 [[ARG1:%.*]]
;
entry:
br label %loop
loop:
%i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
%selector = phi i32 [%arg1, %entry], [%arg2, %loop]
%i.next = add i32 %i, 1
%c = icmp ne i32 %i, 0
br i1 %c, label %loop, label %loopexit
loopexit:
ret i32 %selector
}
define i32 @unroll_phi_select(i32 %arg1, i32 %arg2, i16 %len) {
; CHECK-LABEL: @unroll_phi_select(
; CHECK-NEXT: entry:
; CHECK-NEXT: ret i32 [[ARG2:%.*]]
;
entry:
%length = zext i16 %len to i32
br label %loop
loop:
%i = phi i32 [ -1, %entry ], [ %i.next, %loop ]
%selector = phi i32 [%arg1, %entry], [%arg2, %loop]
%i.next = add nsw i32 %i, 1
%c = icmp slt i32 %i, %length
br i1 %c, label %loop, label %loopexit
loopexit:
ret i32 %selector
}