diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h index 5df40671b52..a49d18bbb95 100644 --- a/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/include/llvm/CodeGen/SelectionDAGNodes.h @@ -1583,11 +1583,16 @@ public: unsigned MinSplatBits = 0, bool isBigEndian = false) const; - /// getConstantSplatValue - Check if this is a constant splat, and if so, - /// return the splat value only if it is a ConstantSDNode. Otherwise - /// return nullptr. This is a simpler form of isConstantSplat. - /// Get the constant splat only if you care about the splat value. - ConstantSDNode *getConstantSplatValue() const; + /// \brief Returns the splatted value or a null value if this is not a splat. + SDValue getSplatValue(bool &HasUndefElements) const; + + /// \brief Returns the splatted constant or null if this is not a constant + /// splat. + ConstantSDNode *getConstantSplatNode(bool &HasUndefElements) const; + + /// \brief Returns the splatted constant FP or null if this is not a constant + /// FP splat. + ConstantFPSDNode *getConstantFPSplatNode(bool &HasUndefElements) const; bool isConstant() const; diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 7198203036b..5d2b02b4bff 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -655,10 +655,14 @@ static ConstantSDNode *isConstOrConstSplat(SDValue N) { return CN; if (BuildVectorSDNode *BV = dyn_cast(N)) { - ConstantSDNode *CN = BV->getConstantSplatValue(); + bool HasUndefElements; + ConstantSDNode *CN = BV->getConstantSplatNode(HasUndefElements); // BuildVectors can truncate their operands. Ignore that case here. - if (CN && CN->getValueType(0) == N.getValueType().getScalarType()) + // FIXME: We blindly ignore splats which include undef which is overly + // pessimistic. + if (CN && !HasUndefElements && + CN->getValueType(0) == N.getValueType().getScalarType()) return CN; } diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 3a8a5f9601f..e41d459f39d 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -1506,8 +1506,10 @@ SDValue SelectionDAG::getVectorShuffle(EVT VT, SDLoc dl, SDValue N1, return N1; // Shuffling a constant splat doesn't change the result. + bool SplatHasUndefs; if (N2Undef && N1.getOpcode() == ISD::BUILD_VECTOR) - if (cast(N1)->getConstantSplatValue()) + if (cast(N1)->getConstantSplatNode(SplatHasUndefs) && + !SplatHasUndefs) return N1; FoldingSetNodeID ID; @@ -6603,16 +6605,38 @@ bool BuildVectorSDNode::isConstantSplat(APInt &SplatValue, return true; } -ConstantSDNode *BuildVectorSDNode::getConstantSplatValue() const { - SDValue Op0 = getOperand(0); - if (Op0.getOpcode() != ISD::Constant) - return nullptr; +SDValue BuildVectorSDNode::getSplatValue(bool &HasUndefElements) const { + HasUndefElements = false; + SDValue Splatted; + for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { + SDValue Op = getOperand(i); + if (Op.getOpcode() == ISD::UNDEF) + HasUndefElements = true; + else if (!Splatted) + Splatted = Op; + else if (Splatted != Op) + return SDValue(); + } - for (unsigned i = 1, e = getNumOperands(); i != e; ++i) - if (getOperand(i) != Op0) - return nullptr; + if (!Splatted) { + assert(getOperand(0).getOpcode() == ISD::UNDEF && + "Can only have a splat without a constant for all undefs."); + return getOperand(0); + } - return cast(Op0); + return Splatted; +} + +ConstantSDNode * +BuildVectorSDNode::getConstantSplatNode(bool &HasUndefElements) const { + return dyn_cast_or_null( + getSplatValue(HasUndefElements).getNode()); +} + +ConstantFPSDNode * +BuildVectorSDNode::getConstantFPSplatNode(bool &HasUndefElements) const { + return dyn_cast_or_null( + getSplatValue(HasUndefElements).getNode()); } bool BuildVectorSDNode::isConstant() const { diff --git a/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/lib/CodeGen/SelectionDAG/TargetLowering.cpp index ad91d4a87c1..74de034777d 100644 --- a/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -1158,7 +1158,10 @@ bool TargetLowering::isConstTrueVal(const SDNode *N) const { return false; IsVec = true; - CN = BV->getConstantSplatValue(); + bool HasUndefElements; + CN = BV->getConstantSplatNode(HasUndefElements); + if (HasUndefElements) + return false; // Can't blindly collapse the undef values. } switch (getBooleanContents(IsVec)) { @@ -1185,7 +1188,10 @@ bool TargetLowering::isConstFalseVal(const SDNode *N) const { return false; IsVec = true; - CN = BV->getConstantSplatValue(); + bool HasUndefElements; + CN = BV->getConstantSplatNode(HasUndefElements); + if (HasUndefElements) + return false; // Can't blindly collapse the undef values. } if (getBooleanContents(IsVec) == UndefinedBooleanContent)