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/LoopUnswitch | |
parent | f0f4822ed4b66e3579e92a89f368f8fb860e218e (diff) |
Diffstat (limited to 'test/Transforms/LoopUnswitch')
-rw-r--r-- | test/Transforms/LoopUnswitch/2011-09-26-EHCrash.ll | 2 | ||||
-rw-r--r-- | test/Transforms/LoopUnswitch/2015-06-17-Metadata.ll | 10 | ||||
-rw-r--r-- | test/Transforms/LoopUnswitch/exponential-behavior.ll | 51 | ||||
-rw-r--r-- | test/Transforms/LoopUnswitch/guards.ll | 97 | ||||
-rw-r--r-- | test/Transforms/LoopUnswitch/infinite-loop.ll | 6 | ||||
-rw-r--r-- | test/Transforms/LoopUnswitch/msan.ll | 153 |
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 +} |