[llvm] [InstCombine]Fold bitcast shuffle ashr v2i64 (PR #206717)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 30 05:13:39 PDT 2026
https://github.com/AntonyCJ30 created https://github.com/llvm/llvm-project/pull/206717
This patch folds the X86 pre-AVX512 64-bit vector arithmetic shift emulation pattern (`bitcast(shuffle(ashr(bitcast(X))))`) into a single `ashr` instruction. The transformation is implemented in InstCombine, the middle-end optimization pass, so it benefits all backends (X86, ARM, RISC-V, etc.) by cleaning up the IR before it reaches any target-specific lowering.
Alive2 proof: https://alive2.llvm.org/ce/z/LM1Eu1
Fixes: #125189
>From 3ef132111999bb695c935dbca49c29d9e39aced9 Mon Sep 17 00:00:00 2001
From: AntonyCJ30 <cj6186609 at gmail@gmail.com>
Date: Tue, 30 Jun 2026 17:10:41 +0530
Subject: [PATCH 1/2] [InstCombine] Add tests for X86 v2i64 ashr emulation
pattern (PR#125189)
---
.../InstCombine/compute-sign-bits-bitcast.ll | 157 ++++++++++++++++++
1 file changed, 157 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/compute-sign-bits-bitcast.ll b/llvm/test/Transforms/InstCombine/compute-sign-bits-bitcast.ll
index 1da304f64a1ee..82b61917cdbd2 100644
--- a/llvm/test/Transforms/InstCombine/compute-sign-bits-bitcast.ll
+++ b/llvm/test/Transforms/InstCombine/compute-sign-bits-bitcast.ll
@@ -59,3 +59,160 @@ define <4 x i8> @test_non_sign_extended(i32 %val) {
%sra = ashr <4 x i8> %bc, <i8 1, i8 1, i8 1, i8 1>
ret <4 x i8> %sra
}
+
+; Case 5: bitcast+ashr+shuffle+bitcast sign-extension idiom (pre-AVX512
+; emulation of wide-element vector ashr). See issue #125189.
+define <2 x i64> @test_bitcast_shuffle_ashr_sign_extend(<2 x i64> %x) {
+; CHECK-LABEL: define <2 x i64> @test_bitcast_shuffle_ashr_sign_extend(
+; CHECK-SAME: <2 x i64> [[X:%.*]]) {
+; CHECK-NEXT: [[NARROW:%.*]] = bitcast <2 x i64> [[X]] to <4 x i32>
+; CHECK-NEXT: [[SHIFTED:%.*]] = ashr <4 x i32> [[NARROW]], <i32 0, i32 31, i32 0, i32 31>
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i32> [[SHIFTED]], <4 x i32> poison, <4 x i32> <i32 1, i32 1, i32 3, i32 3>
+; CHECK-NEXT: [[WIDE:%.*]] = bitcast <4 x i32> [[SHUF]] to <2 x i64>
+; CHECK-NEXT: ret <2 x i64> [[WIDE]]
+;
+ %narrow = bitcast <2 x i64> %x to <4 x i32>
+ %shifted = ashr <4 x i32> %narrow, <i32 0, i32 31, i32 0, i32 31>
+ %shuf = shufflevector <4 x i32> %shifted, <4 x i32> poison, <4 x i32> <i32 1, i32 1, i32 3, i32 3>
+ %wide = bitcast <4 x i32> %shuf to <2 x i64>
+ ret <2 x i64> %wide
+}
+
+; Case 6: same idiom at AVX2 width (<4 x i64> via <8 x i32>)
+define <4 x i64> @test_bitcast_shuffle_ashr_sign_extend_v4i64(<4 x i64> %x) {
+; CHECK-LABEL: define <4 x i64> @test_bitcast_shuffle_ashr_sign_extend_v4i64(
+; CHECK-SAME: <4 x i64> [[X:%.*]]) {
+; CHECK-NEXT: [[NARROW:%.*]] = bitcast <4 x i64> [[X]] to <8 x i32>
+; CHECK-NEXT: [[SHIFTED:%.*]] = ashr <8 x i32> [[NARROW]], <i32 0, i32 31, i32 0, i32 31, i32 0, i32 31, i32 0, i32 31>
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <8 x i32> [[SHIFTED]], <8 x i32> poison, <8 x i32> <i32 1, i32 1, i32 3, i32 3, i32 5, i32 5, i32 7, i32 7>
+; CHECK-NEXT: [[WIDE:%.*]] = bitcast <8 x i32> [[SHUF]] to <4 x i64>
+; CHECK-NEXT: ret <4 x i64> [[WIDE]]
+;
+ %narrow = bitcast <4 x i64> %x to <8 x i32>
+ %shifted = ashr <8 x i32> %narrow, <i32 0, i32 31, i32 0, i32 31, i32 0, i32 31, i32 0, i32 31>
+ %shuf = shufflevector <8 x i32> %shifted, <8 x i32> poison, <8 x i32> <i32 1, i32 1, i32 3, i32 3, i32 5, i32 5, i32 7, i32 7>
+ %wide = bitcast <8 x i32> %shuf to <4 x i64>
+ ret <4 x i64> %wide
+}
+
+; Case 7: same idiom at narrower width (<4 x i32> via <8 x i16>)
+define <4 x i32> @test_bitcast_shuffle_ashr_sign_extend_v4i32(<4 x i32> %x) {
+; CHECK-LABEL: define <4 x i32> @test_bitcast_shuffle_ashr_sign_extend_v4i32(
+; CHECK-SAME: <4 x i32> [[X:%.*]]) {
+; CHECK-NEXT: [[NARROW:%.*]] = bitcast <4 x i32> [[X]] to <8 x i16>
+; CHECK-NEXT: [[SHIFTED:%.*]] = ashr <8 x i16> [[NARROW]], <i16 0, i16 15, i16 0, i16 15, i16 0, i16 15, i16 0, i16 15>
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <8 x i16> [[SHIFTED]], <8 x i16> poison, <8 x i32> <i32 1, i32 1, i32 3, i32 3, i32 5, i32 5, i32 7, i32 7>
+; CHECK-NEXT: [[WIDE:%.*]] = bitcast <8 x i16> [[SHUF]] to <4 x i32>
+; CHECK-NEXT: ret <4 x i32> [[WIDE]]
+;
+ %narrow = bitcast <4 x i32> %x to <8 x i16>
+ %shifted = ashr <8 x i16> %narrow, <i16 0, i16 15, i16 0, i16 15, i16 0, i16 15, i16 0, i16 15>
+ %shuf = shufflevector <8 x i16> %shifted, <8 x i16> poison, <8 x i32> <i32 1, i32 1, i32 3, i32 3, i32 5, i32 5, i32 7, i32 7>
+ %wide = bitcast <8 x i16> %shuf to <4 x i32>
+ ret <4 x i32> %wide
+}
+
+; (Negative) Case 8: wrong shift amount on the high lane - must not fold
+define <2 x i64> @test_bitcast_shuffle_ashr_wrong_shift(<2 x i64> %x) {
+; CHECK-LABEL: define <2 x i64> @test_bitcast_shuffle_ashr_wrong_shift(
+; CHECK-SAME: <2 x i64> [[X:%.*]]) {
+; CHECK-NEXT: [[NARROW:%.*]] = bitcast <2 x i64> [[X]] to <4 x i32>
+; CHECK-NEXT: [[SHIFTED:%.*]] = ashr <4 x i32> [[NARROW]], <i32 0, i32 30, i32 0, i32 30>
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i32> [[SHIFTED]], <4 x i32> poison, <4 x i32> <i32 1, i32 1, i32 3, i32 3>
+; CHECK-NEXT: [[WIDE:%.*]] = bitcast <4 x i32> [[SHUF]] to <2 x i64>
+; CHECK-NEXT: ret <2 x i64> [[WIDE]]
+;
+ %narrow = bitcast <2 x i64> %x to <4 x i32>
+ %shifted = ashr <4 x i32> %narrow, <i32 0, i32 30, i32 0, i32 30>
+ %shuf = shufflevector <4 x i32> %shifted, <4 x i32> poison, <4 x i32> <i32 1, i32 1, i32 3, i32 3>
+ %wide = bitcast <4 x i32> %shuf to <2 x i64>
+ ret <2 x i64> %wide
+}
+
+; (Negative) Case 9: shuffle mask selects low half instead of high - must not fold
+define <2 x i64> @test_bitcast_shuffle_ashr_wrong_mask(<2 x i64> %x) {
+; CHECK-LABEL: define <2 x i64> @test_bitcast_shuffle_ashr_wrong_mask(
+; CHECK-SAME: <2 x i64> [[X:%.*]]) {
+; CHECK-NEXT: [[NARROW:%.*]] = bitcast <2 x i64> [[X]] to <4 x i32>
+; CHECK-NEXT: [[SHIFTED:%.*]] = ashr <4 x i32> [[NARROW]], <i32 0, i32 31, i32 0, i32 31>
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i32> [[SHIFTED]], <4 x i32> poison, <4 x i32> <i32 0, i32 0, i32 2, i32 2>
+; CHECK-NEXT: [[WIDE:%.*]] = bitcast <4 x i32> [[SHUF]] to <2 x i64>
+; CHECK-NEXT: ret <2 x i64> [[WIDE]]
+;
+ %narrow = bitcast <2 x i64> %x to <4 x i32>
+ %shifted = ashr <4 x i32> %narrow, <i32 0, i32 31, i32 0, i32 31>
+ %shuf = shufflevector <4 x i32> %shifted, <4 x i32> poison, <4 x i32> <i32 0, i32 0, i32 2, i32 2>
+ %wide = bitcast <4 x i32> %shuf to <2 x i64>
+ ret <2 x i64> %wide
+}
+
+; (Negative) Case 10: non-constant shift amount - must not fold
+define <2 x i64> @test_bitcast_shuffle_ashr_nonconstant_shift(<2 x i64> %x, <4 x i32> %shamt) {
+; CHECK-LABEL: define <2 x i64> @test_bitcast_shuffle_ashr_nonconstant_shift(
+; CHECK-SAME: <2 x i64> [[X:%.*]], <4 x i32> [[SHAMT:%.*]]) {
+; CHECK-NEXT: [[NARROW:%.*]] = bitcast <2 x i64> [[X]] to <4 x i32>
+; CHECK-NEXT: [[SHIFTED:%.*]] = ashr <4 x i32> [[NARROW]], [[SHAMT]]
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i32> [[SHIFTED]], <4 x i32> poison, <4 x i32> <i32 1, i32 1, i32 3, i32 3>
+; CHECK-NEXT: [[WIDE:%.*]] = bitcast <4 x i32> [[SHUF]] to <2 x i64>
+; CHECK-NEXT: ret <2 x i64> [[WIDE]]
+;
+ %narrow = bitcast <2 x i64> %x to <4 x i32>
+ %shifted = ashr <4 x i32> %narrow, %shamt
+ %shuf = shufflevector <4 x i32> %shifted, <4 x i32> poison, <4 x i32> <i32 1, i32 1, i32 3, i32 3>
+ %wide = bitcast <4 x i32> %shuf to <2 x i64>
+ ret <2 x i64> %wide
+}
+
+; (Negative) Case 11: poison shift amount on the high lane - must not fold,
+; since we cannot prove the resulting wide ashr amount is well-defined.
+define <2 x i64> @neg_poison_shift_amount(<2 x i64> %x) {
+; CHECK-LABEL: define <2 x i64> @neg_poison_shift_amount(
+; CHECK-SAME: <2 x i64> [[X:%.*]]) {
+; CHECK-NEXT: [[NARROW:%.*]] = bitcast <2 x i64> [[X]] to <4 x i32>
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i32> [[NARROW]], <4 x i32> poison, <4 x i32> <i32 1, i32 1, i32 3, i32 3>
+; CHECK-NEXT: [[WIDE:%.*]] = bitcast <4 x i32> [[SHUF]] to <2 x i64>
+; CHECK-NEXT: ret <2 x i64> [[WIDE]]
+;
+ %narrow = bitcast <2 x i64> %x to <4 x i32>
+ %shifted = ashr <4 x i32> %narrow, <i32 0, i32 poison, i32 0, i32 poison>
+ %shuf = shufflevector <4 x i32> %shifted, <4 x i32> poison, <4 x i32> <i32 1, i32 1, i32 3, i32 3>
+ %wide = bitcast <4 x i32> %shuf to <2 x i64>
+ ret <2 x i64> %wide
+}
+
+; (Negative) Case 12: poison element in the shuffle mask itself - must not
+; fold, since the broadcast structure cannot be confirmed for that lane.
+define <2 x i64> @neg_poison_shuffle_mask_elt(<2 x i64> %x) {
+; CHECK-LABEL: define <2 x i64> @neg_poison_shuffle_mask_elt(
+; CHECK-SAME: <2 x i64> [[X:%.*]]) {
+; CHECK-NEXT: [[NARROW:%.*]] = bitcast <2 x i64> [[X]] to <4 x i32>
+; CHECK-NEXT: [[SHIFTED:%.*]] = ashr <4 x i32> [[NARROW]], <i32 0, i32 31, i32 0, i32 31>
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i32> [[SHIFTED]], <4 x i32> poison, <4 x i32> <i32 1, i32 poison, i32 3, i32 3>
+; CHECK-NEXT: [[WIDE:%.*]] = bitcast <4 x i32> [[SHUF]] to <2 x i64>
+; CHECK-NEXT: ret <2 x i64> [[WIDE]]
+;
+ %narrow = bitcast <2 x i64> %x to <4 x i32>
+ %shifted = ashr <4 x i32> %narrow, <i32 0, i32 31, i32 0, i32 31>
+ %shuf = shufflevector <4 x i32> %shifted, <4 x i32> poison, <4 x i32> <i32 1, i32 poison, i32 3, i32 3>
+ %wide = bitcast <4 x i32> %shuf to <2 x i64>
+ ret <2 x i64> %wide
+}
+
+; Positive: low-lane shift amount is poison instead of a literal 0. This is
+; still safe to fold, since the low half is discarded by the shuffle and its
+; value (poison or not) never reaches the result.
+define <2 x i64> @pos_poison_low_shift_is_safe(<2 x i64> %x) {
+; CHECK-LABEL: define <2 x i64> @pos_poison_low_shift_is_safe(
+; CHECK-SAME: <2 x i64> [[X:%.*]]) {
+; CHECK-NEXT: [[NARROW:%.*]] = bitcast <2 x i64> [[X]] to <4 x i32>
+; CHECK-NEXT: [[SHIFTED:%.*]] = ashr <4 x i32> [[NARROW]], <i32 poison, i32 31, i32 poison, i32 31>
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i32> [[SHIFTED]], <4 x i32> poison, <4 x i32> <i32 1, i32 1, i32 3, i32 3>
+; CHECK-NEXT: [[WIDE:%.*]] = bitcast <4 x i32> [[SHUF]] to <2 x i64>
+; CHECK-NEXT: ret <2 x i64> [[WIDE]]
+;
+ %narrow = bitcast <2 x i64> %x to <4 x i32>
+ %shifted = ashr <4 x i32> %narrow, <i32 poison, i32 31, i32 poison, i32 31>
+ %shuf = shufflevector <4 x i32> %shifted, <4 x i32> poison, <4 x i32> <i32 1, i32 1, i32 3, i32 3>
+ %wide = bitcast <4 x i32> %shuf to <2 x i64>
+ ret <2 x i64> %wide
+}
>From d444387ca862a0fe518b3a127a2b396e84f5816a Mon Sep 17 00:00:00 2001
From: AntonyCJ30 <cj6186609 at gmail@gmail.com>
Date: Tue, 30 Jun 2026 17:25:33 +0530
Subject: [PATCH 2/2] [InstCombine] Fold X86 v2i64 ashr emulation pattern to
single ashr (PR#125189)
---
.../InstCombine/InstCombineCasts.cpp | 62 +++++++++++++++++++
.../InstCombine/compute-sign-bits-bitcast.ll | 15 +----
2 files changed, 65 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 7e747ddb9013e..7d3c656617895 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -3303,7 +3303,66 @@ static Value *foldCopySignIdioms(BitCastInst &CI,
return Builder.CreateCopySign(Builder.CreateBitCast(Y, FTy), X);
}
+/// Fold bitcast(shuffle(ashr(bitcast(X)))) to wide ashr.
+/// This pattern is generated by pre-AVX512 X86 backends to emulate
+/// 64-bit vector arithmetic shifts.
+///
+/// Fixes llvm/llvm-project#125189.
+static Instruction *
+foldBitcastShuffleAShrToWideAShr(BitCastInst &BC,
+ InstCombiner::BuilderTy &Builder) {
+ auto *DstTy = dyn_cast<FixedVectorType>(BC.getType());
+ auto *SrcTy = dyn_cast<FixedVectorType>(BC.getOperand(0)->getType());
+ if (!DstTy || !SrcTy)
+ return nullptr;
+
+ auto *Ti = dyn_cast<IntegerType>(DstTy->getElementType());
+ auto *Tj = dyn_cast<IntegerType>(SrcTy->getElementType());
+ if (!Ti || !Tj)
+ return nullptr;
+
+ unsigned N = DstTy->getNumElements();
+ unsigned W = Ti->getBitWidth();
+ unsigned Half = W / 2;
+ if (SrcTy->getNumElements() != 2 * N || Tj->getBitWidth() != Half || W < 4)
+ return nullptr;
+
+ Value *X;
+ Constant *ShiftVec;
+ ArrayRef<int> Mask;
+
+ if (!match(BC.getOperand(0),
+ m_Shuffle(m_AShr(m_BitCast(m_Value(X)), m_Constant(ShiftVec)),
+ m_CombineOr(m_Poison(), m_Undef()), m_Mask(Mask))))
+ return nullptr;
+
+ if (X->getType() != DstTy)
+ return nullptr;
+
+ // Pattern: shift[2k] = 0, shift[2k+1] = Half-1
+ // mask[2k] = mask[2k+1] = 2k+1
+ for (unsigned i = 0; i < N; ++i) {
+ unsigned Lo = 2 * i;
+ unsigned Hi = 2 * i + 1;
+
+ auto *ShiftLo = dyn_cast_or_null<ConstantInt>(
+ ShiftVec->getAggregateElement(Lo));
+ auto *ShiftHi = dyn_cast_or_null<ConstantInt>(
+ ShiftVec->getAggregateElement(Hi));
+ if (!ShiftLo || !ShiftHi || !ShiftLo->isZero() ||
+ ShiftHi->getZExtValue() != Half - 1)
+ return nullptr;
+
+ if (Mask[Lo] != (int)Hi || Mask[Hi] != (int)Hi)
+ return nullptr;
+ }
+
+ Constant *SplatAmt = ConstantVector::getSplat(
+ ElementCount::getFixed(N),
+ ConstantInt::get(Ti, W - 1));
+ return BinaryOperator::CreateAShr(X, SplatAmt);
+}
Instruction *InstCombinerImpl::visitBitCast(BitCastInst &CI) {
// If the operands are integer typed then apply the integer transforms,
// otherwise just apply the common ones.
@@ -3444,6 +3503,9 @@ Instruction *InstCombinerImpl::visitBitCast(BitCastInst &CI) {
if (Instruction *I = foldBitCastSelect(CI, Builder))
return I;
+ if (Instruction *I = foldBitcastShuffleAShrToWideAShr(CI, Builder))
+ return I;
+
if (Value *V = foldCopySignIdioms(CI, Builder, SQ.getWithInstruction(&CI)))
return replaceInstUsesWith(CI, V);
diff --git a/llvm/test/Transforms/InstCombine/compute-sign-bits-bitcast.ll b/llvm/test/Transforms/InstCombine/compute-sign-bits-bitcast.ll
index 82b61917cdbd2..11d504615df7a 100644
--- a/llvm/test/Transforms/InstCombine/compute-sign-bits-bitcast.ll
+++ b/llvm/test/Transforms/InstCombine/compute-sign-bits-bitcast.ll
@@ -65,10 +65,7 @@ define <4 x i8> @test_non_sign_extended(i32 %val) {
define <2 x i64> @test_bitcast_shuffle_ashr_sign_extend(<2 x i64> %x) {
; CHECK-LABEL: define <2 x i64> @test_bitcast_shuffle_ashr_sign_extend(
; CHECK-SAME: <2 x i64> [[X:%.*]]) {
-; CHECK-NEXT: [[NARROW:%.*]] = bitcast <2 x i64> [[X]] to <4 x i32>
-; CHECK-NEXT: [[SHIFTED:%.*]] = ashr <4 x i32> [[NARROW]], <i32 0, i32 31, i32 0, i32 31>
-; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i32> [[SHIFTED]], <4 x i32> poison, <4 x i32> <i32 1, i32 1, i32 3, i32 3>
-; CHECK-NEXT: [[WIDE:%.*]] = bitcast <4 x i32> [[SHUF]] to <2 x i64>
+; CHECK-NEXT: [[WIDE:%.*]] = ashr <2 x i64> [[X]], splat (i64 63)
; CHECK-NEXT: ret <2 x i64> [[WIDE]]
;
%narrow = bitcast <2 x i64> %x to <4 x i32>
@@ -82,10 +79,7 @@ define <2 x i64> @test_bitcast_shuffle_ashr_sign_extend(<2 x i64> %x) {
define <4 x i64> @test_bitcast_shuffle_ashr_sign_extend_v4i64(<4 x i64> %x) {
; CHECK-LABEL: define <4 x i64> @test_bitcast_shuffle_ashr_sign_extend_v4i64(
; CHECK-SAME: <4 x i64> [[X:%.*]]) {
-; CHECK-NEXT: [[NARROW:%.*]] = bitcast <4 x i64> [[X]] to <8 x i32>
-; CHECK-NEXT: [[SHIFTED:%.*]] = ashr <8 x i32> [[NARROW]], <i32 0, i32 31, i32 0, i32 31, i32 0, i32 31, i32 0, i32 31>
-; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <8 x i32> [[SHIFTED]], <8 x i32> poison, <8 x i32> <i32 1, i32 1, i32 3, i32 3, i32 5, i32 5, i32 7, i32 7>
-; CHECK-NEXT: [[WIDE:%.*]] = bitcast <8 x i32> [[SHUF]] to <4 x i64>
+; CHECK-NEXT: [[WIDE:%.*]] = ashr <4 x i64> [[X]], splat (i64 63)
; CHECK-NEXT: ret <4 x i64> [[WIDE]]
;
%narrow = bitcast <4 x i64> %x to <8 x i32>
@@ -99,10 +93,7 @@ define <4 x i64> @test_bitcast_shuffle_ashr_sign_extend_v4i64(<4 x i64> %x) {
define <4 x i32> @test_bitcast_shuffle_ashr_sign_extend_v4i32(<4 x i32> %x) {
; CHECK-LABEL: define <4 x i32> @test_bitcast_shuffle_ashr_sign_extend_v4i32(
; CHECK-SAME: <4 x i32> [[X:%.*]]) {
-; CHECK-NEXT: [[NARROW:%.*]] = bitcast <4 x i32> [[X]] to <8 x i16>
-; CHECK-NEXT: [[SHIFTED:%.*]] = ashr <8 x i16> [[NARROW]], <i16 0, i16 15, i16 0, i16 15, i16 0, i16 15, i16 0, i16 15>
-; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <8 x i16> [[SHIFTED]], <8 x i16> poison, <8 x i32> <i32 1, i32 1, i32 3, i32 3, i32 5, i32 5, i32 7, i32 7>
-; CHECK-NEXT: [[WIDE:%.*]] = bitcast <8 x i16> [[SHUF]] to <4 x i32>
+; CHECK-NEXT: [[WIDE:%.*]] = ashr <4 x i32> [[X]], splat (i32 31)
; CHECK-NEXT: ret <4 x i32> [[WIDE]]
;
%narrow = bitcast <4 x i32> %x to <8 x i16>
More information about the llvm-commits
mailing list