[PATCH] Teach the DAGCombiner how to fold concat_vector nodes when the input is two BUILD_VECTOR nodes.

Robert Lougher rob.lougher at gmail.com
Tue Feb 4 11:48:34 PST 2014


ping.

On 28 January 2014 17:40, Robert Lougher <rob.lougher at gmail.com> wrote:
> Hi,
>
> This patch teaches the DAGCombiner how to fold concat_vector nodes
> when the input is two BUILD_VECTOR nodes, e.g.:
>
> (concat_vectors (BUILD_VECTOR a1, a2, a3, a4), (BUILD_VECTOR b1, b2, b3, b4))
> ->
> (BUILD_VECTOR a1, a2, a3, a4, b1, b2, b3, b4)
>
> This can be seen with the following IR:
>
> define <8 x float> @memory4(float* %p) {
>   %1 = load float* %p, align 4
>   %2 = insertelement <4 x float> undef, float %1, i32 0
>   %3 = insertelement <4 x float> %2, float %1, i32 1
>   %4 = insertelement <4 x float> %3, float %1, i32 2
>   %5 = insertelement <4 x float> %4, float %1, i32 3
>   %6 = shufflevector <4 x float> %5, <4 x float> undef, <8 x i32> <i32
> 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
>
> The shufflevector is turned into a concat_vectors node, and the
> insertelements into a BUILD_VECTOR.
>
> On AVX, without the patch this generates two instructions:
>
> vbroadcastss (%rdi), %xmm0
> vinsertf128 $1, %xmm0, %ymm0, %ymm0
>
> With the patch:
>
> vbroadcastss (%rdi), %ymm0
>
> This is because the whole sequence was not recognized as a 256-bit
> vbroadcast by LowerVectorBroadcast (X86ISelLowering.cpp) due to the
> concat_vectors.
>
> I have added tests to avx-vbroadcast.ll and avx2-vbroadcast.ll that
> check both single and double vbroadcasts.  If the patch looks OK
> please submit for me.
>
> Thanks,
> Rob.
>
> --
> Robert Lougher
> SN Systems - Sony Computer Entertainment Group
-------------- next part --------------
Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp
===================================================================
--- lib/CodeGen/SelectionDAG/DAGCombiner.cpp	(revision 200791)
+++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp	(working copy)
@@ -10129,6 +10129,26 @@
     }
   }
 
+  // fold (concat_vectors (BUILD_VECTOR A, B, ...), (BUILD_VECTOR C, D, ...))
+  // -> (BUILD_VECTOR A, B, ..., C, D, ...)
+  if (N->getNumOperands() == 2 &&
+      N->getOperand(0).getOpcode() == ISD::BUILD_VECTOR &&
+      N->getOperand(1).getOpcode() == ISD::BUILD_VECTOR) {
+    EVT VT = N->getValueType(0);
+    SDValue N0 = N->getOperand(0);
+    SDValue N1 = N->getOperand(1);
+    SmallVector<SDValue, 8> Opnds;
+    unsigned BuildVecNumElts =  N0.getNumOperands();
+
+    for (unsigned i = 0; i != BuildVecNumElts; ++i)
+      Opnds.push_back(N0.getOperand(i));
+    for (unsigned i = 0; i != BuildVecNumElts; ++i)
+      Opnds.push_back(N1.getOperand(i));
+
+    return DAG.getNode(ISD::BUILD_VECTOR, SDLoc(N), VT, &Opnds[0],
+                       Opnds.size());
+  }
+
   // Type legalization of vectors and DAG canonicalization of SHUFFLE_VECTOR
   // nodes often generate nop CONCAT_VECTOR nodes.
   // Scan the CONCAT_VECTOR operands and look for a CONCAT operations that
Index: test/CodeGen/X86/avx2-vbroadcast.ll
===================================================================
--- test/CodeGen/X86/avx2-vbroadcast.ll	(revision 200791)
+++ test/CodeGen/X86/avx2-vbroadcast.ll	(working copy)
@@ -355,3 +355,61 @@
   %b = shufflevector <16 x i8> %a, <16 x i8> undef, <16 x i32> zeroinitializer
   ret <16 x i8> %b
 }
