Index: include/llvm/IR/Instructions.h =================================================================== --- include/llvm/IR/Instructions.h +++ include/llvm/IR/Instructions.h @@ -2426,7 +2426,7 @@ /// Return the shuffle mask value for the specified element of the mask. /// Return -1 if the element is undef. - static int getMaskValue(Constant *Mask, unsigned Elt); + static int getMaskValue(const Constant *Mask, unsigned Elt); /// Return the shuffle mask value of this instruction for the given element /// index. Return -1 if the element is undef. @@ -2436,7 +2436,8 @@ /// Convert the input shuffle mask operand to a vector of integers. Undefined /// elements of the mask are returned as -1. - static void getShuffleMask(Constant *Mask, SmallVectorImpl &Result); + static void getShuffleMask(const Constant *Mask, + SmallVectorImpl &Result); /// Return the mask for this instruction as a vector of integers. Undefined /// elements of the mask are returned as -1. @@ -2450,6 +2451,170 @@ return Mask; } + /// Return true if this shuffle returns a vector with a different number of + /// elements than its source elements. + /// Example: shufflevector <4 x n> A, <4 x n> B, <1,2> + bool changesLength() const { + unsigned NumSourceElts = Op<0>()->getType()->getVectorNumElements(); + unsigned NumMaskElts = getMask()->getType()->getVectorNumElements(); + return NumSourceElts != NumMaskElts; + } + + /// Return true if this shuffle mask chooses elements from exactly one source + /// vector without lane crossings. A shuffle using this mask is not + /// necessarily a no-op because it may change the number of elements from its + /// input vectors or it may provide demanded bits knowledge via undef lanes. + /// Example: <-1,1,-1,3> + static bool isIdentityMask(ArrayRef Mask); + static bool isIdentityMask(const Constant *Mask) { + assert(Mask->getType()->isVectorTy() && "Shuffle needs vector constant."); + SmallVector MaskAsInts; + getShuffleMask(Mask, MaskAsInts); + return isIdentityMask(MaskAsInts); + } + + /// Return true if this shuffle mask chooses elements from exactly one source + /// vector without lane crossings and does not change the number of elements + /// from its input vectors. + /// Example: shufflevector <4 x n> A, <4 x n> B, <4,undef,6,undef> + bool isIdentity() const { + return !changesLength() && isIdentityMask(getShuffleMask()); + } + + /// Return true if this shuffle mask chooses elements from its source vectors + /// without lane crossings. A shuffle using this mask would be + /// equivalent to a vector select with a constant condition operand. + /// Example: <4,1,6,-1> + /// This returns false if the mask does not choose from both input vectors. + /// In that case, the shuffle is better classified as an identity shuffle. + /// This assumes that vector operands are the same length as the mask + /// (a length-changing shuffle can never be equivalent to a vector select). + static bool isSelectMask(ArrayRef Mask); + static bool isSelectMask(const Constant *Mask) { + assert(Mask->getType()->isVectorTy() && "Shuffle needs vector constant."); + SmallVector MaskAsInts; + getShuffleMask(Mask, MaskAsInts); + return isSelectMask(MaskAsInts); + } + + /// Return true if this shuffle chooses elements from its source vectors + /// without lane crossings and all operands have the same number of elements. + /// In other words, this shuffle is equivalent to a vector select with a + /// constant condition operand. + /// Example: shufflevector <4 x n> A, <4 x n> B, + /// This returns false if the mask does not choose from both input vectors. + /// In that case, the shuffle is better classified as an identity shuffle. + bool isSelect() const { + return !changesLength() && isSelectMask(getMask()); + } + + /// Return true if this shuffle mask swaps the order of elements from exactly + /// one source vector. + /// Example: <7,6,-1,4> + /// This assumes that vector operands are the same length as the mask. + static bool isReverseMask(ArrayRef Mask); + static bool isReverseMask(const Constant *Mask) { + assert(Mask->getType()->isVectorTy() && "Shuffle needs vector constant."); + SmallVector MaskAsInts; + getShuffleMask(Mask, MaskAsInts); + return isReverseMask(MaskAsInts); + } + + /// Return true if this shuffle swaps the order of elements from exactly + /// one source vector. + /// Example: shufflevector <4 x n> A, <4 x n> B, <3,undef,1,undef> + bool isReverse() const { + return !changesLength() && isReverseMask(getMask()); + } + + /// Return true if this shuffle mask chooses elements from exactly one source + /// vector. + /// Example: <7,5,-1,7> + /// This assumes that vector operands are the same length as the mask. + static bool isSingleSourceMask(ArrayRef Mask); + static bool isSingleSourceMask(const Constant *Mask) { + assert(Mask->getType()->isVectorTy() && "Shuffle needs vector constant."); + SmallVector MaskAsInts; + getShuffleMask(Mask, MaskAsInts); + return isSingleSourceMask(MaskAsInts); + } + + /// Return true if this shuffle chooses elements from exactly one source + /// vector without changing the length of that vector. + /// Example: shufflevector <4 x n> A, <4 x n> B, <3,0,undef,3> + bool isSingleSource() const { + return !changesLength() && isSingleSourceMask(getMask()); + } + + /// Return true if this shuffle mask chooses all elements with the same value + /// as the first element of exactly one source vector. + /// Example: <4,-1,-1,4> + /// This assumes that vector operands are the same length as the mask. + static bool isZeroEltSplatMask(ArrayRef Mask); + static bool isZeroEltSplatMask(const Constant *Mask) { + assert(Mask->getType()->isVectorTy() && "Shuffle needs vector constant."); + SmallVector MaskAsInts; + getShuffleMask(Mask, MaskAsInts); + return isZeroEltSplatMask(MaskAsInts); + } + + /// Return true if all elements of this shuffle are the same value as the + /// first element of exactly one source vector without changing the length + /// of that vector. + /// Example: shufflevector <4 x n> A, <4 x n> B, + bool isZeroEltSplat() const { + return !changesLength() && isZeroEltSplatMask(getMask()); + } + + /// Return true if this shuffle mask is a transpose mask. + /// Transpose vector masks transpose a 2xn matrix. They read corresponding + /// even- or odd-numbered vector elements from two n-dimensional source + /// vectors and write each result into consecutive elements of an + /// n-dimensional destination vector. Two shuffles are necessary to complete + /// the transpose, one for the even elements and another for the odd elements. + /// This description closely follows how the TRN1 and TRN2 AArch64 + /// instructions operate. + /// + /// For example, a simple 2x2 matrix can be transposed with: + /// + /// ; Original matrix + /// m0 = + /// m1 = + /// + /// ; Transposed matrix + /// t0 = = shufflevector m0, m1, <0, 2> + /// t1 = = shufflevector m0, m1, <1, 3> + /// + /// For matrices having greater than n columns, the resulting nx2 transposed + /// matrix is stored in two result vectors such that one vector contains + /// interleaved elements from all the even-numbered rows and the other vector + /// contains interleaved elements from all the odd-numbered rows. For example, + /// a 2x4 matrix can be transposed with: + /// + /// ; Original matrix + /// m0 = + /// m1 = + /// + /// ; Transposed matrix + /// t0 = = shufflevector m0, m1 <0, 4, 2, 6> + /// t1 = = shufflevector m0, m1 <1, 5, 3, 7> + static bool isTransposeMask(ArrayRef Mask); + static bool isTransposeMask(const Constant *Mask) { + assert(Mask->getType()->isVectorTy() && "Shuffle needs vector constant."); + SmallVector MaskAsInts; + getShuffleMask(Mask, MaskAsInts); + return isTransposeMask(MaskAsInts); + } + + /// Return true if this shuffle transposes the elements of its inputs without + /// changing the length of the vectors. This operation may also be known as a + /// merge or interleave. See the description for isTransposeMask() for the + /// exact specification. + /// Example: shufflevector <4 x n> A, <4 x n> B, <0,4,2,6> + bool isTranspose() const { + return !changesLength() && isTransposeMask(getMask()); + } + /// Change values in a shuffle permute mask assuming the two vector operands /// of length InVecNumElts have swapped position. static void commuteShuffleMask(MutableArrayRef Mask, Index: lib/Analysis/TargetTransformInfo.cpp =================================================================== --- lib/Analysis/TargetTransformInfo.cpp +++ lib/Analysis/TargetTransformInfo.cpp @@ -630,147 +630,6 @@ return TTIImpl->getInstructionLatency(I); } -static bool isReverseVectorMask(ArrayRef Mask) { - bool ReverseLHS = true; - bool ReverseRHS = true; - unsigned MaskSize = Mask.size(); - - for (unsigned i = 0; i < MaskSize && (ReverseLHS || ReverseRHS); ++i) { - if (Mask[i] < 0) - continue; - ReverseLHS &= (Mask[i] == (int)(MaskSize - 1 - i)); - ReverseRHS &= (Mask[i] == (int)(MaskSize + MaskSize - 1 - i)); - } - return ReverseLHS || ReverseRHS; -} - -static bool isSingleSourceVectorMask(ArrayRef Mask) { - bool ShuffleLHS = false; - bool ShuffleRHS = false; - unsigned MaskSize = Mask.size(); - - for (unsigned i = 0; i < MaskSize && !(ShuffleLHS && ShuffleRHS); ++i) { - if (Mask[i] < 0) - continue; - if ((unsigned)Mask[i] >= MaskSize) - ShuffleRHS = true; - else - ShuffleLHS = true; - } - return !(ShuffleLHS && ShuffleRHS); -} - -static bool isZeroEltBroadcastVectorMask(ArrayRef Mask) { - bool BroadcastLHS = true; - bool BroadcastRHS = true; - unsigned MaskSize = Mask.size(); - - for (unsigned i = 0; i < MaskSize && (BroadcastLHS || BroadcastRHS); ++i) { - if (Mask[i] < 0) - continue; - BroadcastLHS &= (Mask[i] == 0); - BroadcastRHS &= (Mask[i] == (int)MaskSize); - } - return BroadcastLHS || BroadcastRHS; -} - -static bool isIdentityVectorMask(ArrayRef Mask) { - bool IdentityLHS = true; - bool IdentityRHS = true; - unsigned MaskSize = Mask.size(); - - // Example: shufflevector A, B, <0,1,u,3> - // Example: shufflevector A, B, <4,u,6,u> - for (unsigned i = 0; i < MaskSize && (IdentityLHS || IdentityRHS); ++i) { - if (Mask[i] < 0) - continue; - IdentityLHS &= (Mask[i] == (int)i); - IdentityRHS &= (Mask[i] == (int)(i + MaskSize)); - } - return IdentityLHS || IdentityRHS; -} - -static bool isSelectVectorMask(ArrayRef Mask) { - bool IsSelect = true; - bool FoundLHS = false; - bool FoundRHS = false; - unsigned MaskSize = Mask.size(); - - // Example: shufflevector A, B, <0,1,6,3> - // Example: shufflevector A, B, <4,1,6,3> - for (unsigned i = 0; i < MaskSize && IsSelect; ++i) { - if (Mask[i] < 0) - continue; - bool IsLHS = (Mask[i] == (int)i); - bool IsRHS = (Mask[i] == (int)(i + MaskSize)); - FoundLHS |= IsLHS; - FoundRHS |= IsRHS; - IsSelect = IsLHS || IsRHS; - } - // If we don't use both vectors this is really an Identity mask. - return IsSelect && FoundLHS && FoundRHS; -} - -static bool isTransposeVectorMask(ArrayRef Mask) { - // Transpose vector masks transpose a 2xn matrix. They read corresponding - // even- or odd-numbered vector elements from two n-dimensional source - // vectors and write each result into consecutive elements of an - // n-dimensional destination vector. Two shuffles are necessary to complete - // the transpose, one for the even elements and another for the odd elements. - // This description closely follows how the TRN1 and TRN2 AArch64 - // instructions operate. - // - // For example, a simple 2x2 matrix can be transposed with: - // - // ; Original matrix - // m0 = - // m1 = - // - // ; Transposed matrix - // t0 = = shufflevector m0, m1, <0, 2> - // t1 = = shufflevector m0, m1, <1, 3> - // - // For matrices having greater than n columns, the resulting nx2 transposed - // matrix is stored in two result vectors such that one vector contains - // interleaved elements from all the even-numbered rows and the other vector - // contains interleaved elements from all the odd-numbered rows. For example, - // a 2x4 matrix can be transposed with: - // - // ; Original matrix - // m0 = - // m1 = - // - // ; Transposed matrix - // t0 = = shufflevector m0, m1 <0, 4, 2, 6> - // t1 = = shufflevector m0, m1 <1, 5, 3, 7> - // - // The above explanation places limitations on what valid transpose masks can - // look like. These limitations are defined by the checks below. - // - // 1. The number of elements in the mask must be a power of two. - if (!isPowerOf2_32(Mask.size())) - return false; - - // 2. The first element of the mask must be either a zero (for the - // even-numbered vector elements) or a one (for the odd-numbered vector - // elements). - if (Mask[0] != 0 && Mask[0] != 1) - return false; - - // 3. The difference between the first two elements must be equal to the - // number of elements in the mask. - if (Mask[1] - Mask[0] != (int)Mask.size()) - return false; - - // 4. The difference between consecutive even-numbered and odd-numbered - // elements must be equal to two. - for (int I = 2; I < (int)Mask.size(); ++I) - if (Mask[I] - Mask[I - 2] != 2) - return false; - - return true; -} - static TargetTransformInfo::OperandValueKind getOperandInfo(Value *V, TargetTransformInfo::OperandValueProperties &OpProps) { TargetTransformInfo::OperandValueKind OpInfo = @@ -1236,39 +1095,30 @@ } case Instruction::ShuffleVector: { const ShuffleVectorInst *Shuffle = cast(I); - Type *VecTypOp0 = Shuffle->getOperand(0)->getType(); - unsigned NumVecElems = VecTypOp0->getVectorNumElements(); - SmallVector Mask = Shuffle->getShuffleMask(); + // TODO: Identify and add costs for insert/extract subvector, etc. + if (Shuffle->changesLength()) + return -1; + + if (Shuffle->isIdentity()) + return 0; + + Type *Ty = Shuffle->getType(); + if (Shuffle->isReverse()) + return TTIImpl->getShuffleCost(SK_Reverse, Ty, 0, nullptr); + + if (Shuffle->isSelect()) + return TTIImpl->getShuffleCost(SK_Select, Ty, 0, nullptr); + + if (Shuffle->isTranspose()) + return TTIImpl->getShuffleCost(SK_Transpose, Ty, 0, nullptr); - if (NumVecElems == Mask.size()) { - if (isIdentityVectorMask(Mask)) - return 0; - - if (isReverseVectorMask(Mask)) - return TTIImpl->getShuffleCost(TargetTransformInfo::SK_Reverse, - VecTypOp0, 0, nullptr); - - if (isSelectVectorMask(Mask)) - return TTIImpl->getShuffleCost(TargetTransformInfo::SK_Select, - VecTypOp0, 0, nullptr); - - if (isTransposeVectorMask(Mask)) - return TTIImpl->getShuffleCost(TargetTransformInfo::SK_Transpose, - VecTypOp0, 0, nullptr); - - if (isZeroEltBroadcastVectorMask(Mask)) - return TTIImpl->getShuffleCost(TargetTransformInfo::SK_Broadcast, - VecTypOp0, 0, nullptr); - - if (isSingleSourceVectorMask(Mask)) - return TTIImpl->getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc, - VecTypOp0, 0, nullptr); + if (Shuffle->isZeroEltSplat()) + return TTIImpl->getShuffleCost(SK_Broadcast, Ty, 0, nullptr); - return TTIImpl->getShuffleCost(TargetTransformInfo::SK_PermuteTwoSrc, - VecTypOp0, 0, nullptr); - } + if (Shuffle->isSingleSource()) + return TTIImpl->getShuffleCost(SK_PermuteSingleSrc, Ty, 0, nullptr); - return -1; + return TTIImpl->getShuffleCost(SK_PermuteTwoSrc, Ty, 0, nullptr); } case Instruction::Call: if (const IntrinsicInst *II = dyn_cast(I)) { Index: lib/IR/Instructions.cpp =================================================================== --- lib/IR/Instructions.cpp +++ lib/IR/Instructions.cpp @@ -1658,7 +1658,7 @@ return false; } -int ShuffleVectorInst::getMaskValue(Constant *Mask, unsigned i) { +int ShuffleVectorInst::getMaskValue(const Constant *Mask, unsigned i) { assert(i < Mask->getType()->getVectorNumElements() && "Index out of range"); if (auto *CDS = dyn_cast(Mask)) return CDS->getElementAsInteger(i); @@ -1668,7 +1668,7 @@ return cast(C)->getZExtValue(); } -void ShuffleVectorInst::getShuffleMask(Constant *Mask, +void ShuffleVectorInst::getShuffleMask(const Constant *Mask, SmallVectorImpl &Result) { unsigned NumElts = Mask->getType()->getVectorNumElements(); @@ -1684,6 +1684,133 @@ } } +bool ShuffleVectorInst::isIdentityMask(ArrayRef Mask) { + bool UsesLHS = false; + bool UsesRHS = false; + for (int i = 0, NumElts = Mask.size(); i < NumElts; ++i) { + int MaskEltVal = Mask[i]; + if (MaskEltVal == -1) + continue; + bool IsLHS = MaskEltVal == i; + bool IsRHS = MaskEltVal == (i + NumElts); + if (!IsLHS && !IsRHS) + return false; + UsesLHS |= IsLHS; + UsesRHS |= IsRHS; + // Identity can only choose from one vector. + if (UsesLHS && UsesRHS) + return false; + } + assert((UsesLHS ^ UsesRHS) && "Should have selected from exactly 1 source"); + return true; +} + +bool ShuffleVectorInst::isSelectMask(ArrayRef Mask) { + bool UsesLHS = false; + bool UsesRHS = false; + for (int i = 0, NumElts = Mask.size(); i < NumElts; ++i) { + int MaskEltVal = Mask[i]; + if (MaskEltVal == -1) + continue; + bool IsLHS = MaskEltVal == i; + bool IsRHS = MaskEltVal == (i + NumElts); + if (!IsLHS && !IsRHS) + return false; + UsesLHS |= IsLHS; + UsesRHS |= IsRHS; + } + // Select must choose from both vectors. Identity is differentiated. + return UsesLHS && UsesRHS; +} + +bool ShuffleVectorInst::isReverseMask(ArrayRef Mask) { + bool UsesLHS = true; + bool UsesRHS = true; + int LastEltIndex = Mask.size() - 1; + for (int i = 0, NumElts = Mask.size(); i < NumElts; ++i) { + int MaskEltVal = Mask[i]; + if (MaskEltVal == -1) + continue; + bool IsLHS = MaskEltVal == (LastEltIndex - i); + bool IsRHS = MaskEltVal == (NumElts + LastEltIndex - i); + UsesLHS &= IsLHS; + UsesRHS &= IsRHS; + if (!UsesLHS && !UsesRHS) + return false; + } + assert((UsesLHS ^ UsesRHS) && "Should have selected from exactly 1 source"); + return true; +} + +bool ShuffleVectorInst::isSingleSourceMask(ArrayRef Mask) { + bool UsesLHS = false; + bool UsesRHS = false; + for (int i = 0, NumElts = Mask.size(); i < NumElts; ++i) { + int MaskEltVal = Mask[i]; + if (MaskEltVal == -1) + continue; + if (MaskEltVal >= NumElts) + UsesRHS = true; + else + UsesLHS = true; + if (UsesLHS && UsesRHS) + return false; + } + assert((UsesLHS ^ UsesRHS) && "Should have selected from exactly 1 source"); + return true; +} + +bool ShuffleVectorInst::isZeroEltSplatMask(ArrayRef Mask) { + bool UsesLHS = true; + bool UsesRHS = true; + for (int i = 0, NumElts = Mask.size(); i < NumElts; ++i) { + int MaskEltVal = Mask[i]; + if (MaskEltVal == -1) + continue; + UsesLHS &= (MaskEltVal == 0); + UsesRHS &= (MaskEltVal == NumElts); + if (!UsesLHS && !UsesRHS) + return false; + } + assert((UsesLHS ^ UsesRHS) && "Should have selected from exactly 1 source"); + return true; +} + +bool ShuffleVectorInst::isTransposeMask(ArrayRef Mask) { + // Example masks that will return true: + // v1 = + // v2 = + // trn1 = shufflevector v1, v2 <0, 4, 2, 6> = + // trn2 = shufflevector v1, v2 <1, 5, 3, 7> = + + // 1. The number of elements in the mask must be a power-of-2 and at least 2. + int NumElts = Mask.size(); + if (NumElts < 2 || !isPowerOf2_32(NumElts)) + return false; + + // 2. The first element of the mask must be either a 0 or a 1. + if (Mask[0] != 0 && Mask[0] != 1) + return false; + + // 3. The difference between the first 2 elements must be equal to the + // number of elements in the mask. + if ((Mask[1] - Mask[0]) != NumElts) + return false; + + // 4. The difference between consecutive even-numbered and odd-numbered + // elements must be equal to 2. + for (int i = 2; i < NumElts; ++i) { + int MaskEltVal = Mask[i]; + if (MaskEltVal == -1) + return false; + int MaskEltPrevVal = Mask[i - 2]; + if (MaskEltVal - MaskEltPrevVal != 2) + return false; + } + return true; +} + + //===----------------------------------------------------------------------===// // InsertValueInst Class //===----------------------------------------------------------------------===// Index: unittests/IR/InstructionsTest.cpp =================================================================== --- unittests/IR/InstructionsTest.cpp +++ unittests/IR/InstructionsTest.cpp @@ -747,5 +747,87 @@ EXPECT_THAT(Indices, testing::ContainerEq(ArrayRef({-1, 4, 3}))); } +TEST(InstructionsTest, ShuffleMaskQueries) { + // Create the elements for various constant vectors. + LLVMContext Ctx; + Type *Int32Ty = Type::getInt32Ty(Ctx); + Constant *CU = UndefValue::get(Int32Ty); + Constant *C0 = ConstantInt::get(Int32Ty, 0); + Constant *C1 = ConstantInt::get(Int32Ty, 1); + Constant *C2 = ConstantInt::get(Int32Ty, 2); + Constant *C3 = ConstantInt::get(Int32Ty, 3); + Constant *C4 = ConstantInt::get(Int32Ty, 4); + Constant *C5 = ConstantInt::get(Int32Ty, 5); + Constant *C6 = ConstantInt::get(Int32Ty, 6); + Constant *C7 = ConstantInt::get(Int32Ty, 7); + + Constant *Identity = ConstantVector::get({C0, CU, C2, C3, C4}); + EXPECT_TRUE(ShuffleVectorInst::isIdentityMask(Identity)); + EXPECT_FALSE(ShuffleVectorInst::isSelectMask(Identity)); // identity is distinguished from select + EXPECT_FALSE(ShuffleVectorInst::isReverseMask(Identity)); + EXPECT_TRUE(ShuffleVectorInst::isSingleSourceMask(Identity)); // identity is always single source + EXPECT_FALSE(ShuffleVectorInst::isZeroEltSplatMask(Identity)); + EXPECT_FALSE(ShuffleVectorInst::isTransposeMask(Identity)); + + Constant *Select = ConstantVector::get({CU, C1, C5}); + EXPECT_FALSE(ShuffleVectorInst::isIdentityMask(Select)); + EXPECT_TRUE(ShuffleVectorInst::isSelectMask(Select)); + EXPECT_FALSE(ShuffleVectorInst::isReverseMask(Select)); + EXPECT_FALSE(ShuffleVectorInst::isSingleSourceMask(Select)); + EXPECT_FALSE(ShuffleVectorInst::isZeroEltSplatMask(Select)); + EXPECT_FALSE(ShuffleVectorInst::isTransposeMask(Select)); + + Constant *Reverse = ConstantVector::get({C3, C2, C1, CU}); + EXPECT_FALSE(ShuffleVectorInst::isIdentityMask(Reverse)); + EXPECT_FALSE(ShuffleVectorInst::isSelectMask(Reverse)); + EXPECT_TRUE(ShuffleVectorInst::isReverseMask(Reverse)); + EXPECT_TRUE(ShuffleVectorInst::isSingleSourceMask(Reverse)); // reverse is always single source + EXPECT_FALSE(ShuffleVectorInst::isZeroEltSplatMask(Reverse)); + EXPECT_FALSE(ShuffleVectorInst::isTransposeMask(Reverse)); + + Constant *SingleSource = ConstantVector::get({C2, C2, C0, CU}); + EXPECT_FALSE(ShuffleVectorInst::isIdentityMask(SingleSource)); + EXPECT_FALSE(ShuffleVectorInst::isSelectMask(SingleSource)); + EXPECT_FALSE(ShuffleVectorInst::isReverseMask(SingleSource)); + EXPECT_TRUE(ShuffleVectorInst::isSingleSourceMask(SingleSource)); + EXPECT_FALSE(ShuffleVectorInst::isZeroEltSplatMask(SingleSource)); + EXPECT_FALSE(ShuffleVectorInst::isTransposeMask(SingleSource)); + + Constant *ZeroEltSplat = ConstantVector::get({C0, C0, CU, C0}); + EXPECT_FALSE(ShuffleVectorInst::isIdentityMask(ZeroEltSplat)); + EXPECT_FALSE(ShuffleVectorInst::isSelectMask(ZeroEltSplat)); + EXPECT_FALSE(ShuffleVectorInst::isReverseMask(ZeroEltSplat)); + EXPECT_TRUE(ShuffleVectorInst::isSingleSourceMask(ZeroEltSplat)); // 0-splat is always single source + EXPECT_TRUE(ShuffleVectorInst::isZeroEltSplatMask(ZeroEltSplat)); + EXPECT_FALSE(ShuffleVectorInst::isTransposeMask(ZeroEltSplat)); + + Constant *Transpose = ConstantVector::get({C0, C4, C2, C6}); + EXPECT_FALSE(ShuffleVectorInst::isIdentityMask(Transpose)); + EXPECT_FALSE(ShuffleVectorInst::isSelectMask(Transpose)); + EXPECT_FALSE(ShuffleVectorInst::isReverseMask(Transpose)); + EXPECT_FALSE(ShuffleVectorInst::isSingleSourceMask(Transpose)); + EXPECT_FALSE(ShuffleVectorInst::isZeroEltSplatMask(Transpose)); + EXPECT_TRUE(ShuffleVectorInst::isTransposeMask(Transpose)); + + // More tests to make sure the logic is/stays correct... + EXPECT_TRUE(ShuffleVectorInst::isIdentityMask(ConstantVector::get({CU, C1, CU, C3}))); + EXPECT_TRUE(ShuffleVectorInst::isIdentityMask(ConstantVector::get({C4, CU, C6, CU}))); + + EXPECT_TRUE(ShuffleVectorInst::isSelectMask(ConstantVector::get({C4, C1, C6, CU}))); + EXPECT_TRUE(ShuffleVectorInst::isSelectMask(ConstantVector::get({CU, C1, C6, C3}))); + + EXPECT_TRUE(ShuffleVectorInst::isReverseMask(ConstantVector::get({C7, C6, CU, C4}))); + EXPECT_TRUE(ShuffleVectorInst::isReverseMask(ConstantVector::get({C3, CU, C1, CU}))); + + EXPECT_TRUE(ShuffleVectorInst::isSingleSourceMask(ConstantVector::get({C7, C5, CU, C7}))); + EXPECT_TRUE(ShuffleVectorInst::isSingleSourceMask(ConstantVector::get({C3, C0, CU, C3}))); + + EXPECT_TRUE(ShuffleVectorInst::isZeroEltSplatMask(ConstantVector::get({C4, CU, CU, C4}))); + EXPECT_TRUE(ShuffleVectorInst::isZeroEltSplatMask(ConstantVector::get({CU, C0, CU, C0}))); + + EXPECT_TRUE(ShuffleVectorInst::isTransposeMask(ConstantVector::get({C1, C5, C3, C7}))); + EXPECT_TRUE(ShuffleVectorInst::isTransposeMask(ConstantVector::get({C1, C3}))); +} + } // end anonymous namespace } // end namespace llvm