[DAGCombiner] Improved target independent vector shuffle combine rule.
authorAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>
Wed, 13 Aug 2014 16:09:40 +0000 (16:09 +0000)
committerAndrea Di Biagio <Andrea_DiBiagio@sn.scee.net>
Wed, 13 Aug 2014 16:09:40 +0000 (16:09 +0000)
This patch improves the existing algorithm in DAGCombiner that
attempts to fold shuffles according to rule:
  shuffle(shuffle(x, y, M1), undef, M2) -> shuffle(y, undef, M3)

Before this change, there were cases where the DAGCombiner conservatively
avoided folding shuffles even if the resulting mask would have been legal.
That is because the algorithm wrongly assumed that commuting
an illegal shuffle mask would always produce an illegal mask.

With this change, we now correctly compute the commuted shuffle mask before
calling method 'isShuffleMaskLegal' on it.
On X86, this improves for example the codegen for the following function:

define <4 x i32> @test(<4 x i32> %A, <4 x i32> %B) {
  %1 = shufflevector <4 x i32> %B, <4 x i32> %A, <4 x i32> <i32 1, i32 2, i32 6, i32 7>
  %2 = shufflevector <4 x i32> %1, <4 x i32> undef, <4 x i32> <i32 2, i32 3, i32 2, i32 3>
  ret <4 x i32> %2
}

Before this change the X86 backend (-mcpu=corei7) generated
the following assembly code for function @test:
  shufps $-23, %xmm0, %xmm1  # xmm1 = xmm1[1,2],xmm0[2,3]
  movhlps %xmm1, %xmm1       # xmm1 = xmm1[1,1]
  movaps %xmm1, %xmm0

Now we produce:
  movhlps %xmm0, %xmm0       # xmm0 = xmm0[1,1]

Added extra test cases in combine-vec-shuffle-2.ll to verify that we correctly
fold according to the above-mentioned rule.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@215555 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/SelectionDAG/DAGCombiner.cpp
test/CodeGen/X86/combine-vec-shuffle-2.ll

