diff options
| author | Matthew Simpson <mssimpso@codeaurora.org> | 2016-12-07 15:03:32 +0000 |
|---|---|---|
| committer | Matthew Simpson <mssimpso@codeaurora.org> | 2016-12-07 15:03:32 +0000 |
| commit | 364da7e5270445397ef6862c7a7c1c4a0d41bf9b (patch) | |
| tree | baf7e9283c03ac4dda38db2c9fc5c13eece843ae /llvm/test/Transforms/LoopVectorize | |
| parent | 41552d6a37c8c9fb4a620b3a7164469a2cb914ac (diff) | |
| download | bcm5719-llvm-364da7e5270445397ef6862c7a7c1c4a0d41bf9b.tar.gz bcm5719-llvm-364da7e5270445397ef6862c7a7c1c4a0d41bf9b.zip | |
[LV] Scalarize operands of predicated instructions
This patch attempts to scalarize the operand expressions of predicated
instructions if they were conditionally executed in the original loop. After
scalarization, the expressions will be sunk inside the blocks created for the
predicated instructions. The transformation essentially performs
un-if-conversion on the operands.
The cost model has been updated to determine if scalarization is profitable. It
compares the cost of a vectorized instruction, assuming it will be
if-converted, to the cost of the scalarized instruction, assuming that the
instructions corresponding to each vector lane will be sunk inside a predicated
block, possibly avoiding execution. If it's more profitable to scalarize the
entire expression tree feeding the predicated instruction, the expression will
be scalarized; otherwise, it will be vectorized. We only consider the cost of
the entire expression to accurately estimate the cost of the required
insertelement and extractelement instructions.
Differential Revision: https://reviews.llvm.org/D26083
llvm-svn: 288909
Diffstat (limited to 'llvm/test/Transforms/LoopVectorize')
5 files changed, 329 insertions, 7 deletions
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/aarch64-predication.ll b/llvm/test/Transforms/LoopVectorize/AArch64/aarch64-predication.ll new file mode 100644 index 00000000000..21b59f87d04 --- /dev/null +++ b/llvm/test/Transforms/LoopVectorize/AArch64/aarch64-predication.ll @@ -0,0 +1,63 @@ +; RUN: opt < %s -loop-vectorize -simplifycfg -S | FileCheck %s +; RUN: opt < %s -force-vector-width=2 -loop-vectorize -simplifycfg -S | FileCheck %s + +target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128" +target triple = "aarch64--linux-gnu" + +; CHECK-LABEL: predicated_udiv_scalarized_operand +; +; This test checks that we correctly compute the scalarized operands for a +; user-specified vectorization factor when interleaving is disabled. We use the +; "optsize" attribute to disable all interleaving calculations. +; +; CHECK: vector.body: +; CHECK: %wide.load = load <2 x i64>, <2 x i64>* {{.*}}, align 4 +; CHECK: br i1 {{.*}}, label %[[IF0:.+]], label %[[CONT0:.+]] +; CHECK: [[IF0]]: +; CHECK: %[[T00:.+]] = extractelement <2 x i64> %wide.load, i32 0 +; CHECK: %[[T01:.+]] = extractelement <2 x i64> %wide.load, i32 0 +; CHECK: %[[T02:.+]] = add nsw i64 %[[T01]], %x +; CHECK: %[[T03:.+]] = udiv i64 %[[T00]], %[[T02]] +; CHECK: %[[T04:.+]] = insertelement <2 x i64> undef, i64 %[[T03]], i32 0 +; CHECK: br label %[[CONT0]] +; CHECK: [[CONT0]]: +; CHECK: %[[T05:.+]] = phi <2 x i64> [ undef, %vector.body ], [ %[[T04]], %[[IF0]] ] +; CHECK: br i1 {{.*}}, label %[[IF1:.+]], label %[[CONT1:.+]] +; CHECK: [[IF1]]: +; CHECK: %[[T06:.+]] = extractelement <2 x i64> %wide.load, i32 1 +; CHECK: %[[T07:.+]] = extractelement <2 x i64> %wide.load, i32 1 +; CHECK: %[[T08:.+]] = add nsw i64 %[[T07]], %x +; CHECK: %[[T09:.+]] = udiv i64 %[[T06]], %[[T08]] +; CHECK: %[[T10:.+]] = insertelement <2 x i64> %[[T05]], i64 %[[T09]], i32 1 +; CHECK: br label %[[CONT1]] +; CHECK: [[CONT1]]: +; CHECK: phi <2 x i64> [ %[[T05]], %[[CONT0]] ], [ %[[T10]], %[[IF1]] ] +; CHECK: br i1 {{.*}}, label %middle.block, label %vector.body + +define i64 @predicated_udiv_scalarized_operand(i64* %a, i1 %c, i64 %x) optsize { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.inc ] + %r = phi i64 [ 0, %entry ], [ %tmp6, %for.inc ] + %tmp0 = getelementptr inbounds i64, i64* %a, i64 %i + %tmp2 = load i64, i64* %tmp0, align 4 + br i1 %c, label %if.then, label %for.inc + +if.then: + %tmp3 = add nsw i64 %tmp2, %x + %tmp4 = udiv i64 %tmp2, %tmp3 + br label %for.inc + +for.inc: + %tmp5 = phi i64 [ %tmp2, %for.body ], [ %tmp4, %if.then] + %tmp6 = add i64 %r, %tmp5 + %i.next = add nuw nsw i64 %i, 1 + %cond = icmp slt i64 %i.next, 100 + br i1 %cond, label %for.body, label %for.end + +for.end: + %tmp7 = phi i64 [ %tmp6, %for.inc ] + ret i64 %tmp7 +} diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/predication_costs.ll b/llvm/test/Transforms/LoopVectorize/AArch64/predication_costs.ll index 6b3a5b63042..61ed2057914 100644 --- a/llvm/test/Transforms/LoopVectorize/AArch64/predication_costs.ll +++ b/llvm/test/Transforms/LoopVectorize/AArch64/predication_costs.ll @@ -57,9 +57,9 @@ for.end: ; as: ; ; Cost of store: -; (store(4) + extractelement(6)) / 2 = 5 +; (store(4) + extractelement(3)) / 2 = 3 ; -; CHECK: Found an estimated cost of 5 for VF 2 For instruction: store i32 %tmp2, i32* %tmp0, align 4 +; CHECK: Found an estimated cost of 3 for VF 2 For instruction: store i32 %tmp2, i32* %tmp0, align 4 ; CHECK: Scalarizing and predicating: store i32 %tmp2, i32* %tmp0, align 4 ; define void @predicated_store(i32* %a, i1 %c, i32 %x, i64 %n) { @@ -85,3 +85,147 @@ for.inc: for.end: ret void } + +; CHECK-LABEL: predicated_udiv_scalarized_operand +; +; This test checks that we correctly compute the cost of the predicated udiv +; instruction and the add instruction it uses. The add is scalarized and sunk +; inside the predicated block. If we assume the block probability is 50%, we +; compute the cost as: +; +; Cost of add: +; (add(2) + extractelement(3)) / 2 = 2 +; Cost of udiv: +; (udiv(2) + extractelement(3) + insertelement(3)) / 2 = 4 +; +; CHECK: Found an estimated cost of 2 for VF 2 For instruction: %tmp3 = add nsw i32 %tmp2, %x +; CHECK: Found an estimated cost of 4 for VF 2 For instruction: %tmp4 = udiv i32 %tmp2, %tmp3 +; CHECK: Scalarizing: %tmp3 = add nsw i32 %tmp2, %x +; CHECK: Scalarizing and predicating: %tmp4 = udiv i32 %tmp2, %tmp3 +; +define i32 @predicated_udiv_scalarized_operand(i32* %a, i1 %c, i32 %x, i64 %n) { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.inc ] + %r = phi i32 [ 0, %entry ], [ %tmp6, %for.inc ] + %tmp0 = getelementptr inbounds i32, i32* %a, i64 %i + %tmp2 = load i32, i32* %tmp0, align 4 + br i1 %c, label %if.then, label %for.inc + +if.then: + %tmp3 = add nsw i32 %tmp2, %x + %tmp4 = udiv i32 %tmp2, %tmp3 + br label %for.inc + +for.inc: + %tmp5 = phi i32 [ %tmp2, %for.body ], [ %tmp4, %if.then] + %tmp6 = add i32 %r, %tmp5 + %i.next = add nuw nsw i64 %i, 1 + %cond = icmp slt i64 %i.next, %n + br i1 %cond, label %for.body, label %for.end + +for.end: + %tmp7 = phi i32 [ %tmp6, %for.inc ] + ret i32 %tmp7 +} + +; CHECK-LABEL: predicated_store_scalarized_operand +; +; This test checks that we correctly compute the cost of the predicated store +; instruction and the add instruction it uses. The add is scalarized and sunk +; inside the predicated block. If we assume the block probability is 50%, we +; compute the cost as: +; +; Cost of add: +; (add(2) + extractelement(3)) / 2 = 2 +; Cost of store: +; store(4) / 2 = 2 +; +; CHECK: Found an estimated cost of 2 for VF 2 For instruction: %tmp2 = add nsw i32 %tmp1, %x +; CHECK: Found an estimated cost of 2 for VF 2 For instruction: store i32 %tmp2, i32* %tmp0, align 4 +; CHECK: Scalarizing: %tmp2 = add nsw i32 %tmp1, %x +; CHECK: Scalarizing and predicating: store i32 %tmp2, i32* %tmp0, align 4 +; +define void @predicated_store_scalarized_operand(i32* %a, i1 %c, i32 %x, i64 %n) { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.inc ] + %tmp0 = getelementptr inbounds i32, i32* %a, i64 %i + %tmp1 = load i32, i32* %tmp0, align 4 + br i1 %c, label %if.then, label %for.inc + +if.then: + %tmp2 = add nsw i32 %tmp1, %x + store i32 %tmp2, i32* %tmp0, align 4 + br label %for.inc + +for.inc: + %i.next = add nuw nsw i64 %i, 1 + %cond = icmp slt i64 %i.next, %n + br i1 %cond, label %for.body, label %for.end + +for.end: + ret void +} + +; CHECK-LABEL: predication_multi_context +; +; This test checks that we correctly compute the cost of multiple predicated +; instructions in the same block. The sdiv, udiv, and store must be scalarized +; and predicated. The sub feeding the store is scalarized and sunk inside the +; store's predicated block. However, the add feeding the sdiv and udiv cannot +; be sunk and is not scalarized. If we assume the block probability is 50%, we +; compute the cost as: +; +; Cost of add: +; add(1) = 1 +; Cost of sdiv: +; (sdiv(2) + extractelement(6) + insertelement(3)) / 2 = 5 +; Cost of udiv: +; (udiv(2) + extractelement(6) + insertelement(3)) / 2 = 5 +; Cost of sub: +; (sub(2) + extractelement(3)) / 2 = 2 +; Cost of store: +; store(4) / 2 = 2 +; +; CHECK: Found an estimated cost of 1 for VF 2 For instruction: %tmp2 = add i32 %tmp1, %x +; CHECK: Found an estimated cost of 5 for VF 2 For instruction: %tmp3 = sdiv i32 %tmp1, %tmp2 +; CHECK: Found an estimated cost of 5 for VF 2 For instruction: %tmp4 = udiv i32 %tmp3, %tmp2 +; CHECK: Found an estimated cost of 2 for VF 2 For instruction: %tmp5 = sub i32 %tmp4, %x +; CHECK: Found an estimated cost of 2 for VF 2 For instruction: store i32 %tmp5, i32* %tmp0, align 4 +; CHECK-NOT: Scalarizing: %tmp2 = add i32 %tmp1, %x +; CHECK: Scalarizing and predicating: %tmp3 = sdiv i32 %tmp1, %tmp2 +; CHECK: Scalarizing and predicating: %tmp4 = udiv i32 %tmp3, %tmp2 +; CHECK: Scalarizing: %tmp5 = sub i32 %tmp4, %x +; CHECK: Scalarizing and predicating: store i32 %tmp5, i32* %tmp0, align 4 +; +define void @predication_multi_context(i32* %a, i1 %c, i32 %x, i64 %n) { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.inc ] + %tmp0 = getelementptr inbounds i32, i32* %a, i64 %i + %tmp1 = load i32, i32* %tmp0, align 4 + br i1 %c, label %if.then, label %for.inc + +if.then: + %tmp2 = add i32 %tmp1, %x + %tmp3 = sdiv i32 %tmp1, %tmp2 + %tmp4 = udiv i32 %tmp3, %tmp2 + %tmp5 = sub i32 %tmp4, %x + store i32 %tmp5, i32* %tmp0, align 4 + br label %for.inc + +for.inc: + %i.next = add nuw nsw i64 %i, 1 + %cond = icmp slt i64 %i.next, %n + br i1 %cond, label %for.body, label %for.end + +for.end: + ret void +} diff --git a/llvm/test/Transforms/LoopVectorize/X86/x86-predication.ll b/llvm/test/Transforms/LoopVectorize/X86/x86-predication.ll new file mode 100644 index 00000000000..b35fc59542b --- /dev/null +++ b/llvm/test/Transforms/LoopVectorize/X86/x86-predication.ll @@ -0,0 +1,60 @@ +; RUN: opt < %s -mattr=avx -force-vector-width=2 -force-vector-interleave=1 -loop-vectorize -simplifycfg -S | FileCheck %s + +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-S128" +target triple = "x86_64-apple-macosx10.8.0" + +; CHECK-LABEL: predicated_sdiv_masked_load +; +; This test ensures that we don't scalarize the predicated load. Since the load +; can be vectorized with predication, scalarizing it would cause its pointer +; operand to become non-uniform. +; +; CHECK: vector.body: +; CHECK: %wide.masked.load = call <2 x i32> @llvm.masked.load.v2i32.p0v2i32 +; CHECK: br i1 {{.*}}, label %[[IF0:.+]], label %[[CONT0:.+]] +; CHECK: [[IF0]]: +; CHECK: %[[T0:.+]] = extractelement <2 x i32> %wide.masked.load, i32 0 +; CHECK: %[[T1:.+]] = sdiv i32 %[[T0]], %x +; CHECK: %[[T2:.+]] = insertelement <2 x i32> undef, i32 %[[T1]], i32 0 +; CHECK: br label %[[CONT0]] +; CHECK: [[CONT0]]: +; CHECK: %[[T3:.+]] = phi <2 x i32> [ undef, %vector.body ], [ %[[T2]], %[[IF0]] ] +; CHECK: br i1 {{.*}}, label %[[IF1:.+]], label %[[CONT1:.+]] +; CHECK: [[IF1]]: +; CHECK: %[[T4:.+]] = extractelement <2 x i32> %wide.masked.load, i32 1 +; CHECK: %[[T5:.+]] = sdiv i32 %[[T4]], %x +; CHECK: %[[T6:.+]] = insertelement <2 x i32> %[[T3]], i32 %[[T5]], i32 1 +; CHECK: br label %[[CONT1]] +; CHECK: [[CONT1]]: +; CHECK: phi <2 x i32> [ %[[T3]], %[[CONT0]] ], [ %[[T6]], %[[IF1]] ] +; CHECK: br i1 {{.*}}, label %middle.block, label %vector.body + +define i32 @predicated_sdiv_masked_load(i32* %a, i32* %b, i32 %x, i1 %c) { +entry: + br label %for.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.inc ] + %r = phi i32 [ 0, %entry ], [ %tmp7, %for.inc ] + %tmp0 = getelementptr inbounds i32, i32* %a, i64 %i + %tmp1 = load i32, i32* %tmp0, align 4 + br i1 %c, label %if.then, label %for.inc + +if.then: + %tmp2 = getelementptr inbounds i32, i32* %b, i64 %i + %tmp3 = load i32, i32* %tmp2, align 4 + %tmp4 = sdiv i32 %tmp3, %x + %tmp5 = add nsw i32 %tmp4, %tmp1 + br label %for.inc + +for.inc: + %tmp6 = phi i32 [ %tmp1, %for.body ], [ %tmp5, %if.then] + %tmp7 = add i32 %r, %tmp6 + %i.next = add nuw nsw i64 %i, 1 + %cond = icmp eq i64 %i.next, 10000 + br i1 %cond, label %for.end, label %for.body + +for.end: + %tmp8 = phi i32 [ %tmp7, %for.inc ] + ret i32 %tmp8 +} diff --git a/llvm/test/Transforms/LoopVectorize/if-pred-non-void.ll b/llvm/test/Transforms/LoopVectorize/if-pred-non-void.ll index a2c2580271e..dbbf7b30dac 100644 --- a/llvm/test/Transforms/LoopVectorize/if-pred-non-void.ll +++ b/llvm/test/Transforms/LoopVectorize/if-pred-non-void.ll @@ -207,3 +207,57 @@ if.end: ; preds = %if.then, %check %exitcond = icmp eq i64 %indvars.iv.next, 128 br i1 %exitcond, label %for.cond.cleanup, label %for.body } + + +define i32 @predicated_udiv_scalarized_operand(i32* %a, i1 %c, i32 %x, i64 %n) { +entry: + br label %for.body + +; CHECK-LABEL: predicated_udiv_scalarized_operand +; CHECK: vector.body: +; CHECK: %wide.load = load <2 x i32>, <2 x i32>* {{.*}}, align 4 +; CHECK: br i1 {{.*}}, label %[[IF0:.+]], label %[[CONT0:.+]] +; CHECK: [[IF0]]: +; CHECK: %[[T00:.+]] = extractelement <2 x i32> %wide.load, i32 0 +; CHECK: %[[T01:.+]] = extractelement <2 x i32> %wide.load, i32 0 +; CHECK: %[[T02:.+]] = add nsw i32 %[[T01]], %x +; CHECK: %[[T03:.+]] = udiv i32 %[[T00]], %[[T02]] +; CHECK: %[[T04:.+]] = insertelement <2 x i32> undef, i32 %[[T03]], i32 0 +; CHECK: br label %[[CONT0]] +; CHECK: [[CONT0]]: +; CHECK: %[[T05:.+]] = phi <2 x i32> [ undef, %vector.body ], [ %[[T04]], %[[IF0]] ] +; CHECK: br i1 {{.*}}, label %[[IF1:.+]], label %[[CONT1:.+]] +; CHECK: [[IF1]]: +; CHECK: %[[T06:.+]] = extractelement <2 x i32> %wide.load, i32 1 +; CHECK: %[[T07:.+]] = extractelement <2 x i32> %wide.load, i32 1 +; CHECK: %[[T08:.+]] = add nsw i32 %[[T07]], %x +; CHECK: %[[T09:.+]] = udiv i32 %[[T06]], %[[T08]] +; CHECK: %[[T10:.+]] = insertelement <2 x i32> %[[T05]], i32 %[[T09]], i32 1 +; CHECK: br label %[[CONT1]] +; CHECK: [[CONT1]]: +; CHECK: phi <2 x i32> [ %[[T05]], %[[CONT0]] ], [ %[[T10]], %[[IF1]] ] +; CHECK: br i1 {{.*}}, label %middle.block, label %vector.body + +for.body: + %i = phi i64 [ 0, %entry ], [ %i.next, %for.inc ] + %r = phi i32 [ 0, %entry ], [ %tmp6, %for.inc ] + %tmp0 = getelementptr inbounds i32, i32* %a, i64 %i + %tmp2 = load i32, i32* %tmp0, align 4 + br i1 %c, label %if.then, label %for.inc + +if.then: + %tmp3 = add nsw i32 %tmp2, %x + %tmp4 = udiv i32 %tmp2, %tmp3 + br label %for.inc + +for.inc: + %tmp5 = phi i32 [ %tmp2, %for.body ], [ %tmp4, %if.then] + %tmp6 = add i32 %r, %tmp5 + %i.next = add nuw nsw i64 %i, 1 + %cond = icmp slt i64 %i.next, %n + br i1 %cond, label %for.body, label %for.end + +for.end: + %tmp7 = phi i32 [ %tmp6, %for.inc ] + ret i32 %tmp7 +} diff --git a/llvm/test/Transforms/LoopVectorize/if-pred-stores.ll b/llvm/test/Transforms/LoopVectorize/if-pred-stores.ll index f19485c63db..39123756f50 100644 --- a/llvm/test/Transforms/LoopVectorize/if-pred-stores.ll +++ b/llvm/test/Transforms/LoopVectorize/if-pred-stores.ll @@ -12,7 +12,6 @@ entry: ; VEC-LABEL: test ; VEC: %[[v0:.+]] = add i64 %index, 0 ; VEC: %[[v8:.+]] = icmp sgt <2 x i32> %{{.*}}, <i32 100, i32 100> -; VEC: %[[v9:.+]] = add nsw <2 x i32> %{{.*}}, <i32 20, i32 20> ; VEC: %[[v10:.+]] = and <2 x i1> %[[v8]], <i1 true, i1 true> ; VEC: %[[o1:.+]] = or <2 x i1> zeroinitializer, %[[v10]] ; VEC: %[[v11:.+]] = extractelement <2 x i1> %[[o1]], i32 0 @@ -20,9 +19,10 @@ entry: ; VEC: br i1 %[[v12]], label %[[cond:.+]], label %[[else:.+]] ; ; VEC: [[cond]]: -; VEC: %[[v13:.+]] = extractelement <2 x i32> %[[v9]], i32 0 +; VEC: %[[v13:.+]] = extractelement <2 x i32> %wide.load, i32 0 +; VEC: %[[v9a:.+]] = add nsw i32 %[[v13]], 20 ; VEC: %[[v2:.+]] = getelementptr inbounds i32, i32* %f, i64 %[[v0]] -; VEC: store i32 %[[v13]], i32* %[[v2]], align 4 +; VEC: store i32 %[[v9a]], i32* %[[v2]], align 4 ; VEC: br label %[[else:.+]] ; ; VEC: [[else]]: @@ -31,10 +31,11 @@ entry: ; VEC: br i1 %[[v16]], label %[[cond2:.+]], label %[[else2:.+]] ; ; VEC: [[cond2]]: -; VEC: %[[v17:.+]] = extractelement <2 x i32> %[[v9]], i32 1 +; VEC: %[[v17:.+]] = extractelement <2 x i32> %wide.load, i32 1 +; VEC: %[[v9b:.+]] = add nsw i32 %[[v17]], 20 ; VEC: %[[v1:.+]] = add i64 %index, 1 ; VEC: %[[v4:.+]] = getelementptr inbounds i32, i32* %f, i64 %[[v1]] -; VEC: store i32 %[[v17]], i32* %[[v4]], align 4 +; VEC: store i32 %[[v9b]], i32* %[[v4]], align 4 ; VEC: br label %[[else2:.+]] ; ; VEC: [[else2]]: |

