diff --git a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp index 8b353abb949232..8a5ddbbdc3b279 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp @@ -1544,8 +1544,17 @@ static Instruction *foldTruncInsElt(InsertElementInst &InsElt, bool IsBigEndian, // The insert is to the LSB end of the vector (depends on endian). // That's all we need. } else { - // TODO: Look through a shift-right and translate the insert index. - return nullptr; + // If not, we must match a right-shift to translate the insert index. + uint64_t ShiftC; + if (!match(T, m_OneUse(m_LShr(m_Value(X), m_ConstantInt(ShiftC))))) + return nullptr; + + // Check the shift amount to see if this can be folded to an identity + // shuffle (assuming we are shuffling with an undef base vector). + // Big endian has MSB at vector index 0, so the insert index is flipped. + if (ShiftC != (IsBigEndian ? (NumEltsInScalar - 1 - IndexC) * VecEltWidth + : IndexC * VecEltWidth)) + return nullptr; } // Bitcast the scalar to a vector type with the destination element type. diff --git a/llvm/test/Transforms/InstCombine/insert-trunc.ll b/llvm/test/Transforms/InstCombine/insert-trunc.ll index 20922f97648b9f..07b810009228db 100644 --- a/llvm/test/Transforms/InstCombine/insert-trunc.ll +++ b/llvm/test/Transforms/InstCombine/insert-trunc.ll @@ -143,11 +143,16 @@ define <4 x i8> @low_index_shorter_length_poison_basevec_extra_use(i64 %x) { } define <4 x i16> @lshr_same_length_poison_basevec_le(i64 %x) { -; ALL-LABEL: @lshr_same_length_poison_basevec_le( -; ALL-NEXT: [[S:%.*]] = lshr i64 [[X:%.*]], 32 -; ALL-NEXT: [[T:%.*]] = trunc i64 [[S]] to i16 -; ALL-NEXT: [[R:%.*]] = insertelement <4 x i16> poison, i16 [[T]], i64 2 -; ALL-NEXT: ret <4 x i16> [[R]] +; BE-LABEL: @lshr_same_length_poison_basevec_le( +; BE-NEXT: [[S:%.*]] = lshr i64 [[X:%.*]], 32 +; BE-NEXT: [[T:%.*]] = trunc i64 [[S]] to i16 +; BE-NEXT: [[R:%.*]] = insertelement <4 x i16> poison, i16 [[T]], i64 2 +; BE-NEXT: ret <4 x i16> [[R]] +; +; LE-LABEL: @lshr_same_length_poison_basevec_le( +; LE-NEXT: [[VEC_X:%.*]] = bitcast i64 [[X:%.*]] to <4 x i16> +; LE-NEXT: [[R:%.*]] = shufflevector <4 x i16> [[VEC_X]], <4 x i16> poison, <4 x i32> +; LE-NEXT: ret <4 x i16> [[R]] ; %s = lshr i64 %x, 32 %t = trunc i64 %s to i16 @@ -156,11 +161,16 @@ define <4 x i16> @lshr_same_length_poison_basevec_le(i64 %x) { } define <4 x i16> @lshr_same_length_poison_basevec_be(i64 %x) { -; ALL-LABEL: @lshr_same_length_poison_basevec_be( -; ALL-NEXT: [[S:%.*]] = lshr i64 [[X:%.*]], 32 -; ALL-NEXT: [[T:%.*]] = trunc i64 [[S]] to i16 -; ALL-NEXT: [[R:%.*]] = insertelement <4 x i16> poison, i16 [[T]], i64 1 -; ALL-NEXT: ret <4 x i16> [[R]] +; BE-LABEL: @lshr_same_length_poison_basevec_be( +; BE-NEXT: [[VEC_X:%.*]] = bitcast i64 [[X:%.*]] to <4 x i16> +; BE-NEXT: [[R:%.*]] = shufflevector <4 x i16> [[VEC_X]], <4 x i16> poison, <4 x i32> +; BE-NEXT: ret <4 x i16> [[R]] +; +; LE-LABEL: @lshr_same_length_poison_basevec_be( +; LE-NEXT: [[S:%.*]] = lshr i64 [[X:%.*]], 32 +; LE-NEXT: [[T:%.*]] = trunc i64 [[S]] to i16 +; LE-NEXT: [[R:%.*]] = insertelement <4 x i16> poison, i16 [[T]], i64 1 +; LE-NEXT: ret <4 x i16> [[R]] ; %s = lshr i64 %x, 32 %t = trunc i64 %s to i16 @@ -170,9 +180,8 @@ define <4 x i16> @lshr_same_length_poison_basevec_be(i64 %x) { define <4 x i16> @lshr_same_length_poison_basevec_both_endian(i64 %x) { ; BE-LABEL: @lshr_same_length_poison_basevec_both_endian( -; BE-NEXT: [[S:%.*]] = lshr i64 [[X:%.*]], 48 -; BE-NEXT: [[T:%.*]] = trunc i64 [[S]] to i16 -; BE-NEXT: [[R:%.*]] = insertelement <4 x i16> poison, i16 [[T]], i64 0 +; BE-NEXT: [[VEC_X:%.*]] = bitcast i64 [[X:%.*]] to <4 x i16> +; BE-NEXT: [[R:%.*]] = shufflevector <4 x i16> [[VEC_X]], <4 x i16> poison, <4 x i32> ; BE-NEXT: ret <4 x i16> [[R]] ; ; LE-LABEL: @lshr_same_length_poison_basevec_both_endian( @@ -208,9 +217,8 @@ define <8 x i16> @lshr_longer_length_poison_basevec_le(i64 %x) { ; BE-NEXT: ret <8 x i16> [[R]] ; ; LE-LABEL: @lshr_longer_length_poison_basevec_le( -; LE-NEXT: [[S:%.*]] = lshr i64 [[X:%.*]], 48 -; LE-NEXT: [[T:%.*]] = trunc i64 [[S]] to i16 -; LE-NEXT: [[R:%.*]] = insertelement <8 x i16> poison, i16 [[T]], i64 3 +; LE-NEXT: [[VEC_X:%.*]] = bitcast i64 [[X:%.*]] to <4 x i16> +; LE-NEXT: [[R:%.*]] = shufflevector <4 x i16> [[VEC_X]], <4 x i16> poison, <8 x i32> ; LE-NEXT: ret <8 x i16> [[R]] ; %s = lshr i64 %x, 48 @@ -220,11 +228,16 @@ define <8 x i16> @lshr_longer_length_poison_basevec_le(i64 %x) { } define <8 x i16> @lshr_longer_length_poison_basevec_be(i64 %x) { -; ALL-LABEL: @lshr_longer_length_poison_basevec_be( -; ALL-NEXT: [[S:%.*]] = lshr i64 [[X:%.*]], 32 -; ALL-NEXT: [[T:%.*]] = trunc i64 [[S]] to i16 -; ALL-NEXT: [[R:%.*]] = insertelement <8 x i16> poison, i16 [[T]], i64 1 -; ALL-NEXT: ret <8 x i16> [[R]] +; BE-LABEL: @lshr_longer_length_poison_basevec_be( +; BE-NEXT: [[VEC_X:%.*]] = bitcast i64 [[X:%.*]] to <4 x i16> +; BE-NEXT: [[R:%.*]] = shufflevector <4 x i16> [[VEC_X]], <4 x i16> poison, <8 x i32> +; BE-NEXT: ret <8 x i16> [[R]] +; +; LE-LABEL: @lshr_longer_length_poison_basevec_be( +; LE-NEXT: [[S:%.*]] = lshr i64 [[X:%.*]], 32 +; LE-NEXT: [[T:%.*]] = trunc i64 [[S]] to i16 +; LE-NEXT: [[R:%.*]] = insertelement <8 x i16> poison, i16 [[T]], i64 1 +; LE-NEXT: ret <8 x i16> [[R]] ; %s = lshr i64 %x, 32 %t = trunc i64 %s to i16 @@ -246,11 +259,16 @@ define <8 x i16> @lshr_wrong_index_longer_length_poison_basevec(i64 %x) { } define <2 x i16> @lshr_shorter_length_poison_basevec_le(i64 %x) { -; ALL-LABEL: @lshr_shorter_length_poison_basevec_le( -; ALL-NEXT: [[S:%.*]] = lshr i64 [[X:%.*]], 16 -; ALL-NEXT: [[T:%.*]] = trunc i64 [[S]] to i16 -; ALL-NEXT: [[R:%.*]] = insertelement <2 x i16> poison, i16 [[T]], i64 1 -; ALL-NEXT: ret <2 x i16> [[R]] +; BE-LABEL: @lshr_shorter_length_poison_basevec_le( +; BE-NEXT: [[S:%.*]] = lshr i64 [[X:%.*]], 16 +; BE-NEXT: [[T:%.*]] = trunc i64 [[S]] to i16 +; BE-NEXT: [[R:%.*]] = insertelement <2 x i16> poison, i16 [[T]], i64 1 +; BE-NEXT: ret <2 x i16> [[R]] +; +; LE-LABEL: @lshr_shorter_length_poison_basevec_le( +; LE-NEXT: [[VEC_X:%.*]] = bitcast i64 [[X:%.*]] to <4 x i16> +; LE-NEXT: [[R:%.*]] = shufflevector <4 x i16> [[VEC_X]], <4 x i16> poison, <2 x i32> +; LE-NEXT: ret <2 x i16> [[R]] ; %s = lshr i64 %x, 16 %t = trunc i64 %s to i16 @@ -259,11 +277,16 @@ define <2 x i16> @lshr_shorter_length_poison_basevec_le(i64 %x) { } define <4 x i8> @lshr_shorter_length_poison_basevec_be(i64 %x) { -; ALL-LABEL: @lshr_shorter_length_poison_basevec_be( -; ALL-NEXT: [[S:%.*]] = lshr i64 [[X:%.*]], 40 -; ALL-NEXT: [[T:%.*]] = trunc i64 [[S]] to i8 -; ALL-NEXT: [[R:%.*]] = insertelement <4 x i8> poison, i8 [[T]], i64 2 -; ALL-NEXT: ret <4 x i8> [[R]] +; BE-LABEL: @lshr_shorter_length_poison_basevec_be( +; BE-NEXT: [[VEC_X:%.*]] = bitcast i64 [[X:%.*]] to <8 x i8> +; BE-NEXT: [[R:%.*]] = shufflevector <8 x i8> [[VEC_X]], <8 x i8> poison, <4 x i32> +; BE-NEXT: ret <4 x i8> [[R]] +; +; LE-LABEL: @lshr_shorter_length_poison_basevec_be( +; LE-NEXT: [[S:%.*]] = lshr i64 [[X:%.*]], 40 +; LE-NEXT: [[T:%.*]] = trunc i64 [[S]] to i8 +; LE-NEXT: [[R:%.*]] = insertelement <4 x i8> poison, i8 [[T]], i64 2 +; LE-NEXT: ret <4 x i8> [[R]] ; %s = lshr i64 %x, 40 %t = trunc i64 %s to i8