From 24e338e8a3dab2923db30fe63d77a5ac95456ff9 Mon Sep 17 00:00:00 2001 From: Bob Wilson Date: Mon, 2 Mar 2009 23:24:16 +0000 Subject: [PATCH] Generalize BuildVectorSDNode::isConstantSplat to use APInts and handle arbitrary vector sizes. Add an optional MinSplatBits parameter to specify a minimum for the splat element size. Update the PPC target to use the revised interface. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@65899 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/SelectionDAGNodes.h | 19 ++-- lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 127 +++++++++------------- lib/Target/PowerPC/PPCISelLowering.cpp | 19 ++-- 3 files changed, 72 insertions(+), 93 deletions(-) diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h index b10c865f09f..e945b983ef2 100644 --- a/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/include/llvm/CodeGen/SelectionDAGNodes.h @@ -1933,13 +1933,18 @@ public: /// BUILD_VECTORs. class BuildVectorSDNode : public SDNode { public: - /// isConstantSplat - check if this is a constant splat, and if so, return - /// the splat element value in SplatBits. Any undefined bits in that value - /// are set to zero, and the corresponding bits in the SplatUndef mask are - /// set. The SplatSize value is set to the splat element size in bytes. - /// HasAnyUndefs is set to true if any bits in the vector are undefined. - bool isConstantSplat(unsigned &SplatBits, unsigned &SplatUndef, - unsigned &SplatSize, bool &HasAnyUndefs); + /// isConstantSplat - Check if this is a constant splat, and if so, find the + /// smallest element size that splats the vector. If MinSplatBits is + /// nonzero, the element size must be at least that large. Note that the + /// splat element may be the entire vector (i.e., a one element vector). + /// Returns the splat element value in SplatValue. Any undefined bits in + /// that value are zero, and the corresponding bits in the SplatUndef mask + /// are set. The SplatBitSize value is set to the splat element size in + /// bits. HasAnyUndefs is set to true if any bits in the vector are + /// undefined. + bool isConstantSplat(APInt &SplatValue, APInt &SplatUndef, + unsigned &SplatBitSize, bool &HasAnyUndefs, + unsigned MinSplatBits = 0); static inline bool classof(const BuildVectorSDNode *) { return true; } static inline bool classof(const SDNode *N) { diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 9dfd6be9d5b..886e726408c 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -5555,93 +5555,64 @@ const Type *ConstantPoolSDNode::getType() const { return Val.ConstVal->getType(); } -// If this is a splat (repetition) of a value across the whole vector, return -// the smallest size that splats it. For example, "0x01010101010101..." is a -// splat of 0x01, 0x0101, and 0x01010101. We return SplatBits = 0x01 and -// SplatSize = 1 byte. -bool BuildVectorSDNode::isConstantSplat(unsigned &SplatBits, - unsigned &SplatUndef, - unsigned &SplatSize, - bool &HasAnyUndefs) { - uint64_t Bits128[2]; - uint64_t Undef128[2]; - - // If this is a vector of constants or undefs, get the bits. A bit in - // UndefBits is set if the corresponding element of the vector is an - // ISD::UNDEF value. For undefs, the corresponding VectorBits values are - // zero. - - // Start with zero'd results. - Bits128[0] = Bits128[1] = Undef128[0] = Undef128[1] = 0; - - unsigned EltBitSize = getOperand(0).getValueType().getSizeInBits(); - for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { - SDValue OpVal = getOperand(i); - - unsigned PartNo = i >= e/2; // In the upper 128 bits? - unsigned SlotNo = e/2 - (i & (e/2-1))-1; // Which subpiece of the uint64_t. +bool BuildVectorSDNode::isConstantSplat(APInt &SplatValue, + APInt &SplatUndef, + unsigned &SplatBitSize, + bool &HasAnyUndefs, + unsigned MinSplatBits) { + MVT VT = getValueType(0); + assert(VT.isVector() && "Expected a vector type"); + unsigned sz = VT.getSizeInBits(); + if (MinSplatBits > sz) + return false; - uint64_t EltBits = 0; - if (OpVal.getOpcode() == ISD::UNDEF) { - uint64_t EltUndefBits = ~0U >> (32-EltBitSize); - Undef128[PartNo] |= EltUndefBits << (SlotNo*EltBitSize); - continue; - } else if (ConstantSDNode *CN = dyn_cast(OpVal)) { - EltBits = CN->getZExtValue() & (~0U >> (32-EltBitSize)); - } else if (ConstantFPSDNode *CN = dyn_cast(OpVal)) { - assert(CN->getValueType(0) == MVT::f32 && - "Only one legal FP vector type!"); - EltBits = FloatToBits(CN->getValueAPF().convertToFloat()); - } else { - // Nonconstant element. + SplatValue = APInt(sz, 0); + SplatUndef = APInt(sz, 0); + + // Get the bits. Bits with undefined values (when the corresponding element + // of the vector is an ISD::UNDEF value) are set in SplatUndef and cleared + // in SplatValue. If any of the values are not constant, give up and return + // false. + unsigned int nOps = getNumOperands(); + assert(nOps > 0 && "isConstantSplat has 0-size build vector"); + unsigned EltBitSize = VT.getVectorElementType().getSizeInBits(); + for (unsigned i = 0; i < nOps; ++i) { + SDValue OpVal = getOperand(i); + unsigned BitPos = i * EltBitSize; + + if (OpVal.getOpcode() == ISD::UNDEF) + SplatUndef |= APInt::getBitsSet(sz, BitPos, BitPos +EltBitSize); + else if (ConstantSDNode *CN = dyn_cast(OpVal)) + SplatValue |= APInt(CN->getAPIntValue()).zext(sz) << BitPos; + else if (ConstantFPSDNode *CN = dyn_cast(OpVal)) + SplatValue |= CN->getValueAPF().bitcastToAPInt().zext(sz) << BitPos; + else return false; - } - - Bits128[PartNo] |= EltBits << (SlotNo*EltBitSize); } - // Don't let undefs prevent splats from matching. See if the top 64-bits are - // the same as the lower 64-bits, ignoring undefs. - if ((Bits128[0] & ~Undef128[1]) != (Bits128[1] & ~Undef128[0])) - return false; // Can't be a splat if two pieces don't match. + // The build_vector is all constants or undefs. Find the smallest element + // size that splats the vector. - uint64_t Bits64 = Bits128[0] | Bits128[1]; - uint64_t Undef64 = Undef128[0] & Undef128[1]; + HasAnyUndefs = (SplatUndef != 0); + while (sz > 8) { - // Check that the top 32-bits are the same as the lower 32-bits, ignoring - // undefs. - if ((Bits64 & (~Undef64 >> 32)) != ((Bits64 >> 32) & ~Undef64)) - return false; // Can't be a splat if two pieces don't match. - - HasAnyUndefs = (Undef128[0] | Undef128[1]) != 0; - - uint32_t Bits32 = uint32_t(Bits64) | uint32_t(Bits64 >> 32); - uint32_t Undef32 = uint32_t(Undef64) & uint32_t(Undef64 >> 32); - - // If the top 16-bits are different than the lower 16-bits, ignoring - // undefs, we have an i32 splat. - if ((Bits32 & (~Undef32 >> 16)) != ((Bits32 >> 16) & ~Undef32)) { - SplatBits = Bits32; - SplatUndef = Undef32; - SplatSize = 4; - return true; - } + unsigned HalfSize = sz / 2; + APInt HighValue = APInt(SplatValue).lshr(HalfSize).trunc(HalfSize); + APInt LowValue = APInt(SplatValue).trunc(HalfSize); + APInt HighUndef = APInt(SplatUndef).lshr(HalfSize).trunc(HalfSize); + APInt LowUndef = APInt(SplatUndef).trunc(HalfSize); - uint16_t Bits16 = uint16_t(Bits32) | uint16_t(Bits32 >> 16); - uint16_t Undef16 = uint16_t(Undef32) & uint16_t(Undef32 >> 16); + // If the two halves do not match (ignoring undef bits), stop here. + if ((HighValue & ~LowUndef) != (LowValue & ~HighUndef) || + MinSplatBits > HalfSize) + break; - // If the top 8-bits are different than the lower 8-bits, ignoring - // undefs, we have an i16 splat. - if ((Bits16 & (uint16_t(~Undef16) >> 8)) != ((Bits16 >> 8) & ~Undef16)) { - SplatBits = Bits16; - SplatUndef = Undef16; - SplatSize = 2; - return true; + SplatValue = HighValue | LowValue; + SplatUndef = HighUndef & LowUndef; + + sz = HalfSize; } - // Otherwise, we have an 8-bit splat. - SplatBits = uint8_t(Bits16) | uint8_t(Bits16 >> 8); - SplatUndef = uint8_t(Undef16) & uint8_t(Undef16 >> 8); - SplatSize = 1; + SplatBitSize = sz; return true; } diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp index d2f90b51330..9c8f4e42d4f 100644 --- a/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/lib/Target/PowerPC/PPCISelLowering.cpp @@ -3167,13 +3167,16 @@ SDValue PPCTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) { BuildVectorSDNode *BVN = dyn_cast(Op.getNode()); assert(BVN != 0 && "Expected a BuildVectorSDNode in LowerBUILD_VECTOR"); - // If this is a splat (repetition) of a value across the whole vector, return - // the smallest size that splats it. For example, "0x01010101010101..." is a - // splat of 0x01, 0x0101, and 0x01010101. We return SplatBits = 0x01 and - // SplatSize = 1 byte. - unsigned SplatBits, SplatUndef, SplatSize; + // Check if this is a splat of a constant value. + APInt APSplatBits, APSplatUndef; + unsigned SplatBitSize; bool HasAnyUndefs; - if (BVN->isConstantSplat(SplatBits, SplatUndef, SplatSize, HasAnyUndefs)) { + if (BVN->isConstantSplat(APSplatBits, APSplatUndef, SplatBitSize, + HasAnyUndefs) && + SplatBitSize <= 32) { + unsigned SplatBits = APSplatBits.getZExtValue(); + unsigned SplatUndef = APSplatUndef.getZExtValue(); + unsigned SplatSize = SplatBitSize / 8; // First, handle single instruction cases. @@ -3189,7 +3192,8 @@ SDValue PPCTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) { } // If the sign extended value is in the range [-16,15], use VSPLTI[bhw]. - int32_t SextVal= int32_t(SplatBits << (32-8*SplatSize)) >> (32-8*SplatSize); + int32_t SextVal= (int32_t(SplatBits << (32-SplatBitSize)) >> + (32-SplatBitSize)); if (SextVal >= -16 && SextVal <= 15) return BuildSplatI(SextVal, SplatSize, Op.getValueType(), DAG, dl); @@ -3221,7 +3225,6 @@ SDValue PPCTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) { } // Check to see if this is a wide variety of vsplti*, binop self cases. - unsigned SplatBitSize = SplatSize*8; static const signed char SplatCsts[] = { -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7, -8, 8, -9, 9, -10, 10, -11, 11, -12, 12, -13, 13, 14, -14, 15, -15, -16 -- 2.34.1