index e8cbd8af7a83d9b2580250e66cde4349a42bb641..603ccb090ed94d00bee05ef5371a8a03ed77a12a 100644 (file)
@@ -10838,16 +10838,30 @@ SDValue DAGCombiner::visitVECTOR_SHUFFLE(SDNode *N) {
 
     // It may still be beneficial to combine the two shuffles if the
     // resulting shuffle is legal.
-    if (TLI.isTypeLegal(VT) && TLI.isShuffleMaskLegal(Mask, VT)) {
-      if (!CommuteOperands)
-        // shuffle(shuffle(x, undef, M1), undef, M2) -> shuffle(x, undef, M3).
-        // shuffle(shuffle(x, y, M1), undef, M2) -> shuffle(x, undef, M3)
-        return DAG.getVectorShuffle(VT, SDLoc(N), N0->getOperand(0), N1,
-                                    &Mask[0]);
-      
-      //   shuffle(shuffle(x, y, M1), undef, M2) -> shuffle(undef, y, M3)
-      return DAG.getVectorShuffle(VT, SDLoc(N), N1, N0->getOperand(1),
-                                  &Mask[0]);
+    if (TLI.isTypeLegal(VT)) {
+      if (!CommuteOperands) {
+        if (TLI.isShuffleMaskLegal(Mask, VT))
+          // shuffle(shuffle(x, undef, M1), undef, M2) -> shuffle(x, undef, M3).
+          // shuffle(shuffle(x, y, M1), undef, M2) -> shuffle(x, undef, M3)
+          return DAG.getVectorShuffle(VT, SDLoc(N), N0->getOperand(0), N1,
+                                      &Mask[0]);
+      } else {
+        // Compute the commuted shuffle mask.
+        for (unsigned i = 0; i != NumElts; ++i) {
+          int idx = Mask[i];
+          if (idx < 0)
+            continue;
+          else if (idx < (int)NumElts)
+            Mask[i] = idx + NumElts;
+          else
+            Mask[i] = idx - NumElts;
+        }
+
+        if (TLI.isShuffleMaskLegal(Mask, VT))
+          //   shuffle(shuffle(x, y, M1), undef, M2) -> shuffle(y, undef, M3)
+          return DAG.getVectorShuffle(VT, SDLoc(N), N0->getOperand(1), N1,
+                                      &Mask[0]);
+      }
     }
   }
 
index 877d38260d6133cbc5368e58d6882bdb07f70c57..872384ca0a185c75a1c0c30559c7ff1ab5e4e94d 100644 (file)
@@ -204,8 +204,8 @@ define <4 x i32> @test18(<4 x i32> %A, <4 x i32> %B) {
   ret <4 x i32> %2
 }
 ; CHECK-LABEL: test18
-; CHECK: blendps $11
-; CHECK-NEXT: pshufd $-59
+; CHECK-NOT: blendps
+; CHECK: pshufd {{.*}} # xmm0 = xmm1[1,1,0,3]
 ; CHECK-NEXT: ret
 
 define <4 x i32> @test19(<4 x i32> %A, <4 x i32> %B) {
@@ -240,6 +240,8 @@ define <4 x i32> @test21(<4 x i32> %A, <4 x i32> %B) {
 ; CHECK-NEXT: pshufd $-60
 ; CHECK-NEXT: ret
 
+; Test that we correctly combine shuffles according to rule
+;  shuffle(shuffle(x, y), undef) -> shuffle(y, undef)
 
 define <4 x i32> @test22(<4 x i32> %A, <4 x i32> %B) {
   %1 = shufflevector <4 x i32> %A, <4 x i32> %B, <4 x i32> <i32 4, i32 5, i32 2, i32 7>
@@ -247,7 +249,69 @@ define <4 x i32> @test22(<4 x i32> %A, <4 x i32> %B) {
   ret <4 x i32> %2
 }
 ; CHECK-LABEL: test22
-; CHECK: blendps $11
-; CHECK-NEXT: pshufd $-43
+; CHECK-NOT: blendps
+; CHECK: pshufd {{.*}} # xmm0 = xmm1[1,1,1,3]
+; CHECK-NEXT: ret
+
+define <4 x i32> @test23(<4 x i32> %A, <4 x i32> %B) {
+  %1 = shufflevector <4 x i32> %A, <4 x i32> %B, <4 x i32> <i32 4, i32 5, i32 2, i32 7>
+  %2 = shufflevector <4 x i32> %1, <4 x i32> undef, <4 x i32> <i32 0, i32 1, i32 0, i32 3>
+  ret <4 x i32> %2
+}
+; CHECK-LABEL: test23
+; CHECK-NOT: blendps
+; CHECK: pshufd {{.*}} # xmm0 = xmm1[0,1,0,3]
+; CHECK-NEXT: ret
+
+define <4 x i32> @test24(<4 x i32> %A, <4 x i32> %B) {
+  %1 = shufflevector <4 x i32> %A, <4 x i32> %B, <4 x i32> <i32 4, i32 1, i32 6, i32 7>
+  %2 = shufflevector <4 x i32> %1, <4 x i32> undef, <4 x i32> <i32 0, i32 3, i32 2, i32 4>
+  ret <4 x i32> %2
+}
+; CHECK-LABEL: test24
+; CHECK-NOT: blendps
+; CHECK: pshufd {{.*}} # xmm0 = xmm1[0,3,2,0]
+; CHECK-NEXT: ret
+
+define <4 x i32> @test25(<4 x i32> %A, <4 x i32> %B) {
+  %1 = shufflevector <4 x i32> %B, <4 x i32> %A, <4 x i32> <i32 1, i32 5, i32 2, i32 4>
+  %2 = shufflevector <4 x i32> %1, <4 x i32> undef, <4 x i32> <i32 3, i32 1, i32 3, i32 1>
+  ret <4 x i32> %2
+}
+; CHECK-LABEL: test25
+; CHECK-NOT:  shufps
+; CHECK: pshufd {{.*}} # xmm0 = xmm0[0,1,0,1]
+; CHECK-NEXT: ret
+
+define <4 x i32> @test26(<4 x i32> %A, <4 x i32> %B) {
+  %1 = shufflevector <4 x i32> %B, <4 x i32> %A, <4 x i32> <i32 1, i32 2, i32 6, i32 7>
+  %2 = shufflevector <4 x i32> %1, <4 x i32> undef, <4 x i32> <i32 2, i32 3, i32 2, i32 3>
+  ret <4 x i32> %2
+}
+; CHECK-LABEL: test26
+; CHECK-NOT: shufps
+; CHECK: movhlps {{.*}} # xmm0 = xmm0[1,1]
+; CHECK-NEXT: ret
+
+define <4 x i32> @test27(<4 x i32> %A, <4 x i32> %B) {
+  %1 = shufflevector <4 x i32> %B, <4 x i32> %A, <4 x i32> <i32 2, i32 1, i32 5, i32 4>
+  %2 = shufflevector <4 x i32> %1, <4 x i32> undef, <4 x i32> <i32 3, i32 2, i32 3, i32 2>
+  ret <4 x i32> %2
+}
+; CHECK-LABEL: test27
+; CHECK-NOT: shufps
+; CHECK-NOT: movhlps
+; CHECK: pshufd {{.*}} # xmm0 = xmm0[0,1,0,1]
+; CHECK-NEXT: ret
+
+define <4 x i32> @test28(<4 x i32> %A, <4 x i32> %B) {
+  %1 = shufflevector <4 x i32> %B, <4 x i32> %A, <4 x i32> <i32 1, i32 2, i32 4, i32 5>
+  %2 = shufflevector <4 x i32> %1, <4 x i32> undef, <4 x i32> <i32 2, i32 3, i32 3, i32 2>
+  ret <4 x i32> %2
+}
+; CHECK-LABEL: test28
+; CHECK-NOT: shufps
+; CHECK-NOT: movhlps
+; CHECK: pshufd {{.*}} # xmm0 = xmm0[0,1,1,0]
 ; CHECK-NEXT: ret