Index: lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -1089,6 +1089,10 @@ SDValue Cond = N->getOperand(0); EVT OpTy = N->getOperand(1).getValueType(); + if (N->getOpcode() == ISD::VSELECT && Cond->getOpcode() == ISD::SETCC) + if (SDValue Res = WidenVSELECT_SETCC(N)) + return Res; + // Promote all the way up to the canonical SetCC type. EVT OpVT = N->getOpcode() == ISD::SELECT ? OpTy.getScalarType() : OpTy; Cond = PromoteTargetBoolean(Cond, OpVT); Index: lib/CodeGen/SelectionDAG/LegalizeTypes.h =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -724,6 +724,7 @@ SDValue WidenVecRes_UNDEF(SDNode *N); SDValue WidenVecRes_VECTOR_SHUFFLE(ShuffleVectorSDNode *N); SDValue WidenVecRes_VSETCC(SDNode* N); + SDValue WidenVSELECT_SETCC(SDNode *N); SDValue WidenVecRes_Ternary(SDNode *N); SDValue WidenVecRes_Binary(SDNode *N); Index: lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -2859,6 +2859,80 @@ WidenVT, N->getOperand(0)); } +// This method is needed to handle the case where either the SetCCResultType +// or the VSELECT VT needs widening. It only handles the case where all the +// target vector registers are of the same size and hold a varying number of +// elements depending on the element size. +SDValue DAGTypeLegalizer::WidenVSELECT_SETCC(SDNode *N) { + LLVMContext &Ctx = *DAG.getContext(); + SDValue Cond = N->getOperand(0); + + if (N->getOpcode() != ISD::VSELECT || Cond->getOpcode() != ISD::SETCC) + return SDValue(); + + // Get the VTs for the SETCC and VSELECT, and widen them and the VSELECT + // operands if needed. + EVT SetccVT = getSetCCResultType(Cond->getOperand(0).getValueType()); + if (getTypeAction(SetccVT) == TargetLowering::TypeWidenVector) + SetccVT = TLI.getTypeToTransformTo(Ctx, SetccVT); + + EVT VSelVT = N->getValueType(0); + SDValue VSelOp1 = N->getOperand(1); + SDValue VSelOp2 = N->getOperand(2); + if (getTypeAction(VSelVT) == TargetLowering::TypeWidenVector) { + VSelVT = TLI.getTypeToTransformTo(Ctx, VSelVT); + VSelOp1 = GetWidenedVector(VSelOp1); + VSelOp2 = GetWidenedVector(VSelOp2); + } + + // The mask of the VSELECT should have integer elements. + EVT MaskVT = VSelVT; + if (!MaskVT.getScalarType().isInteger()) + MaskVT = MaskVT.changeVectorElementTypeToInteger(); + + // SetccVT and VSelVT must be of same size if they are both legal. + if (getTypeAction(SetccVT) == TargetLowering::TypeLegal && + getTypeAction(VSelVT) == TargetLowering::TypeLegal && + SetccVT.getSizeInBits() != VSelVT.getSizeInBits()) + return SDValue(); + + // If SetccVT has smaller elements than the VSELECT, a + // SIGN_EXTEND_VECTOR_INREG is made. + if ((SetccVT.getScalarSizeInBits() < MaskVT.getScalarSizeInBits()) && + ((SetccVT.getSizeInBits() != MaskVT.getSizeInBits()) || + (SetccVT.getVectorNumElements() <= MaskVT.getVectorNumElements()))) + return SDValue(); + + // Make a new SETCC node, with a legal VT. + Cond = DAG.getNode(ISD::SETCC, SDLoc(Cond), SetccVT, + Cond->getOperand(0), Cond->getOperand(1), Cond->getOperand(2)); + + // After widening, the new SetCCVT and MaskVT types may not have the same + // VTs. Handle as needed with vector sign extension or truncatation. + SDValue Mask; + if (SetccVT == MaskVT) + Mask = Cond; + else if (SetccVT.getScalarSizeInBits() < MaskVT.getScalarSizeInBits()) + Mask = DAG.getSignExtendVectorInReg(Cond, SDLoc(N), MaskVT); + else { + // SetccVT has wider elements: truncate. + EVT SubVT = + EVT::getVectorVT(Ctx, MaskVT.getVectorElementType(), + SetccVT.getVectorNumElements()); + SDValue TruncCC = DAG.getNode(ISD::TRUNCATE, SDLoc(N), SubVT, Cond); + + unsigned NumSubVecs = VSelVT.getVectorNumElements() / SubVT.getVectorNumElements(); + SmallVector SubConcatOps(NumSubVecs); + SubConcatOps[0] = TruncCC; + for (unsigned i = 1; i < NumSubVecs; ++i) + SubConcatOps[i] = DAG.getUNDEF(SubVT); + + Mask = DAG.getNode(ISD::CONCAT_VECTORS, SDLoc(N), MaskVT, SubConcatOps); + } + + return DAG.getNode(ISD::VSELECT, SDLoc(N), VSelVT, Mask, VSelOp1, VSelOp2); +} + SDValue DAGTypeLegalizer::WidenVecRes_SELECT(SDNode *N) { EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); unsigned WidenNumElts = WidenVT.getVectorNumElements(); @@ -2866,6 +2940,9 @@ SDValue Cond1 = N->getOperand(0); EVT CondVT = Cond1.getValueType(); if (CondVT.isVector()) { + if (SDValue Res = WidenVSELECT_SETCC(N)) + return Res; + EVT CondEltVT = CondVT.getVectorElementType(); EVT CondWidenVT = EVT::getVectorVT(*DAG.getContext(), CondEltVT, WidenNumElts);