diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:41:05 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:41:05 +0000 |
| commit | 01095a5d43bbfde13731688ddcf6048ebb8b7721 (patch) | |
| tree | 4def12e759965de927d963ac65840d663ef9d1ea /test/Transforms/LoopLoadElim | |
| parent | f0f4822ed4b66e3579e92a89f368f8fb860e218e (diff) | |
Notes
Diffstat (limited to 'test/Transforms/LoopLoadElim')
| -rw-r--r-- | test/Transforms/LoopLoadElim/cond-load.ll | 42 | ||||
| -rw-r--r-- | test/Transforms/LoopLoadElim/forward.ll | 2 | ||||
| -rw-r--r-- | test/Transforms/LoopLoadElim/loop-simplify-dep.ll | 33 | ||||
| -rw-r--r-- | test/Transforms/LoopLoadElim/non-consecutive.ll | 43 | ||||
| -rw-r--r-- | test/Transforms/LoopLoadElim/opt-size.ll | 76 | ||||
| -rw-r--r-- | test/Transforms/LoopLoadElim/symbolic-stride.ll | 92 | ||||
| -rw-r--r-- | test/Transforms/LoopLoadElim/type-mismatch.ll | 89 |
7 files changed, 376 insertions, 1 deletions
diff --git a/test/Transforms/LoopLoadElim/cond-load.ll b/test/Transforms/LoopLoadElim/cond-load.ll new file mode 100644 index 000000000000..e337397e9969 --- /dev/null +++ b/test/Transforms/LoopLoadElim/cond-load.ll @@ -0,0 +1,42 @@ +; RUN: opt -S -loop-load-elim < %s | FileCheck %s + +; We can't hoist conditional loads to the preheader for the initial value. +; E.g. in the loop below we'd access array[-1] if we did: +; +; for(int i = 0 ; i < n ; i++ ) +; array[i] = ( i > 0 ? array[i - 1] : 0 ) + 4; + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +define void @f(i32* %array, i32 %n) { +entry: + %cmp10 = icmp sgt i32 %n, 0 + br i1 %cmp10, label %for.body, label %for.cond.cleanup + +for.cond.cleanup: ; preds = %cond.end, %entry + ret void + +for.body: ; preds = %entry, %cond.end + %indvars.iv = phi i64 [ %indvars.iv.next, %cond.end ], [ 0, %entry ] +; CHECK-NOT: %store_forwarded = phi + %cmp1 = icmp sgt i64 %indvars.iv, 0 + br i1 %cmp1, label %cond.true, label %cond.end + +cond.true: ; preds = %for.body + %0 = add nsw i64 %indvars.iv, -1 + %arrayidx = getelementptr inbounds i32, i32* %array, i64 %0 + %1 = load i32, i32* %arrayidx, align 4 + br label %cond.end + +cond.end: ; preds = %for.body, %cond.true + %cond = phi i32 [ %1, %cond.true ], [ 0, %for.body ] +; CHECK: %cond = phi i32 [ %1, %cond.true ], [ 0, %for.body ] + %add = add nsw i32 %cond, 4 + %arrayidx3 = getelementptr inbounds i32, i32* %array, i64 %indvars.iv + store i32 %add, i32* %arrayidx3, align 4 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %lftr.wideiv = trunc i64 %indvars.iv.next to i32 + %exitcond = icmp eq i32 %lftr.wideiv, %n + br i1 %exitcond, label %for.cond.cleanup, label %for.body +} diff --git a/test/Transforms/LoopLoadElim/forward.ll b/test/Transforms/LoopLoadElim/forward.ll index c2b1816530c1..ed0d162ab7e3 100644 --- a/test/Transforms/LoopLoadElim/forward.ll +++ b/test/Transforms/LoopLoadElim/forward.ll @@ -1,6 +1,6 @@ ; RUN: opt -loop-load-elim -S < %s | FileCheck %s -; Simple st->ld forwarding derived from a lexical forwrad dep. +; Simple st->ld forwarding derived from a lexical forward dep. ; ; for (unsigned i = 0; i < 100; i++) { ; A[i+1] = B[i] + 2; diff --git a/test/Transforms/LoopLoadElim/loop-simplify-dep.ll b/test/Transforms/LoopLoadElim/loop-simplify-dep.ll new file mode 100644 index 000000000000..f6bfe96d9c98 --- /dev/null +++ b/test/Transforms/LoopLoadElim/loop-simplify-dep.ll @@ -0,0 +1,33 @@ +; RUN: opt -loop-load-elim -S < %s | FileCheck %s + +; Make sure we create a preheader if we dont' have one. + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" + +define void @f(i32* noalias nocapture %A, i32* noalias nocapture readonly %B, i64 %N, i1 %C) { +entry: + br i1 %C, label %for.body, label %for.end + +; CHECK: for.body.preheader: +; CHECK-NEXT: %load_initial = load i32, i32* %A +; CHECK-NEXT: br label %for.body + +; CHECK: for.body: +for.body: +; CHECK-NEXT: %store_forwarded = phi i32 [ %load_initial, %for.body.preheader ], [ %add, %for.body ] + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] + %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv + %load = load i32, i32* %arrayidx, align 4 + %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv + %load_1 = load i32, i32* %arrayidx2, align 4 +; CHECK: %add = add i32 %load_1, %store_forwarded + %add = add i32 %load_1, %load + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %arrayidx_next = getelementptr inbounds i32, i32* %A, i64 %indvars.iv.next + store i32 %add, i32* %arrayidx_next, align 4 + %exitcond = icmp eq i64 %indvars.iv.next, %N + br i1 %exitcond, label %for.end, label %for.body + +for.end: + ret void +} diff --git a/test/Transforms/LoopLoadElim/non-consecutive.ll b/test/Transforms/LoopLoadElim/non-consecutive.ll new file mode 100644 index 000000000000..43751a8ff60d --- /dev/null +++ b/test/Transforms/LoopLoadElim/non-consecutive.ll @@ -0,0 +1,43 @@ +; RUN: opt -loop-load-elim -S < %s | FileCheck %s + +; The accesses to A are independent here but LAA reports it as a loop-carried +; forward dependence. Check that we don't perform st->ld forwarding between +; them. +; +; for (unsigned i = 0; i < 100; i++) { +; A[i][1] = B[i] + 2; +; C[i] = A[i][0] * 2; +; } + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" + +define void @f([2 x i32]* noalias %A, i32* noalias %B, i32* noalias %C, i64 %N) { + +entry: + br label %for.body + +for.body: ; preds = %for.body, %entry + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + + %A1idx = getelementptr inbounds [2 x i32], [2 x i32]* %A, i64 %indvars.iv, i32 1 + %Bidx = getelementptr inbounds i32, i32* %B, i64 %indvars.iv + %Cidx = getelementptr inbounds i32, i32* %C, i64 %indvars.iv + %A0idx = getelementptr inbounds [2 x i32], [2 x i32]* %A, i64 %indvars.iv, i32 0 + + %b = load i32, i32* %Bidx, align 4 + %a_p1 = add i32 %b, 2 + store i32 %a_p1, i32* %A1idx, align 4 + +; CHECK: %a = load i32, i32* %A0idx, align 4 + %a = load i32, i32* %A0idx, align 4 +; CHECK: %c = mul i32 %a, 2 + %c = mul i32 %a, 2 + store i32 %c, i32* %Cidx, align 4 + + %exitcond = icmp eq i64 %indvars.iv.next, %N + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} diff --git a/test/Transforms/LoopLoadElim/opt-size.ll b/test/Transforms/LoopLoadElim/opt-size.ll new file mode 100644 index 000000000000..a6322d874f32 --- /dev/null +++ b/test/Transforms/LoopLoadElim/opt-size.ll @@ -0,0 +1,76 @@ +; RUN: opt -basicaa -loop-load-elim -S < %s | FileCheck %s + +; When optimizing for size don't eliminate in this loop because the loop would +; have to be versioned first because A and C may alias. +; +; for (unsigned i = 0; i < 100; i++) { +; A[i+1] = B[i] + 2; +; C[i] = A[i] * 2; +; } + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" + +; CHECK-LABEL: @f( +define void @f(i32* %A, i32* %B, i32* %C, i64 %N) optsize { + +entry: + br label %for.body + +for.body: ; preds = %for.body, %entry + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + + %Aidx_next = getelementptr inbounds i32, i32* %A, i64 %indvars.iv.next + %Bidx = getelementptr inbounds i32, i32* %B, i64 %indvars.iv + %Cidx = getelementptr inbounds i32, i32* %C, i64 %indvars.iv + %Aidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv + + %b = load i32, i32* %Bidx, align 4 + %a_p1 = add i32 %b, 2 + store i32 %a_p1, i32* %Aidx_next, align 4 + + %a = load i32, i32* %Aidx, align 4 +; CHECK: %c = mul i32 %a, 2 + %c = mul i32 %a, 2 + store i32 %c, i32* %Cidx, align 4 + + %exitcond = icmp eq i64 %indvars.iv.next, %N + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} + +; Same loop but with noalias on %A and %C. In this case load-eliminate even +; with -Os. + +; CHECK-LABEL: @g( +define void @g(i32* noalias %A, i32* %B, i32* noalias %C, i64 %N) optsize { + +entry: + br label %for.body + +for.body: ; preds = %for.body, %entry + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + + %Aidx_next = getelementptr inbounds i32, i32* %A, i64 %indvars.iv.next + %Bidx = getelementptr inbounds i32, i32* %B, i64 %indvars.iv + %Cidx = getelementptr inbounds i32, i32* %C, i64 %indvars.iv + %Aidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv + + %b = load i32, i32* %Bidx, align 4 + %a_p1 = add i32 %b, 2 + store i32 %a_p1, i32* %Aidx_next, align 4 + + %a = load i32, i32* %Aidx, align 4 +; CHECK: %c = mul i32 %store_forwarded, 2 + %c = mul i32 %a, 2 + store i32 %c, i32* %Cidx, align 4 + + %exitcond = icmp eq i64 %indvars.iv.next, %N + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} diff --git a/test/Transforms/LoopLoadElim/symbolic-stride.ll b/test/Transforms/LoopLoadElim/symbolic-stride.ll new file mode 100644 index 000000000000..7a2d1b6c7e3c --- /dev/null +++ b/test/Transforms/LoopLoadElim/symbolic-stride.ll @@ -0,0 +1,92 @@ +; RUN: opt -loop-load-elim -S < %s | \ +; RUN: FileCheck %s -check-prefix=ALL -check-prefix=ONE_STRIDE_SPEC \ +; RUN: -check-prefix=TWO_STRIDE_SPEC + +; RUN: opt -loop-load-elim -S -enable-mem-access-versioning=0 < %s | \ +; RUN: FileCheck %s -check-prefix=ALL -check-prefix=NO_ONE_STRIDE_SPEC \ +; RUN: -check-prefix=NO_TWO_STRIDE_SPEC + +; RUN: opt -loop-load-elim -S -loop-load-elimination-scev-check-threshold=1 < %s | \ +; RUN: FileCheck %s -check-prefix=ALL -check-prefix=ONE_STRIDE_SPEC \ +; RUN: -check-prefix=NO_TWO_STRIDE_SPEC + +; Forwarding in the presence of symbolic strides: +; +; for (unsigned i = 0; i < 100; i++) +; A[i + 1] = A[Stride * i] + B[i]; + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" + +; ALL-LABEL: @f( +define void @f(i32* noalias nocapture %A, i32* noalias nocapture readonly %B, i64 %N, + i64 %stride) { + +; ONE_STRIDE_SPEC: %ident.check = icmp ne i64 %stride, 1 + +entry: +; NO_ONE_STRIDE_SPEC-NOT: %load_initial = load i32, i32* %A +; ONE_STRIDE_SPEC: %load_initial = load i32, i32* %A + br label %for.body + +for.body: ; preds = %for.body, %entry +; NO_ONE_STRIDE_SPEC-NOT: %store_forwarded = phi i32 [ %load_initial, {{.*}} ], [ %add, %for.body ] +; ONE_STRIDE_SPEC: %store_forwarded = phi i32 [ %load_initial, {{.*}} ], [ %add, %for.body ] + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] + %mul = mul i64 %indvars.iv, %stride + %arrayidx = getelementptr inbounds i32, i32* %A, i64 %mul + %load = load i32, i32* %arrayidx, align 4 + %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv + %load_1 = load i32, i32* %arrayidx2, align 4 +; NO_ONE_STRIDE_SPEC-NOT: %add = add i32 %load_1, %store_forwarded +; ONE_STRIDE_SPEC: %add = add i32 %load_1, %store_forwarded + %add = add i32 %load_1, %load + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %arrayidx_next = getelementptr inbounds i32, i32* %A, i64 %indvars.iv.next + store i32 %add, i32* %arrayidx_next, align 4 + %exitcond = icmp eq i64 %indvars.iv.next, %N + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} + +; With two symbolic strides: +; +; for (unsigned i = 0; i < 100; i++) +; A[Stride2 * (i + 1)] = A[Stride1 * i] + B[i]; + +; ALL-LABEL: @two_strides( +define void @two_strides(i32* noalias nocapture %A, i32* noalias nocapture readonly %B, i64 %N, + i64 %stride.1, i64 %stride.2) { + +; TWO_STRIDE_SPEC: %ident.check = icmp ne i64 %stride.2, 1 +; TWO_STRIDE_SPEC: %ident.check1 = icmp ne i64 %stride.1, 1 +; NO_TWO_STRIDE_SPEC-NOT: %ident.check{{.*}} = icmp ne i64 %stride{{.*}}, 1 + +entry: +; NO_TWO_STRIDE_SPEC-NOT: %load_initial = load i32, i32* %A +; TWO_STRIDE_SPEC: %load_initial = load i32, i32* %A + br label %for.body + +for.body: ; preds = %for.body, %entry +; NO_TWO_STRIDE_SPEC-NOT: %store_forwarded = phi i32 [ %load_initial, {{.*}} ], [ %add, %for.body ] +; TWO_STRIDE_SPEC: %store_forwarded = phi i32 [ %load_initial, {{.*}} ], [ %add, %for.body ] + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] + %mul = mul i64 %indvars.iv, %stride.1 + %arrayidx = getelementptr inbounds i32, i32* %A, i64 %mul + %load = load i32, i32* %arrayidx, align 4 + %arrayidx2 = getelementptr inbounds i32, i32* %B, i64 %indvars.iv + %load_1 = load i32, i32* %arrayidx2, align 4 +; NO_TWO_STRIDE_SPEC-NOT: %add = add i32 %load_1, %store_forwarded +; TWO_STRIDE_SPEC: %add = add i32 %load_1, %store_forwarded + %add = add i32 %load_1, %load + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %mul.2 = mul i64 %indvars.iv.next, %stride.2 + %arrayidx_next = getelementptr inbounds i32, i32* %A, i64 %mul.2 + store i32 %add, i32* %arrayidx_next, align 4 + %exitcond = icmp eq i64 %indvars.iv.next, %N + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} diff --git a/test/Transforms/LoopLoadElim/type-mismatch.ll b/test/Transforms/LoopLoadElim/type-mismatch.ll new file mode 100644 index 000000000000..ab8029bd35fb --- /dev/null +++ b/test/Transforms/LoopLoadElim/type-mismatch.ll @@ -0,0 +1,89 @@ +; RUN: opt -loop-load-elim -S < %s | FileCheck %s + +; Don't crash if the store and the load use different types. +; +; for (unsigned i = 0; i < 100; i++) { +; A[i+1] = B[i] + 2; +; C[i] = ((float*)A)[i] * 2; +; } + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" + +; CHECK-LABEL: @f( +define void @f(i32* noalias %A, i32* noalias %B, i32* noalias %C, i64 %N) { + +entry: + br label %for.body + +for.body: ; preds = %for.body, %entry + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + + %Aidx_next = getelementptr inbounds i32, i32* %A, i64 %indvars.iv.next + %Bidx = getelementptr inbounds i32, i32* %B, i64 %indvars.iv + %Cidx = getelementptr inbounds i32, i32* %C, i64 %indvars.iv + %Aidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv + %Aidx.float = bitcast i32* %Aidx to float* + + %b = load i32, i32* %Bidx, align 4 + %a_p1 = add i32 %b, 2 + store i32 %a_p1, i32* %Aidx_next, align 4 + +; CHECK: %a = load float, float* %Aidx.float, align 4 + %a = load float, float* %Aidx.float, align 4 +; CHECK-NEXT: %c = fmul float %a, 2.0 + %c = fmul float %a, 2.0 + %c.int = fptosi float %c to i32 + store i32 %c.int, i32* %Cidx, align 4 + + %exitcond = icmp eq i64 %indvars.iv.next, %N + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} + +; Don't crash if the store and the load use different types. +; +; for (unsigned i = 0; i < 100; i++) { +; A[i+1] = B[i] + 2; +; A[i+1] = B[i] + 3; +; C[i] = ((float*)A)[i] * 2; +; } + +; CHECK-LABEL: @f2( +define void @f2(i32* noalias %A, i32* noalias %B, i32* noalias %C, i64 %N) { + +entry: + br label %for.body + +for.body: ; preds = %for.body, %entry + %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + + %Aidx_next = getelementptr inbounds i32, i32* %A, i64 %indvars.iv.next + %Bidx = getelementptr inbounds i32, i32* %B, i64 %indvars.iv + %Cidx = getelementptr inbounds i32, i32* %C, i64 %indvars.iv + %Aidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv + %Aidx.float = bitcast i32* %Aidx to float* + + %b = load i32, i32* %Bidx, align 4 + %a_p2 = add i32 %b, 2 + store i32 %a_p2, i32* %Aidx_next, align 4 + + %a_p3 = add i32 %b, 3 + store i32 %a_p3, i32* %Aidx_next, align 4 + +; CHECK: %a = load float, float* %Aidx.float, align 4 + %a = load float, float* %Aidx.float, align 4 +; CHECK-NEXT: %c = fmul float %a, 2.0 + %c = fmul float %a, 2.0 + %c.int = fptosi float %c to i32 + store i32 %c.int, i32* %Cidx, align 4 + + %exitcond = icmp eq i64 %indvars.iv.next, %N + br i1 %exitcond, label %for.end, label %for.body + +for.end: ; preds = %for.body + ret void +} |
