[IR] move shuffle mask queries from TTI to ShuffleVectorInst

The optimizer is getting smarter (eg, D47986) about differentiating shuffles 
based on its mask values, so we should make queries on the mask constant 
operand generally available to avoid code duplication.

We'll probably use this soon in the vectorizers and instcombine (D48023 and 
https://bugs.llvm.org/show_bug.cgi?id=37806).

We might clean up TTI a bit more once all of its current 'SK_*' options are 
covered.

Differential Revision: https://reviews.llvm.org/D48236

llvm-svn: 335067
This commit is contained in:
Sanjay Patel 2018-06-19 18:44:00 +00:00
parent 2054afa728
commit 39c6758e06
4 changed files with 377 additions and 172 deletions

View File

@ -2426,7 +2426,7 @@ public:
/// 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 @@ public:
/// 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.
@ -2450,6 +2451,176 @@ public:
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,

View File

@ -630,147 +630,6 @@ int TargetTransformInfo::getInstructionLatency(const Instruction *I) const {
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 =
@ -1236,39 +1095,30 @@ int TargetTransformInfo::getInstructionThroughput(const Instruction *I) const {
}
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();
// TODO: Identify and add costs for insert/extract subvector, etc.
if (Shuffle->changesLength())
return -1;
if (Shuffle->isIdentity())
return 0;
if (NumVecElems == Mask.size()) {
if (isIdentityVectorMask(Mask))
return 0;
Type *Ty = Shuffle->getType();
if (Shuffle->isReverse())
return TTIImpl->getShuffleCost(SK_Reverse, Ty, 0, nullptr);
if (isReverseVectorMask(Mask))
return TTIImpl->getShuffleCost(TargetTransformInfo::SK_Reverse,
VecTypOp0, 0, nullptr);
if (Shuffle->isSelect())
return TTIImpl->getShuffleCost(SK_Select, Ty, 0, nullptr);
if (isSelectVectorMask(Mask))
return TTIImpl->getShuffleCost(TargetTransformInfo::SK_Select,
VecTypOp0, 0, nullptr);
if (Shuffle->isTranspose())
return TTIImpl->getShuffleCost(SK_Transpose, Ty, 0, nullptr);
if (isTransposeVectorMask(Mask))
return TTIImpl->getShuffleCost(TargetTransformInfo::SK_Transpose,
VecTypOp0, 0, nullptr);
if (Shuffle->isZeroEltSplat())
return TTIImpl->getShuffleCost(SK_Broadcast, Ty, 0, nullptr);
if (isZeroEltBroadcastVectorMask(Mask))
return TTIImpl->getShuffleCost(TargetTransformInfo::SK_Broadcast,
VecTypOp0, 0, nullptr);
if (Shuffle->isSingleSource())
return TTIImpl->getShuffleCost(SK_PermuteSingleSrc, Ty, 0, nullptr);
if (isSingleSourceVectorMask(Mask))
return TTIImpl->getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc,
VecTypOp0, 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)) {

View File

@ -1658,7 +1658,7 @@ bool ShuffleVectorInst::isValidOperands(const Value *V1, const Value *V2,
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);
@ -1668,7 +1668,7 @@ int ShuffleVectorInst::getMaskValue(Constant *Mask, unsigned 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();
@ -1684,6 +1684,108 @@ void ShuffleVectorInst::getShuffleMask(Constant *Mask,
}
}
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
//===----------------------------------------------------------------------===//

View File

@ -747,5 +747,87 @@ TEST(InstructionsTest, CommuteShuffleMask) {
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