Skip to content

Commit 795c24c

Browse files
authored
[InstCombine] foldVecExtTruncToExtElt - extend to handle trunc(lshr(extractelement(x,c1),c2)) -> extractelement(bitcast(x),c3) patterns. (#109689)
This patch moves the existing trunc+extractlement -> extractelement+bitcast fold into a foldVecExtTruncToExtElt helper and extends the helper to handle trunc+lshr+extractelement cases as well. Fixes #107404
1 parent 5d734fa commit 795c24c

File tree

3 files changed

+273
-30
lines changed

3 files changed

+273
-30
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp

Lines changed: 67 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,71 @@ static Instruction *foldVecTruncToExtElt(TruncInst &Trunc,
436436
return ExtractElementInst::Create(VecInput, IC.Builder.getInt32(Elt));
437437
}
438438

439+
/// Whenever an element is extracted from a vector, optionally shifted down, and
440+
/// then truncated, canonicalize by converting it to a bitcast followed by an
441+
/// extractelement.
442+
///
443+
/// Examples (little endian):
444+
/// trunc (extractelement <4 x i64> %X, 0) to i32
445+
/// --->
446+
/// extractelement <8 x i32> (bitcast <4 x i64> %X to <8 x i32>), i32 0
447+
///
448+
/// trunc (lshr (extractelement <4 x i32> %X, 0), 8) to i8
449+
/// --->
450+
/// extractelement <16 x i8> (bitcast <4 x i32> %X to <16 x i8>), i32 1
451+
static Instruction *foldVecExtTruncToExtElt(TruncInst &Trunc,
452+
InstCombinerImpl &IC) {
453+
Value *Src = Trunc.getOperand(0);
454+
Type *SrcType = Src->getType();
455+
Type *DstType = Trunc.getType();
456+
457+
// Only attempt this if we have simple aliasing of the vector elements.
458+
// A badly fit destination size would result in an invalid cast.
459+
unsigned SrcBits = SrcType->getScalarSizeInBits();
460+
unsigned DstBits = DstType->getScalarSizeInBits();
461+
unsigned TruncRatio = SrcBits / DstBits;
462+
if ((SrcBits % DstBits) != 0)
463+
return nullptr;
464+
465+
Value *VecOp;
466+
ConstantInt *Cst;
467+
const APInt *ShiftAmount = nullptr;
468+
if (!match(Src, m_OneUse(m_ExtractElt(m_Value(VecOp), m_ConstantInt(Cst)))) &&
469+
!match(Src,
470+
m_OneUse(m_LShr(m_ExtractElt(m_Value(VecOp), m_ConstantInt(Cst)),
471+
m_APInt(ShiftAmount)))))
472+
return nullptr;
473+
474+
auto *VecOpTy = cast<VectorType>(VecOp->getType());
475+
auto VecElts = VecOpTy->getElementCount();
476+
477+
uint64_t BitCastNumElts = VecElts.getKnownMinValue() * TruncRatio;
478+
uint64_t VecOpIdx = Cst->getZExtValue();
479+
uint64_t NewIdx = IC.getDataLayout().isBigEndian()
480+
? (VecOpIdx + 1) * TruncRatio - 1
481+
: VecOpIdx * TruncRatio;
482+
483+
// Adjust index by the whole number of truncated elements.
484+
if (ShiftAmount) {
485+
// Check shift amount is in range and shifts a whole number of truncated
486+
// elements.
487+
if (ShiftAmount->uge(SrcBits) || ShiftAmount->urem(DstBits) != 0)
488+
return nullptr;
489+
490+
uint64_t IdxOfs = ShiftAmount->udiv(DstBits).getZExtValue();
491+
NewIdx = IC.getDataLayout().isBigEndian() ? (NewIdx - IdxOfs)
492+
: (NewIdx + IdxOfs);
493+
}
494+
495+
assert(BitCastNumElts <= std::numeric_limits<uint32_t>::max() &&
496+
NewIdx <= std::numeric_limits<uint32_t>::max() && "overflow 32-bits");
497+
498+
auto *BitCastTo =
499+
VectorType::get(DstType, BitCastNumElts, VecElts.isScalable());
500+
Value *BitCast = IC.Builder.CreateBitCast(VecOp, BitCastTo);
501+
return ExtractElementInst::Create(BitCast, IC.Builder.getInt32(NewIdx));
502+
}
503+
439504
/// Funnel/Rotate left/right may occur in a wider type than necessary because of
440505
/// type promotion rules. Try to narrow the inputs and convert to funnel shift.
441506
Instruction *InstCombinerImpl::narrowFunnelShift(TruncInst &Trunc) {
@@ -848,36 +913,8 @@ Instruction *InstCombinerImpl::visitTrunc(TruncInst &Trunc) {
848913
if (Instruction *I = foldVecTruncToExtElt(Trunc, *this))
849914
return I;
850915

851-
// Whenever an element is extracted from a vector, and then truncated,
852-
// canonicalize by converting it to a bitcast followed by an
853-
// extractelement.
854-
//
855-
// Example (little endian):
856-
// trunc (extractelement <4 x i64> %X, 0) to i32
857-
// --->
858-
// extractelement <8 x i32> (bitcast <4 x i64> %X to <8 x i32>), i32 0
859-
Value *VecOp;
860-
ConstantInt *Cst;
861-
if (match(Src, m_OneUse(m_ExtractElt(m_Value(VecOp), m_ConstantInt(Cst))))) {
862-
auto *VecOpTy = cast<VectorType>(VecOp->getType());
863-
auto VecElts = VecOpTy->getElementCount();
864-
865-
// A badly fit destination size would result in an invalid cast.
866-
if (SrcWidth % DestWidth == 0) {
867-
uint64_t TruncRatio = SrcWidth / DestWidth;
868-
uint64_t BitCastNumElts = VecElts.getKnownMinValue() * TruncRatio;
869-
uint64_t VecOpIdx = Cst->getZExtValue();
870-
uint64_t NewIdx = DL.isBigEndian() ? (VecOpIdx + 1) * TruncRatio - 1
871-
: VecOpIdx * TruncRatio;
872-
assert(BitCastNumElts <= std::numeric_limits<uint32_t>::max() &&
873-
"overflow 32-bits");
874-
875-
auto *BitCastTo =
876-
VectorType::get(DestTy, BitCastNumElts, VecElts.isScalable());
877-
Value *BitCast = Builder.CreateBitCast(VecOp, BitCastTo);
878-
return ExtractElementInst::Create(BitCast, Builder.getInt32(NewIdx));
879-
}
880-
}
916+
if (Instruction *I = foldVecExtTruncToExtElt(Trunc, *this))
917+
return I;
881918

882919
// trunc (ctlz_i32(zext(A), B) --> add(ctlz_i16(A, B), C)
883920
if (match(Src, m_OneUse(m_Intrinsic<Intrinsic::ctlz>(m_ZExt(m_Value(A)),

llvm/test/Transforms/InstCombine/trunc-extractelement-inseltpoison.ll

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,23 @@ define i32 @shrinkExtractElt_i64_to_i32_0(<3 x i64> %x) {
1818
ret i32 %t
1919
}
2020

21+
define i32 @shrinkShiftExtractElt_i64_to_i32_0(<3 x i64> %x) {
22+
; LE-LABEL: @shrinkShiftExtractElt_i64_to_i32_0(
23+
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <6 x i32>
24+
; LE-NEXT: [[T:%.*]] = extractelement <6 x i32> [[TMP1]], i64 1
25+
; LE-NEXT: ret i32 [[T]]
26+
;
27+
; BE-LABEL: @shrinkShiftExtractElt_i64_to_i32_0(
28+
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <6 x i32>
29+
; BE-NEXT: [[T:%.*]] = extractelement <6 x i32> [[TMP1]], i64 0
30+
; BE-NEXT: ret i32 [[T]]
31+
;
32+
%e = extractelement <3 x i64> %x, i32 0
33+
%s = lshr i64 %e, 32
34+
%t = trunc i64 %s to i32
35+
ret i32 %t
36+
}
37+
2138
define i32 @vscale_shrinkExtractElt_i64_to_i32_0(<vscale x 3 x i64> %x) {
2239
; LE-LABEL: @vscale_shrinkExtractElt_i64_to_i32_0(
2340
; LE-NEXT: [[TMP1:%.*]] = bitcast <vscale x 3 x i64> [[X:%.*]] to <vscale x 6 x i32>
@@ -34,6 +51,22 @@ define i32 @vscale_shrinkExtractElt_i64_to_i32_0(<vscale x 3 x i64> %x) {
3451
ret i32 %t
3552
}
3653

54+
define i32 @vscale_shrinkShiftExtractElt_i64_to_i32_0(<vscale x 3 x i64> %x) {
55+
; LE-LABEL: @vscale_shrinkShiftExtractElt_i64_to_i32_0(
56+
; LE-NEXT: [[TMP1:%.*]] = bitcast <vscale x 3 x i64> [[X:%.*]] to <vscale x 6 x i32>
57+
; LE-NEXT: [[T:%.*]] = extractelement <vscale x 6 x i32> [[TMP1]], i64 1
58+
; LE-NEXT: ret i32 [[T]]
59+
;
60+
; BE-LABEL: @vscale_shrinkShiftExtractElt_i64_to_i32_0(
61+
; BE-NEXT: [[TMP1:%.*]] = bitcast <vscale x 3 x i64> [[X:%.*]] to <vscale x 6 x i32>
62+
; BE-NEXT: [[T:%.*]] = extractelement <vscale x 6 x i32> [[TMP1]], i64 0
63+
; BE-NEXT: ret i32 [[T]]
64+
;
65+
%e = extractelement <vscale x 3 x i64> %x, i32 0
66+
%s = lshr i64 %e, 32
67+
%t = trunc i64 %s to i32
68+
ret i32 %t
69+
}
3770

3871
define i32 @shrinkExtractElt_i64_to_i32_1(<3 x i64> %x) {
3972
; LE-LABEL: @shrinkExtractElt_i64_to_i32_1(
@@ -83,6 +116,23 @@ define i16 @shrinkExtractElt_i64_to_i16_0(<3 x i64> %x) {
83116
ret i16 %t
84117
}
85118

119+
define i16 @shrinkShiftExtractElt_i64_to_i16_0(<3 x i64> %x) {
120+
; LE-LABEL: @shrinkShiftExtractElt_i64_to_i16_0(
121+
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <12 x i16>
122+
; LE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 3
123+
; LE-NEXT: ret i16 [[T]]
124+
;
125+
; BE-LABEL: @shrinkShiftExtractElt_i64_to_i16_0(
126+
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <12 x i16>
127+
; BE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 0
128+
; BE-NEXT: ret i16 [[T]]
129+
;
130+
%e = extractelement <3 x i64> %x, i16 0
131+
%s = ashr i64 %e, 48
132+
%t = trunc i64 %s to i16
133+
ret i16 %t
134+
}
135+
86136
define i16 @shrinkExtractElt_i64_to_i16_1(<3 x i64> %x) {
87137
; LE-LABEL: @shrinkExtractElt_i64_to_i16_1(
88138
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <12 x i16>
@@ -157,6 +207,20 @@ define i30 @shrinkExtractElt_i40_to_i30_1(<3 x i40> %x) {
157207
ret i30 %t
158208
}
159209

210+
; Do not optimize if the shift amount isn't a whole number of truncated bits.
211+
define i16 @shrinkShiftExtractElt_i64_to_i16_0_badshift(<3 x i64> %x) {
212+
; ANY-LABEL: @shrinkShiftExtractElt_i64_to_i16_0_badshift(
213+
; ANY-NEXT: [[E:%.*]] = extractelement <3 x i64> [[X:%.*]], i64 0
214+
; ANY-NEXT: [[S:%.*]] = lshr i64 [[E]], 31
215+
; ANY-NEXT: [[T:%.*]] = trunc i64 [[S]] to i16
216+
; ANY-NEXT: ret i16 [[T]]
217+
;
218+
%e = extractelement <3 x i64> %x, i16 0
219+
%s = lshr i64 %e, 31
220+
%t = trunc i64 %s to i16
221+
ret i16 %t
222+
}
223+
160224
; Do not canonicalize if that would increase the instruction count.
161225
declare void @use(i64)
162226
define i16 @shrinkExtractElt_i64_to_i16_2_extra_use(<3 x i64> %x) {
@@ -172,6 +236,45 @@ define i16 @shrinkExtractElt_i64_to_i16_2_extra_use(<3 x i64> %x) {
172236
ret i16 %t
173237
}
174238

239+
; Do not canonicalize if that would increase the instruction count.
240+
define i16 @shrinkShiftExtractElt_i64_to_i16_2_extra_shift_use(<3 x i64> %x) {
241+
; ANY-LABEL: @shrinkShiftExtractElt_i64_to_i16_2_extra_shift_use(
242+
; ANY-NEXT: [[E:%.*]] = extractelement <3 x i64> [[X:%.*]], i64 2
243+
; ANY-NEXT: [[S:%.*]] = lshr i64 [[E]], 48
244+
; ANY-NEXT: call void @use(i64 [[S]])
245+
; ANY-NEXT: [[T:%.*]] = trunc nuw i64 [[S]] to i16
246+
; ANY-NEXT: ret i16 [[T]]
247+
;
248+
%e = extractelement <3 x i64> %x, i64 2
249+
%s = lshr i64 %e, 48
250+
call void @use(i64 %s)
251+
%t = trunc i64 %s to i16
252+
ret i16 %t
253+
}
254+
255+
; OK to reuse the extract if we remove the shift+trunc.
256+
define i16 @shrinkShiftExtractElt_i64_to_i16_2_extra_extract_use(<3 x i64> %x) {
257+
; LE-LABEL: @shrinkShiftExtractElt_i64_to_i16_2_extra_extract_use(
258+
; LE-NEXT: [[E:%.*]] = extractelement <3 x i64> [[X:%.*]], i64 2
259+
; LE-NEXT: call void @use(i64 [[E]])
260+
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X]] to <12 x i16>
261+
; LE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 11
262+
; LE-NEXT: ret i16 [[T]]
263+
;
264+
; BE-LABEL: @shrinkShiftExtractElt_i64_to_i16_2_extra_extract_use(
265+
; BE-NEXT: [[E:%.*]] = extractelement <3 x i64> [[X:%.*]], i64 2
266+
; BE-NEXT: call void @use(i64 [[E]])
267+
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X]] to <12 x i16>
268+
; BE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 8
269+
; BE-NEXT: ret i16 [[T]]
270+
;
271+
%e = extractelement <3 x i64> %x, i64 2
272+
call void @use(i64 %e)
273+
%s = lshr i64 %e, 48
274+
%t = trunc i64 %s to i16
275+
ret i16 %t
276+
}
277+
175278
; Check to ensure PR45314 remains fixed.
176279
define <4 x i64> @PR45314(<4 x i64> %x) {
177280
; LE-LABEL: @PR45314(

llvm/test/Transforms/InstCombine/trunc-extractelement.ll

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,23 @@ define i32 @shrinkExtractElt_i64_to_i32_0(<3 x i64> %x) {
1818
ret i32 %t
1919
}
2020

21+
define i32 @shrinkShiftExtractElt_i64_to_i32_0(<3 x i64> %x) {
22+
; LE-LABEL: @shrinkShiftExtractElt_i64_to_i32_0(
23+
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <6 x i32>
24+
; LE-NEXT: [[T:%.*]] = extractelement <6 x i32> [[TMP1]], i64 1
25+
; LE-NEXT: ret i32 [[T]]
26+
;
27+
; BE-LABEL: @shrinkShiftExtractElt_i64_to_i32_0(
28+
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <6 x i32>
29+
; BE-NEXT: [[T:%.*]] = extractelement <6 x i32> [[TMP1]], i64 0
30+
; BE-NEXT: ret i32 [[T]]
31+
;
32+
%e = extractelement <3 x i64> %x, i32 0
33+
%s = lshr i64 %e, 32
34+
%t = trunc i64 %s to i32
35+
ret i32 %t
36+
}
37+
2138
define i32 @vscale_shrinkExtractElt_i64_to_i32_0(<vscale x 3 x i64> %x) {
2239
; LE-LABEL: @vscale_shrinkExtractElt_i64_to_i32_0(
2340
; LE-NEXT: [[TMP1:%.*]] = bitcast <vscale x 3 x i64> [[X:%.*]] to <vscale x 6 x i32>
@@ -34,6 +51,22 @@ define i32 @vscale_shrinkExtractElt_i64_to_i32_0(<vscale x 3 x i64> %x) {
3451
ret i32 %t
3552
}
3653

54+
define i32 @vscale_shrinkShiftExtractElt_i64_to_i32_0(<vscale x 3 x i64> %x) {
55+
; LE-LABEL: @vscale_shrinkShiftExtractElt_i64_to_i32_0(
56+
; LE-NEXT: [[TMP1:%.*]] = bitcast <vscale x 3 x i64> [[X:%.*]] to <vscale x 6 x i32>
57+
; LE-NEXT: [[T:%.*]] = extractelement <vscale x 6 x i32> [[TMP1]], i64 1
58+
; LE-NEXT: ret i32 [[T]]
59+
;
60+
; BE-LABEL: @vscale_shrinkShiftExtractElt_i64_to_i32_0(
61+
; BE-NEXT: [[TMP1:%.*]] = bitcast <vscale x 3 x i64> [[X:%.*]] to <vscale x 6 x i32>
62+
; BE-NEXT: [[T:%.*]] = extractelement <vscale x 6 x i32> [[TMP1]], i64 0
63+
; BE-NEXT: ret i32 [[T]]
64+
;
65+
%e = extractelement <vscale x 3 x i64> %x, i32 0
66+
%s = lshr i64 %e, 32
67+
%t = trunc i64 %s to i32
68+
ret i32 %t
69+
}
3770

3871
define i32 @shrinkExtractElt_i64_to_i32_1(<3 x i64> %x) {
3972
; LE-LABEL: @shrinkExtractElt_i64_to_i32_1(
@@ -83,6 +116,23 @@ define i16 @shrinkExtractElt_i64_to_i16_0(<3 x i64> %x) {
83116
ret i16 %t
84117
}
85118

119+
define i16 @shrinkShiftExtractElt_i64_to_i16_0(<3 x i64> %x) {
120+
; LE-LABEL: @shrinkShiftExtractElt_i64_to_i16_0(
121+
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <12 x i16>
122+
; LE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 3
123+
; LE-NEXT: ret i16 [[T]]
124+
;
125+
; BE-LABEL: @shrinkShiftExtractElt_i64_to_i16_0(
126+
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <12 x i16>
127+
; BE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 0
128+
; BE-NEXT: ret i16 [[T]]
129+
;
130+
%e = extractelement <3 x i64> %x, i16 0
131+
%s = ashr i64 %e, 48
132+
%t = trunc i64 %s to i16
133+
ret i16 %t
134+
}
135+
86136
define i16 @shrinkExtractElt_i64_to_i16_1(<3 x i64> %x) {
87137
; LE-LABEL: @shrinkExtractElt_i64_to_i16_1(
88138
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <12 x i16>
@@ -157,6 +207,20 @@ define i30 @shrinkExtractElt_i40_to_i30_1(<3 x i40> %x) {
157207
ret i30 %t
158208
}
159209

210+
; Do not optimize if the shift amount isn't a whole number of truncated bits.
211+
define i16 @shrinkShiftExtractElt_i64_to_i16_0_badshift(<3 x i64> %x) {
212+
; ANY-LABEL: @shrinkShiftExtractElt_i64_to_i16_0_badshift(
213+
; ANY-NEXT: [[E:%.*]] = extractelement <3 x i64> [[X:%.*]], i64 0
214+
; ANY-NEXT: [[S:%.*]] = lshr i64 [[E]], 31
215+
; ANY-NEXT: [[T:%.*]] = trunc i64 [[S]] to i16
216+
; ANY-NEXT: ret i16 [[T]]
217+
;
218+
%e = extractelement <3 x i64> %x, i16 0
219+
%s = lshr i64 %e, 31
220+
%t = trunc i64 %s to i16
221+
ret i16 %t
222+
}
223+
160224
; Do not canonicalize if that would increase the instruction count.
161225
declare void @use(i64)
162226
define i16 @shrinkExtractElt_i64_to_i16_2_extra_use(<3 x i64> %x) {
@@ -172,6 +236,45 @@ define i16 @shrinkExtractElt_i64_to_i16_2_extra_use(<3 x i64> %x) {
172236
ret i16 %t
173237
}
174238

239+
; Do not canonicalize if that would increase the instruction count.
240+
define i16 @shrinkShiftExtractElt_i64_to_i16_2_extra_shift_use(<3 x i64> %x) {
241+
; ANY-LABEL: @shrinkShiftExtractElt_i64_to_i16_2_extra_shift_use(
242+
; ANY-NEXT: [[E:%.*]] = extractelement <3 x i64> [[X:%.*]], i64 2
243+
; ANY-NEXT: [[S:%.*]] = lshr i64 [[E]], 48
244+
; ANY-NEXT: call void @use(i64 [[S]])
245+
; ANY-NEXT: [[T:%.*]] = trunc nuw i64 [[S]] to i16
246+
; ANY-NEXT: ret i16 [[T]]
247+
;
248+
%e = extractelement <3 x i64> %x, i64 2
249+
%s = lshr i64 %e, 48
250+
call void @use(i64 %s)
251+
%t = trunc i64 %s to i16
252+
ret i16 %t
253+
}
254+
255+
; OK to reuse the extract if we remove the shift+trunc.
256+
define i16 @shrinkShiftExtractElt_i64_to_i16_2_extra_extract_use(<3 x i64> %x) {
257+
; LE-LABEL: @shrinkShiftExtractElt_i64_to_i16_2_extra_extract_use(
258+
; LE-NEXT: [[E:%.*]] = extractelement <3 x i64> [[X:%.*]], i64 2
259+
; LE-NEXT: call void @use(i64 [[E]])
260+
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X]] to <12 x i16>
261+
; LE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 11
262+
; LE-NEXT: ret i16 [[T]]
263+
;
264+
; BE-LABEL: @shrinkShiftExtractElt_i64_to_i16_2_extra_extract_use(
265+
; BE-NEXT: [[E:%.*]] = extractelement <3 x i64> [[X:%.*]], i64 2
266+
; BE-NEXT: call void @use(i64 [[E]])
267+
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X]] to <12 x i16>
268+
; BE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 8
269+
; BE-NEXT: ret i16 [[T]]
270+
;
271+
%e = extractelement <3 x i64> %x, i64 2
272+
call void @use(i64 %e)
273+
%s = lshr i64 %e, 48
274+
%t = trunc i64 %s to i16
275+
ret i16 %t
276+
}
277+
175278
; Check to ensure PR45314 remains fixed.
176279
define <4 x i64> @PR45314(<4 x i64> %x) {
177280
; LE-LABEL: @PR45314(

0 commit comments

Comments
 (0)