/// 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.
/// 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<int> &Result);
+ static void getShuffleMask(const Constant *Mask,
+ SmallVectorImpl<int> &Result);
/// Return the mask for this instruction as a vector of integers. Undefined
/// elements of the mask are returned as -1.
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.
+ /// Example: <7,5,undef,7>
+ /// This assumes that vector operands are the same length as the mask.
+ static bool isSingleSourceMask(ArrayRef<int> Mask);
+ static bool isSingleSourceMask(const Constant *Mask) {
+ assert(Mask->getType()->isVectorTy() && "Shuffle needs vector constant.");
+ SmallVector<int, 16> 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>
+ /// TODO: Optionally allow length-changing shuffles.
+ bool isSingleSource() const {
+ return !changesLength() && isSingleSourceMask(getMask());
+ }
+
+ /// 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: <undef,undef,2,3>
+ static bool isIdentityMask(ArrayRef<int> Mask);
+ static bool isIdentityMask(const Constant *Mask) {
+ assert(Mask->getType()->isVectorTy() && "Shuffle needs vector constant.");
+ SmallVector<int, 16> 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>
+ /// TODO: Optionally allow length-changing shuffles.
+ 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,undef>
+ /// 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<int> Mask);
+ static bool isSelectMask(const Constant *Mask) {
+ assert(Mask->getType()->isVectorTy() && "Shuffle needs vector constant.");
+ SmallVector<int, 16> 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, <undef,1,6,3>
+ /// 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.
+ /// TODO: Optionally allow length-changing shuffles.
+ 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,undef,4>
+ /// This assumes that vector operands are the same length as the mask.
+ static bool isReverseMask(ArrayRef<int> Mask);
+ static bool isReverseMask(const Constant *Mask) {
+ assert(Mask->getType()->isVectorTy() && "Shuffle needs vector constant.");
+ SmallVector<int, 16> 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>
+ /// TODO: Optionally allow length-changing shuffles.
+ bool isReverse() const {
+ return !changesLength() && isReverseMask(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,undef,undef,4>
+ /// This assumes that vector operands are the same length as the mask.
+ static bool isZeroEltSplatMask(ArrayRef<int> Mask);
+ static bool isZeroEltSplatMask(const Constant *Mask) {
+ assert(Mask->getType()->isVectorTy() && "Shuffle needs vector constant.");
+ SmallVector<int, 16> 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, <undef,0,undef,0>
+ /// TODO: Optionally allow length-changing shuffles.
+ /// TODO: Optionally allow splats from other elements.
+ 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 = <a, b>
+ /// m1 = <c, d>
+ ///
+ /// ; Transposed matrix
+ /// t0 = <a, c> = shufflevector m0, m1, <0, 2>
+ /// t1 = <b, d> = 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 = <a, b, c, d>
+ /// m1 = <e, f, g, h>
+ ///
+ /// ; Transposed matrix
+ /// t0 = <a, e, c, g> = shufflevector m0, m1 <0, 4, 2, 6>
+ /// t1 = <b, f, d, h> = shufflevector m0, m1 <1, 5, 3, 7>
+ static bool isTransposeMask(ArrayRef<int> Mask);
+ static bool isTransposeMask(const Constant *Mask) {
+ assert(Mask->getType()->isVectorTy() && "Shuffle needs vector constant.");
+ SmallVector<int, 16> 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<int> Mask,
return TTIImpl->getInstructionLatency(I);
}
-static bool isReverseVectorMask(ArrayRef<int> 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<int> 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<int> 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<int> 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<int> 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<int> 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 = <a, b>
- // m1 = <c, d>
- //
- // ; Transposed matrix
- // t0 = <a, c> = shufflevector m0, m1, <0, 2>
- // t1 = <b, d> = 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 = <a, b, c, d>
- // m1 = <e, f, g, h>
- //
- // ; Transposed matrix
- // t0 = <a, e, c, g> = shufflevector m0, m1 <0, 4, 2, 6>
- // t1 = <b, f, d, h> = 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 =
}
case Instruction::ShuffleVector: {
const ShuffleVectorInst *Shuffle = cast<ShuffleVectorInst>(I);
- Type *VecTypOp0 = Shuffle->getOperand(0)->getType();
- unsigned NumVecElems = VecTypOp0->getVectorNumElements();
- SmallVector<int, 16> Mask = Shuffle->getShuffleMask();
-
- if (NumVecElems == Mask.size()) {
- if (isIdentityVectorMask(Mask))
- return 0;
+ // TODO: Identify and add costs for insert/extract subvector, etc.
+ if (Shuffle->changesLength())
+ return -1;
+
+ if (Shuffle->isIdentity())
+ return 0;
- if (isReverseVectorMask(Mask))
- return TTIImpl->getShuffleCost(TargetTransformInfo::SK_Reverse,
- VecTypOp0, 0, nullptr);
+ Type *Ty = Shuffle->getType();
+ if (Shuffle->isReverse())
+ return TTIImpl->getShuffleCost(SK_Reverse, Ty, 0, nullptr);
- if (isSelectVectorMask(Mask))
- return TTIImpl->getShuffleCost(TargetTransformInfo::SK_Select,
- VecTypOp0, 0, nullptr);
+ if (Shuffle->isSelect())
+ return TTIImpl->getShuffleCost(SK_Select, Ty, 0, nullptr);
- if (isTransposeVectorMask(Mask))
- return TTIImpl->getShuffleCost(TargetTransformInfo::SK_Transpose,
- VecTypOp0, 0, nullptr);
+ if (Shuffle->isTranspose())
+ return TTIImpl->getShuffleCost(SK_Transpose, Ty, 0, nullptr);
- if (isZeroEltBroadcastVectorMask(Mask))
- return TTIImpl->getShuffleCost(TargetTransformInfo::SK_Broadcast,
- VecTypOp0, 0, nullptr);
+ if (Shuffle->isZeroEltSplat())
+ return TTIImpl->getShuffleCost(SK_Broadcast, Ty, 0, nullptr);
- if (isSingleSourceVectorMask(Mask))
- return TTIImpl->getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc,
- VecTypOp0, 0, nullptr);
+ if (Shuffle->isSingleSource())
+ return TTIImpl->getShuffleCost(SK_PermuteSingleSrc, Ty, 0, nullptr);
- return TTIImpl->getShuffleCost(TargetTransformInfo::SK_PermuteTwoSrc,
- VecTypOp0, 0, nullptr);
- }
-
- return -1;
+ return TTIImpl->getShuffleCost(SK_PermuteTwoSrc, Ty, 0, nullptr);
}
case Instruction::Call:
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
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<ConstantDataSequential>(Mask))
return CDS->getElementAsInteger(i);
return cast<ConstantInt>(C)->getZExtValue();
}
-void ShuffleVectorInst::getShuffleMask(Constant *Mask,
+void ShuffleVectorInst::getShuffleMask(const Constant *Mask,
SmallVectorImpl<int> &Result) {
unsigned NumElts = Mask->getType()->getVectorNumElements();
}
}
+bool ShuffleVectorInst::isSingleSourceMask(ArrayRef<int> Mask) {
+ assert(!Mask.empty() && "Shuffle mask must contain elements");
+ bool UsesLHS = false;
+ bool UsesRHS = false;
+ for (int i = 0, NumElts = Mask.size(); i < NumElts; ++i) {
+ if (Mask[i] == -1)
+ continue;
+ assert(Mask[i] >= 0 && Mask[i] < (NumElts * 2) &&
+ "Out-of-bounds shuffle mask element");
+ UsesLHS |= (Mask[i] < NumElts);
+ UsesRHS |= (Mask[i] >= NumElts);
+ if (UsesLHS && UsesRHS)
+ return false;
+ }
+ assert((UsesLHS ^ UsesRHS) && "Should have selected from exactly 1 source");
+ return true;
+}
+
+bool ShuffleVectorInst::isIdentityMask(ArrayRef<int> Mask) {
+ if (!isSingleSourceMask(Mask))
+ return false;
+ for (int i = 0, NumElts = Mask.size(); i < NumElts; ++i) {
+ if (Mask[i] == -1)
+ continue;
+ if (Mask[i] != i && Mask[i] != (NumElts + i))
+ return false;
+ }
+ return true;
+}
+
+bool ShuffleVectorInst::isReverseMask(ArrayRef<int> Mask) {
+ if (!isSingleSourceMask(Mask))
+ return false;
+ for (int i = 0, NumElts = Mask.size(); i < NumElts; ++i) {
+ if (Mask[i] == -1)
+ continue;
+ if (Mask[i] != (NumElts - 1 - i) && Mask[i] != (NumElts + NumElts - 1 - i))
+ return false;
+ }
+ return true;
+}
+
+bool ShuffleVectorInst::isZeroEltSplatMask(ArrayRef<int> Mask) {
+ if (!isSingleSourceMask(Mask))
+ return false;
+ for (int i = 0, NumElts = Mask.size(); i < NumElts; ++i) {
+ if (Mask[i] == -1)
+ continue;
+ if (Mask[i] != 0 && Mask[i] != NumElts)
+ return false;
+ }
+ return true;
+}
+
+bool ShuffleVectorInst::isSelectMask(ArrayRef<int> Mask) {
+ // Select is differentiated from identity. It requires using both sources.
+ if (isSingleSourceMask(Mask))
+ return false;
+ for (int i = 0, NumElts = Mask.size(); i < NumElts; ++i) {
+ if (Mask[i] == -1)
+ continue;
+ if (Mask[i] != i && Mask[i] != (NumElts + i))
+ return false;
+ }
+ return true;
+}
+
+bool ShuffleVectorInst::isTransposeMask(ArrayRef<int> Mask) {
+ // Example masks that will return true:
+ // v1 = <a, b, c, d>
+ // v2 = <e, f, g, h>
+ // trn1 = shufflevector v1, v2 <0, 4, 2, 6> = <a, e, c, g>
+ // trn2 = shufflevector v1, v2 <1, 5, 3, 7> = <b, f, d, h>
+
+ // 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
//===----------------------------------------------------------------------===//
EXPECT_THAT(Indices, testing::ContainerEq(ArrayRef<int>({-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