Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[IRCE] Smarter detection of empty ranges using SCEV
For a SCEV range, this patch replaces the naive emptiness check for SCEV ranges which looks like `Begin == End` with a SCEV check. The range is guaranteed to be empty of `Begin >= End`. We should filter such ranges out and do not try to perform IRCE for them. For example, we can get such range when intersecting range `[A, B)` and `[C, D)` where `A < B < C < D`. The resulting range is `[max(A, C), min(B, D)) = [C, B)`. This range is empty, but its `Begin` does not match with `End`. Making IRCE for an empty range is basically safe but unprofitable because we never actually get into the main loop where the range checks are supposed to be eliminated. This patch uses SCEV mechanisms to treat loops with proved `Begin >= End` as empty. Differential Revision: https://reviews.llvm.org/D39082 llvm-svn: 316550
- Loading branch information
Max Kazantsev
committed
Oct 25, 2017
1 parent
f012360
commit 4332a94
Showing
3 changed files
with
88 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
; RUN: opt -verify-loop-info -irce-print-changed-loops -irce -irce-allow-unsigned-latch=true -S | ||
|
||
|
||
; Make sure that IRCE doesn't apply in case of empty ranges. | ||
; (i + 30 < 40) if i in [-30, 10). | ||
; Intersected with iteration space, it is [0, 10). | ||
; (i - 60 < 40) if i in [60 , 100). | ||
; The intersection with safe iteration space is the empty range [60, 10). | ||
; It is better to eliminate one range check than attempt to eliminate both given | ||
; that we will never go to the main loop in the latter case and basically | ||
; only duplicate code with no benefits. | ||
|
||
define void @test_01(i32* %arr, i32* %a_len_ptr) #0 { | ||
|
||
; CHECK-LABEL: test_01( | ||
; CHECK-NOT: preloop | ||
; CHECK: entry: | ||
; CHECK-NEXT: br i1 true, label %loop.preheader, label %main.pseudo.exit | ||
; CHECK: in.bounds.1: | ||
; CHECK-NEXT: %addr = getelementptr i32, i32* %arr, i32 %idx | ||
; CHECK-NEXT: store i32 0, i32* %addr | ||
; CHECK-NEXT: %off1 = add i32 %idx, 30 | ||
; CHECK-NEXT: %c2 = icmp slt i32 %off1, 40 | ||
; CHECK-NEXT: br i1 true, label %in.bounds.2, label %exit.loopexit2 | ||
; CHECK: in.bounds.2: | ||
; CHECK-NEXT: %off2 = add i32 %idx, -60 | ||
; CHECK-NEXT: %c3 = icmp slt i32 %off2, 40 | ||
; CHECK-NEXT: br i1 %c3, label %in.bounds.3, label %exit.loopexit2 | ||
; CHECK: in.bounds.3: | ||
; CHECK-NEXT: %next = icmp ult i32 %idx.next, 100 | ||
; CHECK-NEXT: [[COND1:%[^ ]+]] = icmp ult i32 %idx.next, 10 | ||
; CHECK-NEXT: br i1 [[COND1]], label %loop, label %main.exit.selector | ||
; CHECK: main.exit.selector: | ||
; CHECK-NEXT: %idx.next.lcssa = phi i32 [ %idx.next, %in.bounds.3 ] | ||
; CHECK-NEXT: [[COND2:%[^ ]+]] = icmp ult i32 %idx.next.lcssa, 100 | ||
; CHECK-NEXT: br i1 [[COND2]], label %main.pseudo.exit, label %exit | ||
; CHECK: postloop: | ||
|
||
entry: | ||
br label %loop | ||
|
||
loop: | ||
%idx = phi i32 [ 0, %entry ], [ %idx.next, %in.bounds.3 ] | ||
%idx.next = add nsw nuw i32 %idx, 1 | ||
%c1 = icmp slt i32 %idx, 20 | ||
br i1 %c1, label %in.bounds.1, label %out.of.bounds | ||
|
||
in.bounds.1: | ||
%addr = getelementptr i32, i32* %arr, i32 %idx | ||
store i32 0, i32* %addr | ||
%off1 = add i32 %idx, 30 | ||
%c2 = icmp slt i32 %off1, 40 | ||
br i1 %c2, label %in.bounds.2, label %exit | ||
|
||
in.bounds.2: | ||
%off2 = add i32 %idx, -60 | ||
%c3 = icmp slt i32 %off2, 40 | ||
br i1 %c3, label %in.bounds.3, label %exit | ||
|
||
in.bounds.3: | ||
%next = icmp ult i32 %idx.next, 100 | ||
br i1 %next, label %loop, label %exit | ||
|
||
out.of.bounds: | ||
ret void | ||
|
||
exit: | ||
ret void | ||
} |