SelectionDAG: Teach the legalizer to split SETCC if VSELECT needs splitting too.
authorJuergen Ributzka <juergen@apple.com>
Sat, 21 Sep 2013 04:55:18 +0000 (04:55 +0000)
committerJuergen Ributzka <juergen@apple.com>
Sat, 21 Sep 2013 04:55:18 +0000 (04:55 +0000)
The Type Legalizer recognizes that VSELECT needs to be split, because the type
is to wide for the given target. The same does not always apply to SETCC,
because less space is required to encode the result of a comparison. As a result
VSELECT is split and SETCC is unrolled into scalar comparisons.

This commit fixes the issue by checking for VSELECT-SETCC patterns in the DAG
Combiner. If a matching pattern is found, then the result mask of SETCC is
promoted to the expected vector mask for the given target. This mask has usually
te same size as the VSELECT return type (except for Intel KNL). Now the type
legalizer will split both VSELECT and SETCC.

This allows the following X86 DAG Combine code to sucessfully detect the MIN/MAX
pattern. This fixes PR16695, PR17002, and <rdar://problem/14594431>.

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

lib/CodeGen/SelectionDAG/DAGCombiner.cpp
lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp
lib/Target/X86/X86ISelLowering.cpp
test/CodeGen/X86/vec_split.ll [new file with mode: 0644]

index b355cc9a6483a3efcc8756157ce648fb14561017..2c0ed3f586f10370c329b5a94b874f5acaf23956 100644 (file)
@@ -4327,6 +4327,27 @@ SDValue DAGCombiner::visitVSELECT(SDNode *N) {
     }
   }
 
+  // Treat SETCC as a mask and promote the result type based on the targets
+  // expected SETCC result type. This will ensure that SETCC and VSELECT are
+  // both split by the type legalizer. This is done to prevent the type
+  // legalizer from unrolling SETCC into scalar comparions.
+  EVT SelectVT = N->getValueType(0);
+  if (N0.getOpcode() == ISD::SETCC &&
+      N0.getValueType() != getSetCCResultType(SelectVT)) {
+    SDLoc MaskDL(N0);
+    EVT MaskVT = getSetCCResultType(SelectVT);
+
+    SDValue Mask = DAG.getNode(ISD::SETCC, MaskDL, MaskVT, N0->getOperand(0),
+                               N0->getOperand(1), N0->getOperand(2));
+
+    AddToWorkList(Mask.getNode());
+
+    SDValue LHS = N->getOperand(1);
+    SDValue RHS = N->getOperand(2);
+
+    return DAG.getNode(ISD::VSELECT, DL, SelectVT, Mask, LHS, RHS);
+  }
+
   return SDValue();
 }
 
index d2c26d55073b7a71df1ed07a40746bff38db6643..136d104a4baf99452c92d852a596294e1322bc06 100644 (file)
@@ -489,14 +489,20 @@ void DAGTypeLegalizer::SplitRes_SELECT(SDNode *N, SDValue &Lo,
   SDValue Cond = N->getOperand(0);
   CL = CH = Cond;
   if (Cond.getValueType().isVector()) {
-    assert(Cond.getValueType().getVectorElementType() == MVT::i1 &&
-           "Condition legalized before result?");
-    unsigned NumElements = Cond.getValueType().getVectorNumElements();
-    EVT VCondTy = EVT::getVectorVT(*DAG.getContext(), MVT::i1, NumElements / 2);
-    CL = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VCondTy, Cond,
-                     DAG.getConstant(0, TLI.getVectorIdxTy()));
-    CH = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VCondTy, Cond,
-                     DAG.getConstant(NumElements / 2, TLI.getVectorIdxTy()));
+    if (Cond.getOpcode() == ISD::SETCC) {
+      assert(Cond.getValueType() == getSetCCResultType(N->getValueType(0)) &&
+             "Condition has not been prepared for split!");
+      GetSplitVector(Cond, CL, CH);
+    } else {
+      assert(Cond.getValueType().getVectorElementType() == MVT::i1 &&
+             "Condition legalized before result?");
+      unsigned NumElements = Cond.getValueType().getVectorNumElements();
+      EVT VCondTy = EVT::getVectorVT(*DAG.getContext(), MVT::i1, NumElements / 2);
+      CL = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VCondTy, Cond,
+                       DAG.getConstant(0, TLI.getVectorIdxTy()));
+      CH = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, VCondTy, Cond,
+                       DAG.getConstant(NumElements / 2, TLI.getVectorIdxTy()));
+    }
   }
 
   Lo = DAG.getNode(N->getOpcode(), dl, LL.getValueType(), CL, LL, RL);
index b3cac0523f3f7be374155ed4e93eada4a4f0a209..974a1ee2da3197f44b3d040e168d43cdcce84bb9 100644 (file)
@@ -1535,7 +1535,16 @@ void X86TargetLowering::resetOperationActions() {
 }
 
 EVT X86TargetLowering::getSetCCResultType(LLVMContext &, EVT VT) const {
-  if (!VT.isVector()) return MVT::i8;
+  if (!VT.isVector())
+    return MVT::i8;
+
+  const TargetMachine &TM = getTargetMachine();
+  if (!TM.Options.UseSoftFloat && Subtarget->hasAVX512())
+    switch(VT.getVectorNumElements()) {
+    case  8: return MVT::v8i1;
+    case 16: return MVT::v16i1;
+    }
+
   return VT.changeVectorElementTypeToInteger();
 }
 
diff --git a/test/CodeGen/X86/vec_split.ll b/test/CodeGen/X86/vec_split.ll
new file mode 100644 (file)
index 0000000..a49af34
--- /dev/null
@@ -0,0 +1,29 @@
+; RUN: llc -march=x86-64 -mcpu=corei7 < %s | FileCheck %s -check-prefix=SSE4
+; RUN: llc -march=x86-64 -mcpu=core-avx2 < %s | FileCheck %s -check-prefix=AVX2
+
+define <16 x i16> @split16(<16 x i16> %a, <16 x i16> %b, <16 x i8> %__mask) {
+; SSE4-LABEL: split16:
+; SSE4: pminuw
+; SSE4: pminuw
+; AVX2-LABEL: split16:
+; AVX2: vpminuw
+; AVX2: ret
+  %1 = icmp ult <16 x i16> %a, %b
+  %2 = select <16 x i1> %1, <16 x i16> %a, <16 x i16> %b
+  ret <16 x i16> %2
+}
+
+define <32 x i16> @split32(<32 x i16> %a, <32 x i16> %b, <32 x i8> %__mask) {
+; SSE4-LABEL: split32:
+; SSE4: pminuw
+; SSE4: pminuw
+; SSE4: pminuw
+; SSE4: pminuw
+; AVX2-LABEL: split32:
+; AVX2: vpminuw
+; AVX2: vpminuw
+; AVX2: ret
+  %1 = icmp ult <32 x i16> %a, %b
+  %2 = select <32 x i1> %1, <32 x i16> %a, <32 x i16> %b
+  ret <32 x i16> %2
+}