Index: llvm/include/llvm/Analysis/VectorUtils.h =================================================================== --- llvm/include/llvm/Analysis/VectorUtils.h +++ llvm/include/llvm/Analysis/VectorUtils.h @@ -328,6 +328,40 @@ /// not limited by finding a scalar source value to a splatted vector. bool isSplatValue(const Value *V, int Index = -1, unsigned Depth = 0); +/// Scale a shuffle or target shuffle mask, replacing each mask index with the +/// scaled sequential indices for an equivalent mask of narrowed elements. +/// Mask elements that are less than 0 (sentinel values) are repeated in the +/// output mask. +/// +/// Example with Scale = 4: +/// <4 x i32> <3, 2, 0, -1> --> +/// <16 x i8> <12, 13, 14, 15, 8, 9, 10, 11, 0, 1, 2, 3, -1, -1, -1, -1> +/// +/// This is the reverse process of "canWidenShuffleElements", but can always +/// succeed. +template +void scaleShuffleMask(size_t Scale, ArrayRef Mask, + SmallVectorImpl &ScaledMask) { + assert(Scale > 0 && "Unexpected scaling factor"); + size_t NumElts = Mask.size(); + ScaledMask.assign(NumElts * Scale, -1); + + for (size_t i = 0; i != NumElts; ++i) { + int M = Mask[i]; + + // Repeat sentinel values in every mask element. + if (M < 0) { + for (size_t s = 0; s != Scale; ++s) + ScaledMask[(Scale * i) + s] = M; + continue; + } + + // Scale mask element and increment across each mask element. + for (size_t s = 0; s != Scale; ++s) + ScaledMask[(Scale * i) + s] = (Scale * M) + s; + } +} + /// Compute a map of integer instructions to their minimum legal type /// size. /// Index: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -19755,16 +19755,6 @@ if (N0.getOpcode() == ISD::BITCAST && N0.hasOneUse() && N1.isUndef() && Level < AfterLegalizeVectorOps && TLI.isTypeLegal(VT)) { - auto ScaleShuffleMask = [](ArrayRef Mask, int Scale) { - if (Scale == 1) - return SmallVector(Mask.begin(), Mask.end()); - - SmallVector NewMask; - for (int M : Mask) - for (int s = 0; s != Scale; ++s) - NewMask.push_back(M < 0 ? -1 : Scale * M + s); - return NewMask; - }; SDValue BC0 = peekThroughOneUseBitcasts(N0); if (BC0.getOpcode() == ISD::VECTOR_SHUFFLE && BC0.hasOneUse()) { @@ -19784,10 +19774,10 @@ // Scale the shuffle masks to the smaller scalar type. ShuffleVectorSDNode *InnerSVN = cast(BC0); - SmallVector InnerMask = - ScaleShuffleMask(InnerSVN->getMask(), InnerScale); - SmallVector OuterMask = - ScaleShuffleMask(SVN->getMask(), OuterScale); + SmallVector InnerMask; + SmallVector OuterMask; + scaleShuffleMask(InnerScale, InnerSVN->getMask(), InnerMask); + scaleShuffleMask(OuterScale, SVN->getMask(), OuterMask); // Merge the shuffle masks. SmallVector NewMask; Index: llvm/lib/Target/X86/X86ISelLowering.h =================================================================== --- llvm/lib/Target/X86/X86ISelLowering.h +++ llvm/lib/Target/X86/X86ISelLowering.h @@ -1595,32 +1595,6 @@ } } - /// Helper function to scale a shuffle or target shuffle mask, replacing each - /// mask index with the scaled sequential indices for an equivalent narrowed - /// mask. This is the reverse process to canWidenShuffleElements, but can - /// always succeed. - template - void scaleShuffleMask(size_t Scale, ArrayRef Mask, - SmallVectorImpl &ScaledMask) { - assert(0 < Scale && "Unexpected scaling factor"); - size_t NumElts = Mask.size(); - ScaledMask.assign(NumElts * Scale, -1); - - for (size_t i = 0; i != NumElts; ++i) { - int M = Mask[i]; - - // Repeat sentinel values in every mask element. - if (M < 0) { - for (size_t s = 0; s != Scale; ++s) - ScaledMask[(Scale * i) + s] = M; - continue; - } - - // Scale mask element and increment across each mask element. - for (size_t s = 0; s != Scale; ++s) - ScaledMask[(Scale * i) + s] = (Scale * M) + s; - } - } } // end namespace llvm #endif // LLVM_LIB_TARGET_X86_X86ISELLOWERING_H Index: llvm/unittests/Analysis/VectorUtilsTest.cpp =================================================================== --- llvm/unittests/Analysis/VectorUtilsTest.cpp +++ llvm/unittests/Analysis/VectorUtilsTest.cpp @@ -98,6 +98,12 @@ EXPECT_FALSE(isSplatValue(SplatWithUndefC)); } +TEST_F(BasicTest, scaleShuffleMask) { + SmallVector ScaledMask; + scaleShuffleMask(4, {3,2,0,-1}, ScaledMask); + EXPECT_EQ(makeArrayRef(ScaledMask), makeArrayRef({12,13,14,15,8,9,10,11,0,1,2,3,-1,-1,-1,-1})); +} + TEST_F(BasicTest, getSplatIndex) { EXPECT_EQ(getSplatIndex({0,0,0}), 0); EXPECT_EQ(getSplatIndex({1,0,0}), -1); // no splat