summaryrefslogtreecommitdiff
path: root/test/Transforms/LoopUnswitch
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-07-23 20:41:05 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-07-23 20:41:05 +0000
commit01095a5d43bbfde13731688ddcf6048ebb8b7721 (patch)
tree4def12e759965de927d963ac65840d663ef9d1ea /test/Transforms/LoopUnswitch
parentf0f4822ed4b66e3579e92a89f368f8fb860e218e (diff)
Diffstat (limited to 'test/Transforms/LoopUnswitch')
-rw-r--r--test/Transforms/LoopUnswitch/2011-09-26-EHCrash.ll2
-rw-r--r--test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll10
-rw-r--r--test/Transforms/LoopUnswitch/exponential-behavior.ll51
-rw-r--r--test/Transforms/LoopUnswitch/guards.ll97
-rw-r--r--test/Transforms/LoopUnswitch/infinite-loop.ll6
-rw-r--r--test/Transforms/LoopUnswitch/msan.ll153
6 files changed, 310 insertions, 9 deletions
diff --git a/test/Transforms/LoopUnswitch/2011-09-26-EHCrash.ll b/test/Transforms/LoopUnswitch/2011-09-26-EHCrash.ll
index 1a929d68573a9..5d763a9b3e70f 100644
--- a/test/Transforms/LoopUnswitch/2011-09-26-EHCrash.ll
+++ b/test/Transforms/LoopUnswitch/2011-09-26-EHCrash.ll
@@ -1,4 +1,4 @@
-; RUN: opt < %s -scalarrepl-ssa -loop-unswitch -disable-output
+; RUN: opt < %s -sroa -loop-unswitch -disable-output
; PR11016
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-apple-macosx10.7.2"
diff --git a/test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll b/test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll
index d536da1e8b600..a215be9d4877b 100644
--- a/test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll
+++ b/test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll
@@ -16,23 +16,23 @@ for.body: ; preds = %for.inc, %for.body.
%cmp1 = icmp eq i32 %a, 12345
br i1 %cmp1, label %if.then, label %if.else, !prof !0
; CHECK: %cmp1 = icmp eq i32 %a, 12345
-; CHECK-NEXT: br i1 %cmp1, label %if.then.us, label %if.else, !prof !0
+; CHECK-NEXT: br i1 %cmp1, label %for.body.us, label %for.body, !prof !0
if.then: ; preds = %for.body
-; CHECK: if.then.us:
+; CHECK: for.body.us:
; CHECK: add nsw i32 %{{.*}}, 123
; CHECK: %exitcond.us = icmp eq i32 %inc.us, %b
-; CHECK: br i1 %exitcond.us, label %for.cond.cleanup, label %if.then.us
+; CHECK: br i1 %exitcond.us, label %for.cond.cleanup, label %for.body.us
%add = add nsw i32 %add.i, 123
br label %for.inc
if.else: ; preds = %for.body
%mul = mul nsw i32 %mul.i, %b
br label %for.inc
-; CHECK: if.else:
+; CHECK: for.body:
; CHECK: %mul = mul nsw i32 %mul.i, %b
; CHECK: %inc = add nuw nsw i32 %inc.i, 1
; CHECK: %exitcond = icmp eq i32 %inc, %b
-; CHECK: br i1 %exitcond, label %for.cond.cleanup, label %if.else
+; CHECK: br i1 %exitcond, label %for.cond.cleanup, label %for.body
for.inc: ; preds = %if.then, %if.else
%mul.p = phi i32 [ %b, %if.then ], [ %mul, %if.else ]
%add.p = phi i32 [ %add, %if.then ], [ %a, %if.else ]
diff --git a/test/Transforms/LoopUnswitch/exponential-behavior.ll b/test/Transforms/LoopUnswitch/exponential-behavior.ll
new file mode 100644
index 0000000000000..fb5a1ccf87b8e
--- /dev/null
+++ b/test/Transforms/LoopUnswitch/exponential-behavior.ll
@@ -0,0 +1,51 @@
+; RUN: opt -loop-unswitch -S < %s | FileCheck %s
+
+define void @f(i32 %n, i32* %ptr) {
+; CHECK-LABEL: @f(
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.inc, %be ]
+ %iv.inc = add i32 %iv, 1
+ %unswitch_cond_root = icmp ne i32 %iv.inc, 42
+ %us.0 = and i1 %unswitch_cond_root, %unswitch_cond_root
+ %us.1 = and i1 %us.0, %us.0
+ %us.2 = and i1 %us.1, %us.1
+ %us.3 = and i1 %us.2, %us.2
+ %us.4 = and i1 %us.3, %us.3
+ %us.5 = and i1 %us.4, %us.4
+ %us.6 = and i1 %us.5, %us.5
+ %us.7 = and i1 %us.6, %us.6
+ %us.8 = and i1 %us.7, %us.7
+ %us.9 = and i1 %us.8, %us.8
+ %us.10 = and i1 %us.9, %us.9
+ %us.11 = and i1 %us.10, %us.10
+ %us.12 = and i1 %us.11, %us.11
+ %us.13 = and i1 %us.12, %us.12
+ %us.14 = and i1 %us.13, %us.13
+ %us.15 = and i1 %us.14, %us.14
+ %us.16 = and i1 %us.15, %us.15
+ %us.17 = and i1 %us.16, %us.16
+ %us.18 = and i1 %us.17, %us.17
+ %us.19 = and i1 %us.18, %us.18
+ %us.20 = and i1 %us.19, %us.19
+ %us.21 = and i1 %us.20, %us.20
+ %us.22 = and i1 %us.21, %us.21
+ %us.23 = and i1 %us.22, %us.22
+ %us.24 = and i1 %us.23, %us.23
+ %us.25 = and i1 %us.24, %us.24
+ %us.26 = and i1 %us.25, %us.25
+ %us.27 = and i1 %us.26, %us.26
+ %us.28 = and i1 %us.27, %us.27
+ %us.29 = and i1 %us.28, %us.28
+ br i1 %us.29, label %leave, label %be
+
+be:
+ store volatile i32 0, i32* %ptr
+ %becond = icmp ult i32 %iv.inc, %n
+ br i1 %becond, label %leave, label %loop
+
+leave:
+ ret void
+}
diff --git a/test/Transforms/LoopUnswitch/guards.ll b/test/Transforms/LoopUnswitch/guards.ll
new file mode 100644
index 0000000000000..558853389602b
--- /dev/null
+++ b/test/Transforms/LoopUnswitch/guards.ll
@@ -0,0 +1,97 @@
+; RUN: opt -S -loop-unswitch < %s | FileCheck %s
+
+declare void @llvm.experimental.guard(i1, ...)
+
+define void @f_0(i32 %n, i32* %ptr, i1 %c) {
+; CHECK-LABEL: @f_0(
+; CHECK: loop.us:
+; CHECK-NOT: guard
+; CHECK: loop:
+; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"() ]
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
+ %iv.inc = add i32 %iv, 1
+ call void(i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"() ]
+ store volatile i32 0, i32* %ptr
+ %becond = icmp ult i32 %iv.inc, %n
+ br i1 %becond, label %leave, label %loop
+
+leave:
+ ret void
+}
+
+define void @f_1(i32 %n, i32* %ptr, i1 %c_0, i1 %c_1) {
+; CHECK-LABEL: @f_1(
+; CHECK: loop.us.us:
+; CHECK-NOT: guard
+; CHECK: loop.us:
+; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"(i32 2) ]
+; CHECK-NOT: guard
+; CHECK: loop.us1:
+; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"(i32 1) ]
+; CHECK-NOT: guard
+; CHECK: loop:
+; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"(i32 1) ]
+; CHECK: call void (i1, ...) @llvm.experimental.guard(i1 false) [ "deopt"(i32 2) ]
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
+ %iv.inc = add i32 %iv, 1
+ call void(i1, ...) @llvm.experimental.guard(i1 %c_0) [ "deopt"(i32 1) ]
+ store volatile i32 0, i32* %ptr
+ call void(i1, ...) @llvm.experimental.guard(i1 %c_1) [ "deopt"(i32 2) ]
+ %becond = icmp ult i32 %iv.inc, %n
+ br i1 %becond, label %leave, label %loop
+
+leave:
+ ret void
+}
+
+; Basic negative test
+
+define void @f_3(i32 %n, i32* %ptr, i1* %c_ptr) {
+; CHECK-LABEL: @f_3(
+; CHECK-NOT: loop.us:
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
+ %iv.inc = add i32 %iv, 1
+ %c = load volatile i1, i1* %c_ptr
+ call void(i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"() ]
+ store volatile i32 0, i32* %ptr
+ %becond = icmp ult i32 %iv.inc, %n
+ br i1 %becond, label %leave, label %loop
+
+leave:
+ ret void
+}
+
+define void @f_4(i32 %n, i32* %ptr, i1 %c) {
+; CHECK-LABEL: @f_4(
+;
+; Demonstrate that unswitching on one guard can cause another guard to
+; be erased (this has implications on what guards we can keep raw
+; pointers to).
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.inc, %loop ]
+ %iv.inc = add i32 %iv, 1
+ call void(i1, ...) @llvm.experimental.guard(i1 %c) [ "deopt"(i32 1) ]
+ store volatile i32 0, i32* %ptr
+ %neg = xor i1 %c, 1
+ call void(i1, ...) @llvm.experimental.guard(i1 %neg) [ "deopt"(i32 2) ]
+ %becond = icmp ult i32 %iv.inc, %n
+ br i1 %becond, label %leave, label %loop
+
+leave:
+ ret void
+}
diff --git a/test/Transforms/LoopUnswitch/infinite-loop.ll b/test/Transforms/LoopUnswitch/infinite-loop.ll
index 3d1c895edec90..0aef9092a1feb 100644
--- a/test/Transforms/LoopUnswitch/infinite-loop.ll
+++ b/test/Transforms/LoopUnswitch/infinite-loop.ll
@@ -16,10 +16,10 @@
; CHECK-NEXT: br i1 %a, label %entry.split, label %abort0.split
; CHECK: entry.split:
-; CHECK-NEXT: br i1 %b, label %cond.end, label %abort1.split
+; CHECK-NEXT: br i1 %b, label %for.body, label %abort1.split
-; CHECK: cond.end:
-; CHECK-NEXT: br label %cond.end
+; CHECK: for.body:
+; CHECK-NEXT: br label %for.body
; CHECK: abort0.split:
; CHECK-NEXT: call void @end0() [[NOR_NUW:#[0-9]+]]
diff --git a/test/Transforms/LoopUnswitch/msan.ll b/test/Transforms/LoopUnswitch/msan.ll
new file mode 100644
index 0000000000000..a5e10e828a7b5
--- /dev/null
+++ b/test/Transforms/LoopUnswitch/msan.ll
@@ -0,0 +1,153 @@
+; RUN: opt < %s -loop-unswitch -verify-loop-info -S < %s 2>&1 | FileCheck %s
+
+@sink = global i32 0, align 4
+@y = global i64 0, align 8
+
+; The following is approximately:
+; void f(bool x, int p, int q) {
+; volatile bool x2 = x;
+; for (int i = 0; i < 1; ++i) {
+; if (x2) {
+; if (y)
+; sink = p;
+; else
+; sink = q;
+; }
+; }
+; }
+; With MemorySanitizer, the loop can not be unswitched on "y", because "y" could
+; be uninitialized when x == false.
+; Test that the branch on "y" is inside the loop (after the first unconditional
+; branch).
+
+define void @may_not_execute(i1 zeroext %x, i32 %p, i32 %q) sanitize_memory {
+; CHECK-LABEL: @may_not_execute(
+entry:
+; CHECK: %[[Y:.*]] = load i64, i64* @y, align 8
+; CHECK: %[[YB:.*]] = icmp eq i64 %[[Y]], 0
+; CHECK-NOT: br i1
+; CHECK: br label
+; CHECK: br i1 %[[YB]]
+
+ %x2 = alloca i8, align 1
+ %frombool1 = zext i1 %x to i8
+ store volatile i8 %frombool1, i8* %x2, align 1
+ %0 = load i64, i64* @y, align 8
+ %tobool3 = icmp eq i64 %0, 0
+ br label %for.body
+
+for.body:
+ %i.01 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+ %x2.0. = load volatile i8, i8* %x2, align 1
+ %tobool2 = icmp eq i8 %x2.0., 0
+ br i1 %tobool2, label %for.inc, label %if.then
+
+if.then:
+ br i1 %tobool3, label %if.else, label %if.then4
+
+if.then4:
+ store volatile i32 %p, i32* @sink, align 4
+ br label %for.inc
+
+if.else:
+ store volatile i32 %q, i32* @sink, align 4
+ br label %for.inc
+
+for.inc:
+ %inc = add nsw i32 %i.01, 1
+ %cmp = icmp slt i32 %inc, 1
+ br i1 %cmp, label %for.body, label %for.end
+
+for.end:
+ ret void
+}
+
+
+; The same as above, but "y" is a function parameter instead of a global.
+; This shows that it is not enough to suppress hoisting of load instructions,
+; the actual problem is in the speculative branching.
+
+define void @may_not_execute2(i1 zeroext %x, i1 zeroext %y, i32 %p, i32 %q) sanitize_memory {
+; CHECK-LABEL: @may_not_execute2(
+entry:
+; CHECK-NOT: br i1
+; CHECK: br label
+; CHECK: br i1 %y,
+ %x2 = alloca i8, align 1
+ %frombool2 = zext i1 %x to i8
+ store volatile i8 %frombool2, i8* %x2, align 1
+ br label %for.body
+
+for.body:
+ %i.01 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+ %x2.0. = load volatile i8, i8* %x2, align 1
+ %tobool3 = icmp eq i8 %x2.0., 0
+ br i1 %tobool3, label %for.inc, label %if.then
+
+if.then:
+ br i1 %y, label %if.then5, label %if.else
+
+if.then5:
+ store volatile i32 %p, i32* @sink, align 4
+ br label %for.inc
+
+if.else:
+ store volatile i32 %q, i32* @sink, align 4
+ br label %for.inc
+
+for.inc:
+ %inc = add nsw i32 %i.01, 1
+ %cmp = icmp slt i32 %inc, 1
+ br i1 %cmp, label %for.body, label %for.end
+
+for.end:
+ ret void
+}
+
+
+; The following is approximately:
+; void f(bool x, int p, int q) {
+; volatile bool x2 = x;
+; for (int i = 0; i < 1; ++i) {
+; if (y)
+; sink = p;
+; else
+; sink = q;
+; }
+; }
+; "if (y)" is guaranteed to execute; the loop can be unswitched.
+
+define void @must_execute(i1 zeroext %x, i32 %p, i32 %q) sanitize_memory {
+; CHECK-LABEL: @must_execute(
+entry:
+; CHECK: %[[Y:.*]] = load i64, i64* @y, align 8
+; CHECK-NEXT: %[[YB:.*]] = icmp eq i64 %[[Y]], 0
+; CHECK-NEXT: br i1 %[[YB]],
+
+ %x2 = alloca i8, align 1
+ %frombool1 = zext i1 %x to i8
+ store volatile i8 %frombool1, i8* %x2, align 1
+ %0 = load i64, i64* @y, align 8
+ %tobool2 = icmp eq i64 %0, 0
+ br label %for.body
+
+for.body:
+ %i.01 = phi i32 [ 0, %entry ], [ %inc, %for.inc ]
+ br i1 %tobool2, label %if.else, label %if.then
+
+if.then:
+ store volatile i32 %p, i32* @sink, align 4
+ br label %for.inc
+
+if.else:
+ store volatile i32 %q, i32* @sink, align 4
+ br label %for.inc
+
+for.inc:
+ %inc = add nsw i32 %i.01, 1
+ %cmp = icmp slt i32 %inc, 1
+ br i1 %cmp, label %for.body, label %for.end
+
+for.end:
+ ret void
+}