2019-06-04 01:41:12 +08:00
|
|
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
|
|
; RUN: opt < %s -indvars -S | FileCheck %s
|
|
|
|
; This is a collection of tests specifically for LFTR of multiple exit loops.
|
|
|
|
; The actual LFTR performed is trivial so as to focus on the loop structure
|
|
|
|
; aspects.
|
|
|
|
|
|
|
|
; Provide legal integer types.
|
|
|
|
target datalayout = "n8:16:32:64"
|
|
|
|
|
|
|
|
@A = external global i32
|
|
|
|
|
|
|
|
define void @analyzeable_early_exit(i32 %n) {
|
|
|
|
; CHECK-LABEL: @analyzeable_early_exit(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]]
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK: latch:
|
|
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store i32 [[IV]], i32* @A, align 4
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 1000
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]]
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
|
|
|
|
%earlycnd = icmp ult i32 %iv, %n
|
|
|
|
br i1 %earlycnd, label %latch, label %exit
|
|
|
|
|
|
|
|
latch:
|
|
|
|
%iv.next = add i32 %iv, 1
|
|
|
|
store i32 %iv, i32* @A
|
|
|
|
%c = icmp ult i32 %iv.next, 1000
|
|
|
|
br i1 %c, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
define void @unanalyzeable_early_exit() {
|
|
|
|
; CHECK-LABEL: @unanalyzeable_early_exit(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: [[VOL:%.*]] = load volatile i32, i32* @A, align 4
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK-NEXT: [[EARLYCND:%.*]] = icmp ne i32 [[VOL]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[EARLYCND]], label [[LATCH]], label [[EXIT:%.*]]
|
|
|
|
; CHECK: latch:
|
|
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store i32 [[IV]], i32* @A, align 4
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV_NEXT]], 1000
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT]]
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
|
|
|
|
%vol = load volatile i32, i32* @A
|
|
|
|
%earlycnd = icmp ne i32 %vol, 0
|
|
|
|
br i1 %earlycnd, label %latch, label %exit
|
|
|
|
|
|
|
|
latch:
|
|
|
|
%iv.next = add i32 %iv, 1
|
|
|
|
store i32 %iv, i32* @A
|
|
|
|
%c = icmp ult i32 %iv.next, 1000
|
|
|
|
br i1 %c, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
define void @multiple_early_exits(i32 %n, i32 %m) {
|
|
|
|
; CHECK-LABEL: @multiple_early_exits(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[CONTINUE:%.*]], label [[EXIT:%.*]]
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK: continue:
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store volatile i32 [[IV]], i32* @A, align 4
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV]], [[M:%.*]]
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LATCH]], label [[EXIT]]
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK: latch:
|
|
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store volatile i32 [[IV]], i32* @A, align 4
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND2:%.*]] = icmp ne i32 [[IV_NEXT]], 1000
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND2]], label [[LOOP]], label [[EXIT]]
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
|
|
|
|
%earlycnd = icmp ult i32 %iv, %n
|
|
|
|
br i1 %earlycnd, label %continue, label %exit
|
|
|
|
|
|
|
|
continue:
|
|
|
|
store volatile i32 %iv, i32* @A
|
|
|
|
%earlycnd2 = icmp ult i32 %iv, %m
|
|
|
|
br i1 %earlycnd2, label %latch, label %exit
|
|
|
|
|
|
|
|
latch:
|
|
|
|
%iv.next = add i32 %iv, 1
|
|
|
|
store volatile i32 %iv, i32* @A
|
|
|
|
%c = icmp ult i32 %iv.next, 1000
|
|
|
|
br i1 %c, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; Note: This slightly odd form is what indvars itself produces for multiple
|
|
|
|
; exits without a side effect between them.
|
|
|
|
define void @compound_early_exit(i32 %n, i32 %m) {
|
|
|
|
; CHECK-LABEL: @compound_early_exit(
|
|
|
|
; CHECK-NEXT: entry:
|
[NFCI] SCEVExpander: emit intrinsics for integral {u,s}{min,max} SCEV expressions
These intrinsics, not the icmp+select are the canonical form nowadays,
so we might as well directly emit them.
This should not cause any regressions, but if it does,
then then they would needed to be fixed regardless.
Note that this doesn't deal with `SCEVExpander::isHighCostExpansion()`,
but that is a pessimization, not a correctness issue.
Additionally, the non-intrinsic form has issues with undef,
see https://reviews.llvm.org/D88287#2587863
2021-02-26 21:48:58 +08:00
|
|
|
; CHECK-NEXT: [[UMIN:%.*]] = call i32 @llvm.umin.i32(i32 [[M:%.*]], i32 [[N:%.*]])
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
|
[SCEV] SCEVExpander::isHighCostExpansionHelper(): cost-model min/max (PR44668)
Summary:
Previosly we simply always said that `SCEVMinMaxExpr` is too costly to expand.
But this isn't really true, it expands into just a comparison+swap pair.
And again much like with add/mul, there will be one less such pair
than the number of operands. And we need to count the cost of operands themselves.
This does change a number of testcases, and as far as i can tell,
all of these changes are improvements, in the sense that
we fixed up more latches to do the [in]equality comparison.
This concludes cost-modelling changes, no other SCEV expressions exist as of now.
This is a part of addressing [[ https://bugs.llvm.org/show_bug.cgi?id=44668 | PR44668 ]].
Reviewers: reames, mkazantsev, wmi, sanjoy
Reviewed By: mkazantsev
Subscribers: hiraditya, javed.absar, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D73744
2020-02-26 02:52:46 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[UMIN]]
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]]
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK: latch:
|
|
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store volatile i32 [[IV]], i32* @A, align 4
|
[SCEV] SCEVExpander::isHighCostExpansionHelper(): cost-model min/max (PR44668)
Summary:
Previosly we simply always said that `SCEVMinMaxExpr` is too costly to expand.
But this isn't really true, it expands into just a comparison+swap pair.
And again much like with add/mul, there will be one less such pair
than the number of operands. And we need to count the cost of operands themselves.
This does change a number of testcases, and as far as i can tell,
all of these changes are improvements, in the sense that
we fixed up more latches to do the [in]equality comparison.
This concludes cost-modelling changes, no other SCEV expressions exist as of now.
This is a part of addressing [[ https://bugs.llvm.org/show_bug.cgi?id=44668 | PR44668 ]].
Reviewers: reames, mkazantsev, wmi, sanjoy
Reviewed By: mkazantsev
Subscribers: hiraditya, javed.absar, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D73744
2020-02-26 02:52:46 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 1000
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]]
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
|
|
|
|
%earlycnd = icmp ult i32 %iv, %n
|
|
|
|
%earlycnd2 = icmp ult i32 %iv, %m
|
|
|
|
%and = and i1 %earlycnd, %earlycnd2
|
|
|
|
br i1 %and, label %latch, label %exit
|
|
|
|
|
|
|
|
latch:
|
|
|
|
%iv.next = add i32 %iv, 1
|
|
|
|
store volatile i32 %iv, i32* @A
|
|
|
|
%c = icmp ult i32 %iv.next, 1000
|
|
|
|
br i1 %c, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
define void @unanalyzeable_latch(i32 %n) {
|
|
|
|
; CHECK-LABEL: @unanalyzeable_latch(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]]
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK: latch:
|
|
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store i32 [[IV]], i32* @A, align 4
|
|
|
|
; CHECK-NEXT: [[VOL:%.*]] = load volatile i32, i32* @A, align 4
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[VOL]], 1000
|
|
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
|
|
|
|
%earlycnd = icmp ult i32 %iv, %n
|
|
|
|
br i1 %earlycnd, label %latch, label %exit
|
|
|
|
|
|
|
|
latch:
|
|
|
|
%iv.next = add i32 %iv, 1
|
|
|
|
store i32 %iv, i32* @A
|
|
|
|
%vol = load volatile i32, i32* @A
|
|
|
|
%c = icmp ult i32 %vol, 1000
|
|
|
|
br i1 %c, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
define void @single_exit_no_latch(i32 %n) {
|
|
|
|
; CHECK-LABEL: @single_exit_no_latch(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
|
|
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]]
|
|
|
|
; CHECK: latch:
|
|
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store i32 [[IV]], i32* @A, align 4
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
|
|
|
|
%earlycnd = icmp ult i32 %iv, %n
|
|
|
|
br i1 %earlycnd, label %latch, label %exit
|
|
|
|
|
|
|
|
latch:
|
|
|
|
%iv.next = add i32 %iv, 1
|
|
|
|
store i32 %iv, i32* @A
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; Multiple exits which could be LFTRed, but the latch itself is not an
|
|
|
|
; exiting block.
|
|
|
|
define void @no_latch_exit(i32 %n, i32 %m) {
|
|
|
|
; CHECK-LABEL: @no_latch_exit(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[CONTINUE:%.*]], label [[EXIT:%.*]]
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK: continue:
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store volatile i32 [[IV]], i32* @A, align 4
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV]], [[M:%.*]]
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LATCH]], label [[EXIT]]
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK: latch:
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store volatile i32 [[IV]], i32* @A, align 4
|
2019-06-04 01:41:12 +08:00
|
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
|
|
|
|
%earlycnd = icmp ult i32 %iv, %n
|
|
|
|
br i1 %earlycnd, label %continue, label %exit
|
|
|
|
|
|
|
|
continue:
|
|
|
|
store volatile i32 %iv, i32* @A
|
|
|
|
%earlycnd2 = icmp ult i32 %iv, %m
|
|
|
|
br i1 %earlycnd2, label %latch, label %exit
|
|
|
|
|
|
|
|
latch:
|
|
|
|
store volatile i32 %iv, i32* @A
|
|
|
|
%iv.next = add i32 %iv, 1
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
2019-06-13 07:39:49 +08:00
|
|
|
|
|
|
|
;; Show the value of multiple exit LFTR (being able to eliminate all but
|
|
|
|
;; one IV when exit tests involve multiple IVs).
|
|
|
|
define void @combine_ivs(i32 %n) {
|
|
|
|
; CHECK-LABEL: @combine_ivs(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]]
|
2019-06-13 07:39:49 +08:00
|
|
|
; CHECK: latch:
|
|
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store volatile i32 [[IV]], i32* @A, align 4
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 999
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]]
|
2019-06-13 07:39:49 +08:00
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
|
|
|
|
%iv2 = phi i32 [ 1, %entry], [ %iv2.next, %latch]
|
|
|
|
%earlycnd = icmp ult i32 %iv, %n
|
|
|
|
br i1 %earlycnd, label %latch, label %exit
|
|
|
|
|
|
|
|
latch:
|
|
|
|
%iv.next = add i32 %iv, 1
|
|
|
|
%iv2.next = add i32 %iv2, 1
|
|
|
|
store volatile i32 %iv, i32* @A
|
|
|
|
%c = icmp ult i32 %iv2.next, 1000
|
|
|
|
br i1 %c, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; We can remove the decrementing IV entirely
|
|
|
|
define void @combine_ivs2(i32 %n) {
|
|
|
|
; CHECK-LABEL: @combine_ivs2(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]]
|
2019-06-13 07:39:49 +08:00
|
|
|
; CHECK: latch:
|
|
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store volatile i32 [[IV]], i32* @A, align 4
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 1000
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]]
|
2019-06-13 07:39:49 +08:00
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
|
|
|
|
%iv2 = phi i32 [ 1000, %entry], [ %iv2.next, %latch]
|
|
|
|
%earlycnd = icmp ult i32 %iv, %n
|
|
|
|
br i1 %earlycnd, label %latch, label %exit
|
|
|
|
|
|
|
|
latch:
|
|
|
|
%iv.next = add i32 %iv, 1
|
|
|
|
%iv2.next = sub i32 %iv2, 1
|
|
|
|
store volatile i32 %iv, i32* @A
|
|
|
|
%c = icmp ugt i32 %iv2.next, 0
|
|
|
|
br i1 %c, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
; An example where we can eliminate an f(i) computation entirely
|
|
|
|
; from a multiple exit loop with LFTR.
|
|
|
|
define void @simplify_exit_test(i32 %n) {
|
|
|
|
; CHECK-LABEL: @simplify_exit_test(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV]], [[N:%.*]]
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LATCH]], label [[EXIT:%.*]]
|
2019-06-13 07:39:49 +08:00
|
|
|
; CHECK: latch:
|
|
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store volatile i32 [[IV]], i32* @A, align 4
|
2019-06-20 05:58:25 +08:00
|
|
|
; CHECK-NEXT: [[EXITCOND1:%.*]] = icmp ne i32 [[IV_NEXT]], 65
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND1]], label [[LOOP]], label [[EXIT]]
|
2019-06-13 07:39:49 +08:00
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
|
|
|
|
%earlycnd = icmp ult i32 %iv, %n
|
|
|
|
br i1 %earlycnd, label %latch, label %exit
|
|
|
|
|
|
|
|
latch:
|
|
|
|
%iv.next = add i32 %iv, 1
|
|
|
|
%fx = shl i32 %iv, 4
|
|
|
|
store volatile i32 %iv, i32* @A
|
|
|
|
%c = icmp ult i32 %fx, 1024
|
|
|
|
br i1 %c, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
; Another example where we can remove an f(i) type computation, but this
|
|
|
|
; time in a loop w/o a statically computable exit count.
|
|
|
|
define void @simplify_exit_test2(i32 %n) {
|
|
|
|
; CHECK-LABEL: @simplify_exit_test2(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
|
|
; CHECK: loop:
|
|
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH:%.*]] ]
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: [[VOL:%.*]] = load volatile i32, i32* @A, align 4
|
2019-06-13 07:39:49 +08:00
|
|
|
; CHECK-NEXT: [[EARLYCND:%.*]] = icmp ne i32 [[VOL]], 0
|
|
|
|
; CHECK-NEXT: br i1 [[EARLYCND]], label [[LATCH]], label [[EXIT:%.*]]
|
|
|
|
; CHECK: latch:
|
|
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
|
|
; CHECK-NEXT: [[FX:%.*]] = udiv i32 [[IV]], 4
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store volatile i32 [[IV]], i32* @A, align 4
|
2019-06-13 07:39:49 +08:00
|
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[FX]], 1024
|
|
|
|
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
br label %loop
|
|
|
|
|
|
|
|
loop:
|
|
|
|
%iv = phi i32 [ 0, %entry], [ %iv.next, %latch]
|
|
|
|
%vol = load volatile i32, i32* @A
|
|
|
|
%earlycnd = icmp ne i32 %vol, 0
|
|
|
|
br i1 %earlycnd, label %latch, label %exit
|
|
|
|
|
|
|
|
latch:
|
|
|
|
%iv.next = add i32 %iv, 1
|
|
|
|
%fx = udiv i32 %iv, 4
|
|
|
|
store volatile i32 %iv, i32* @A
|
|
|
|
%c = icmp ult i32 %fx, 1024
|
|
|
|
br i1 %c, label %loop, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|
2019-06-21 01:16:53 +08:00
|
|
|
|
|
|
|
; Demonstrate a case where two nested loops share a single exiting block.
|
|
|
|
; The key point is that the exit count is *different* for the two loops, and
|
|
|
|
; thus we can't rewrite the exit for the outer one. There are three sub-cases
|
|
|
|
; which can happen here: a) the outer loop has a backedge taken count of zero
|
|
|
|
; (for the case where we know the inner exit is known taken), b) the exit is
|
|
|
|
; known never taken (but may have an exit count outside the range of the IV)
|
|
|
|
; or c) the outer loop has an unanalyzable exit count (where we can't tell).
|
|
|
|
define void @nested(i32 %n) {
|
|
|
|
; CHECK-LABEL: @nested(
|
|
|
|
; CHECK-NEXT: entry:
|
|
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N:%.*]], 1
|
|
|
|
; CHECK-NEXT: br label [[OUTER:%.*]]
|
|
|
|
; CHECK: outer:
|
|
|
|
; CHECK-NEXT: [[IV1:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV1_NEXT:%.*]], [[OUTER_LATCH:%.*]] ]
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store volatile i32 [[IV1]], i32* @A, align 4
|
2019-06-21 01:16:53 +08:00
|
|
|
; CHECK-NEXT: [[IV1_NEXT]] = add nuw nsw i32 [[IV1]], 1
|
|
|
|
; CHECK-NEXT: br label [[INNER:%.*]]
|
|
|
|
; CHECK: inner:
|
|
|
|
; CHECK-NEXT: [[IV2:%.*]] = phi i32 [ 0, [[OUTER]] ], [ [[IV2_NEXT:%.*]], [[INNER_LATCH:%.*]] ]
|
2020-09-08 12:14:36 +08:00
|
|
|
; CHECK-NEXT: store volatile i32 [[IV2]], i32* @A, align 4
|
2019-06-21 01:16:53 +08:00
|
|
|
; CHECK-NEXT: [[IV2_NEXT]] = add nuw nsw i32 [[IV2]], 1
|
|
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[IV2]], 20
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[INNER_LATCH]], label [[EXIT_LOOPEXIT:%.*]]
|
|
|
|
; CHECK: inner_latch:
|
|
|
|
; CHECK-NEXT: [[EXITCOND2:%.*]] = icmp ne i32 [[IV2_NEXT]], [[TMP0]]
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND2]], label [[INNER]], label [[OUTER_LATCH]]
|
|
|
|
; CHECK: outer_latch:
|
|
|
|
; CHECK-NEXT: [[EXITCOND3:%.*]] = icmp ne i32 [[IV1_NEXT]], 21
|
|
|
|
; CHECK-NEXT: br i1 [[EXITCOND3]], label [[OUTER]], label [[EXIT_LOOPEXIT1:%.*]]
|
|
|
|
; CHECK: exit.loopexit:
|
|
|
|
; CHECK-NEXT: br label [[EXIT:%.*]]
|
|
|
|
; CHECK: exit.loopexit1:
|
|
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
|
|
; CHECK: exit:
|
|
|
|
; CHECK-NEXT: ret void
|
|
|
|
;
|
|
|
|
entry:
|
|
|
|
br label %outer
|
|
|
|
|
|
|
|
outer:
|
|
|
|
%iv1 = phi i32 [ 0, %entry ], [ %iv1.next, %outer_latch ]
|
|
|
|
store volatile i32 %iv1, i32* @A
|
|
|
|
%iv1.next = add i32 %iv1, 1
|
|
|
|
br label %inner
|
|
|
|
|
|
|
|
inner:
|
|
|
|
%iv2 = phi i32 [ 0, %outer ], [ %iv2.next, %inner_latch ]
|
|
|
|
store volatile i32 %iv2, i32* @A
|
|
|
|
%iv2.next = add i32 %iv2, 1
|
|
|
|
%innertest = icmp ult i32 %iv2, 20
|
|
|
|
br i1 %innertest, label %inner_latch, label %exit
|
|
|
|
|
|
|
|
inner_latch:
|
|
|
|
%innertestb = icmp ult i32 %iv2, %n
|
|
|
|
br i1 %innertestb, label %inner, label %outer_latch
|
|
|
|
|
|
|
|
outer_latch:
|
|
|
|
%outertest = icmp ult i32 %iv1, 20
|
|
|
|
br i1 %outertest, label %outer, label %exit
|
|
|
|
|
|
|
|
exit:
|
|
|
|
ret void
|
|
|
|
}
|