+
+; These tests check that a vbroadcast instruction is used when we have a splat
+; formed from a concat_vectors (via the shufflevector) of two BUILD_VECTORs
+; (via the insertelements).
+
+; CHECK-LABEL: splat_concat1
+; CHECK-NOT: vinsertf128
+; CHECK: vbroadcastss
+; CHECK-NEXT: ret
+define <8 x float> @splat_concat1(float %f) {
+  %1 = insertelement <4 x float> undef, float %f, i32 0
+  %2 = insertelement <4 x float> %1, float %f, i32 1
+  %3 = insertelement <4 x float> %2, float %f, i32 2
+  %4 = insertelement <4 x float> %3, float %f, i32 3
+  %5 = shufflevector <4 x float> %4, <4 x float> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+  ret <8 x float> %5
+}
+
+; CHECK-LABEL: splat_concat2
+; CHECK-NOT: vinsertf128
+; CHECK: vbroadcastss
+; CHECK-NEXT: ret
+define <8 x float> @splat_concat2(float %f) {
+  %1 = insertelement <4 x float> undef, float %f, i32 0
+  %2 = insertelement <4 x float> %1, float %f, i32 1
+  %3 = insertelement <4 x float> %2, float %f, i32 2
+  %4 = insertelement <4 x float> %3, float %f, i32 3
+  %5 = insertelement <4 x float> undef, float %f, i32 0
+  %6 = insertelement <4 x float> %5, float %f, i32 1
+  %7 = insertelement <4 x float> %6, float %f, i32 2
+  %8 = insertelement <4 x float> %7, float %f, i32 3
+  %9 = shufflevector <4 x float> %4, <4 x float> %8, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+  ret <8 x float> %9
+}
+
+; CHECK-LABEL: splat_concat3
+; CHECK-NOT: vinsertf128
+; CHECK: vbroadcastsd
+; CHECK-NEXT: ret
+define <4 x double> @splat_concat3(double %d) {
+  %1 = insertelement <2 x double> undef, double %d, i32 0
+  %2 = insertelement <2 x double> %1, double %d, i32 1
+  %3 = shufflevector <2 x double> %2, <2 x double> undef, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+  ret <4 x double> %3
+}
+
+; CHECK-LABEL: splat_concat4
+; CHECK-NOT: vinsertf128
+; CHECK: vbroadcastsd
+; CHECK-NEXT: ret
+define <4 x double> @splat_concat4(double %d) {
+  %1 = insertelement <2 x double> undef, double %d, i32 0
+  %2 = insertelement <2 x double> %1, double %d, i32 1
+  %3 = insertelement <2 x double> undef, double %d, i32 0
+  %4 = insertelement <2 x double> %3, double %d, i32 1
+  %5 = shufflevector <2 x double> %2, <2 x double> %4, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  ret <4 x double> %5
+}
Index: test/CodeGen/X86/avx-vbroadcast.ll
===================================================================
--- test/CodeGen/X86/avx-vbroadcast.ll	(revision 200791)
+++ test/CodeGen/X86/avx-vbroadcast.ll	(working copy)
@@ -141,3 +141,66 @@
   ret <4 x float> %t
 }
 
+
+; These tests check that a vbroadcast instruction is used when we have a splat
+; formed from a concat_vectors (via the shufflevector) of two BUILD_VECTORs
+; (via the insertelements).
+
+; CHECK-LABEL: splat_concat1
+; CHECK-NOT: vinsertf128
+; CHECK: vbroadcastss (%
+; CHECK-NEXT: ret
+define <8 x float> @splat_concat1(float* %p) {
+  %1 = load float* %p, align 4
+  %2 = insertelement <4 x float> undef, float %1, i32 0
+  %3 = insertelement <4 x float> %2, float %1, i32 1
+  %4 = insertelement <4 x float> %3, float %1, i32 2
+  %5 = insertelement <4 x float> %4, float %1, i32 3
+  %6 = shufflevector <4 x float> %5, <4 x float> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 0, i32 1, i32 2, i32 3>
+  ret <8 x float> %6
+}
+
+; CHECK-LABEL: splat_concat2
+; CHECK-NOT: vinsertf128
+; CHECK: vbroadcastss (%
+; CHECK-NEXT: ret
+define <8 x float> @splat_concat2(float* %p) {
+  %1 = load float* %p, align 4
+  %2 = insertelement <4 x float> undef, float %1, i32 0
+  %3 = insertelement <4 x float> %2, float %1, i32 1
+  %4 = insertelement <4 x float> %3, float %1, i32 2
+  %5 = insertelement <4 x float> %4, float %1, i32 3
+  %6 = insertelement <4 x float> undef, float %1, i32 0
+  %7 = insertelement <4 x float> %6, float %1, i32 1
+  %8 = insertelement <4 x float> %7, float %1, i32 2
+  %9 = insertelement <4 x float> %8, float %1, i32 3
+  %10 = shufflevector <4 x float> %5, <4 x float> %9, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+  ret <8 x float> %10
+}
+
+; CHECK-LABEL: splat_concat3
+; CHECK-NOT: vinsertf128
+; CHECK: vbroadcastsd (%
+; CHECK-NEXT: ret
+define <4 x double> @splat_concat3(double* %p) {
+  %1 = load double* %p, align 8
+  %2 = insertelement <2 x double> undef, double %1, i32 0
+  %3 = insertelement <2 x double> %2, double %1, i32 1
+  %4 = shufflevector <2 x double> %3, <2 x double> undef, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+  ret <4 x double> %4
+}
+
+; CHECK-LABEL: splat_concat4
+; CHECK-NOT: vinsertf128
+; CHECK: vbroadcastsd (%
+; CHECK-NEXT: ret
+define <4 x double> @splat_concat4(double* %p) {
+  %1 = load double* %p, align 8
+  %2 = insertelement <2 x double> undef, double %1, i32 0
+  %3 = insertelement <2 x double> %2, double %1, i32 1
+  %4 = insertelement <2 x double> undef, double %1, i32 0
+  %5 = insertelement <2 x double> %2, double %1, i32 1
+  %6 = shufflevector <2 x double> %3, <2 x double> %5, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+  ret <4 x double> %6
+}
+


More information about the llvm-commits mailing list