mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
c3dd7f4b12
This patch adds the ability to peel off iterations of the first loop in loop fusion. This can allow for both loops to have the same trip count, making it legal for them to be fused together. Here is a simple scenario peeling can be used in loop fusion: for (i = 0; i < 10; ++i) a[i] = a[i] + 3; for (j = 1; j < 10; ++j) b[j] = b[j] + 5; Here is we can make use of peeling, and then fuse the two loops together. We can peel off the 0th iteration of the loop i, and then combine loop i and j for i = 1 to 10. a[0] = a[0] +3; for (i = 1; i < 10; ++i) { a[i] = a[i] + 3; b[i] = b[i] + 5; } Currently peeling with loop fusion is only supported for loops with constant trip counts and a single exit point. Both unguarded and guarded loops are supported. Reviewed By: bmahjour (Bardia Mahjour), MaskRay (Fangrui Song) Differential Revision: https://reviews.llvm.org/D82927
73 lines
2.8 KiB
LLVM
73 lines
2.8 KiB
LLVM
; RUN: opt -S -loop-fusion -loop-fusion-peel-max-count=3 < %s | FileCheck %s
|
|
|
|
; Tests that we do not fuse two guarded loops together.
|
|
; These loops do not have the same trip count, and the first loop meets the
|
|
; requirements for peeling. However, the exit block of the first loop makes the
|
|
; loops unsafe to fuse together.
|
|
; The expected output of this test is the function as below.
|
|
|
|
; CHECK-LABEL: void @unsafe_exitblock(i32* noalias %A, i32* noalias %B)
|
|
; CHECK: for.first.guard
|
|
; CHECK: br i1 %cmp3, label %for.first.preheader, label %for.second.guard
|
|
; CHECK: for.first.preheader:
|
|
; CHECK-NEXT: br label %for.first
|
|
; CHECK: for.first:
|
|
; CHECK: br i1 %cmp, label %for.first, label %for.first.exit
|
|
; CHECK: for.first.exit:
|
|
; CHECK-NEXT: call void @bar()
|
|
; CHECK-NEXT: br label %for.second.guard
|
|
; CHECK: for.second.guard:
|
|
; CHECK: br i1 %cmp21, label %for.second.preheader, label %for.end
|
|
; CHECK: for.second.preheader:
|
|
; CHECK-NEXT: br label %for.second
|
|
; CHECK: for.second:
|
|
; CHECK: br i1 %cmp2, label %for.second, label %for.second.exit
|
|
; CHECK: for.second.exit:
|
|
; CHECK-NEXT: br label %for.end
|
|
; CHECK: for.end:
|
|
; CHECK-NEXT: ret void
|
|
|
|
define void @unsafe_exitblock(i32* noalias %A, i32* noalias %B) {
|
|
for.first.guard:
|
|
%cmp3 = icmp slt i64 0, 45
|
|
br i1 %cmp3, label %for.first.preheader, label %for.second.guard
|
|
|
|
for.first.preheader: ; preds = %for.first.guard
|
|
br label %for.first
|
|
|
|
for.first: ; preds = %for.first.preheader, %for.first
|
|
%i.04 = phi i64 [ %inc, %for.first ], [ 0, %for.first.preheader ]
|
|
%arrayidx = getelementptr inbounds i32, i32* %A, i64 %i.04
|
|
store i32 0, i32* %arrayidx, align 4
|
|
%inc = add nsw i64 %i.04, 1
|
|
%cmp = icmp slt i64 %inc, 45
|
|
br i1 %cmp, label %for.first, label %for.first.exit
|
|
|
|
for.first.exit: ; preds = %for.first
|
|
call void @bar()
|
|
br label %for.second.guard
|
|
|
|
for.second.guard: ; preds = %for.first.exit, %for.first.guard
|
|
%cmp21 = icmp slt i64 2,45
|
|
br i1 %cmp21, label %for.second.preheader, label %for.end
|
|
|
|
for.second.preheader: ; preds = %for.second.guard
|
|
br label %for.second
|
|
|
|
for.second: ; preds = %for.second.preheader, %for.second
|
|
%j.02 = phi i64 [ %inc6, %for.second ], [ 2, %for.second.preheader ]
|
|
%arrayidx4 = getelementptr inbounds i32, i32* %B, i64 %j.02
|
|
store i32 0, i32* %arrayidx4, align 4
|
|
%inc6 = add nsw i64 %j.02, 1
|
|
%cmp2 = icmp slt i64 %inc6, 45
|
|
br i1 %cmp2, label %for.second, label %for.second.exit
|
|
|
|
for.second.exit: ; preds = %for.second
|
|
br label %for.end
|
|
|
|
for.end: ; preds = %for.second.exit, %for.second.guard
|
|
ret void
|
|
}
|
|
|
|
declare void @bar()
|