; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instcombine -S -data-layout="e" | FileCheck %s --check-prefixes=ANY,LE
; RUN: opt < %s -passes=instcombine -S -data-layout="E" | FileCheck %s --check-prefixes=ANY,BE
define i32 @shrinkExtractElt_i64_to_i32_0(<3 x i64> %x) {
; LE-LABEL: @shrinkExtractElt_i64_to_i32_0(
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <6 x i32>
; LE-NEXT: [[T:%.*]] = extractelement <6 x i32> [[TMP1]], i64 0
; LE-NEXT: ret i32 [[T]]
;
; BE-LABEL: @shrinkExtractElt_i64_to_i32_0(
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <6 x i32>
; BE-NEXT: [[T:%.*]] = extractelement <6 x i32> [[TMP1]], i64 1
; BE-NEXT: ret i32 [[T]]
;
%e = extractelement <3 x i64> %x, i32 0
%t = trunc i64 %e to i32
ret i32 %t
}
define i32 @shrinkShiftExtractElt_i64_to_i32_0(<3 x i64> %x) {
; LE-LABEL: @shrinkShiftExtractElt_i64_to_i32_0(
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <6 x i32>
; LE-NEXT: [[T:%.*]] = extractelement <6 x i32> [[TMP1]], i64 1
; LE-NEXT: ret i32 [[T]]
;
; BE-LABEL: @shrinkShiftExtractElt_i64_to_i32_0(
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <6 x i32>
; BE-NEXT: [[T:%.*]] = extractelement <6 x i32> [[TMP1]], i64 0
; BE-NEXT: ret i32 [[T]]
;
%e = extractelement <3 x i64> %x, i32 0
%s = lshr i64 %e, 32
%t = trunc i64 %s to i32
ret i32 %t
}
define i32 @vscale_shrinkExtractElt_i64_to_i32_0(<vscale x 3 x i64> %x) {
; LE-LABEL: @vscale_shrinkExtractElt_i64_to_i32_0(
; LE-NEXT: [[TMP1:%.*]] = bitcast <vscale x 3 x i64> [[X:%.*]] to <vscale x 6 x i32>
; LE-NEXT: [[T:%.*]] = extractelement <vscale x 6 x i32> [[TMP1]], i64 0
; LE-NEXT: ret i32 [[T]]
;
; BE-LABEL: @vscale_shrinkExtractElt_i64_to_i32_0(
; BE-NEXT: [[TMP1:%.*]] = bitcast <vscale x 3 x i64> [[X:%.*]] to <vscale x 6 x i32>
; BE-NEXT: [[T:%.*]] = extractelement <vscale x 6 x i32> [[TMP1]], i64 1
; BE-NEXT: ret i32 [[T]]
;
%e = extractelement <vscale x 3 x i64> %x, i32 0
%t = trunc i64 %e to i32
ret i32 %t
}
define i32 @vscale_shrinkShiftExtractElt_i64_to_i32_0(<vscale x 3 x i64> %x) {
; LE-LABEL: @vscale_shrinkShiftExtractElt_i64_to_i32_0(
; LE-NEXT: [[TMP1:%.*]] = bitcast <vscale x 3 x i64> [[X:%.*]] to <vscale x 6 x i32>
; LE-NEXT: [[T:%.*]] = extractelement <vscale x 6 x i32> [[TMP1]], i64 1
; LE-NEXT: ret i32 [[T]]
;
; BE-LABEL: @vscale_shrinkShiftExtractElt_i64_to_i32_0(
; BE-NEXT: [[TMP1:%.*]] = bitcast <vscale x 3 x i64> [[X:%.*]] to <vscale x 6 x i32>
; BE-NEXT: [[T:%.*]] = extractelement <vscale x 6 x i32> [[TMP1]], i64 0
; BE-NEXT: ret i32 [[T]]
;
%e = extractelement <vscale x 3 x i64> %x, i32 0
%s = lshr i64 %e, 32
%t = trunc i64 %s to i32
ret i32 %t
}
define i32 @shrinkExtractElt_i64_to_i32_1(<3 x i64> %x) {
; LE-LABEL: @shrinkExtractElt_i64_to_i32_1(
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <6 x i32>
; LE-NEXT: [[T:%.*]] = extractelement <6 x i32> [[TMP1]], i64 2
; LE-NEXT: ret i32 [[T]]
;
; BE-LABEL: @shrinkExtractElt_i64_to_i32_1(
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <6 x i32>
; BE-NEXT: [[T:%.*]] = extractelement <6 x i32> [[TMP1]], i64 3
; BE-NEXT: ret i32 [[T]]
;
%e = extractelement <3 x i64> %x, i32 1
%t = trunc i64 %e to i32
ret i32 %t
}
define i32 @shrinkExtractElt_i64_to_i32_2(<3 x i64> %x) {
; LE-LABEL: @shrinkExtractElt_i64_to_i32_2(
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <6 x i32>
; LE-NEXT: [[T:%.*]] = extractelement <6 x i32> [[TMP1]], i64 4
; LE-NEXT: ret i32 [[T]]
;
; BE-LABEL: @shrinkExtractElt_i64_to_i32_2(
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <6 x i32>
; BE-NEXT: [[T:%.*]] = extractelement <6 x i32> [[TMP1]], i64 5
; BE-NEXT: ret i32 [[T]]
;
%e = extractelement <3 x i64> %x, i32 2
%t = trunc i64 %e to i32
ret i32 %t
}
define i16 @shrinkExtractElt_i64_to_i16_0(<3 x i64> %x) {
; LE-LABEL: @shrinkExtractElt_i64_to_i16_0(
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <12 x i16>
; LE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 0
; LE-NEXT: ret i16 [[T]]
;
; BE-LABEL: @shrinkExtractElt_i64_to_i16_0(
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <12 x i16>
; BE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 3
; BE-NEXT: ret i16 [[T]]
;
%e = extractelement <3 x i64> %x, i16 0
%t = trunc i64 %e to i16
ret i16 %t
}
define i16 @shrinkShiftExtractElt_i64_to_i16_0(<3 x i64> %x) {
; LE-LABEL: @shrinkShiftExtractElt_i64_to_i16_0(
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <12 x i16>
; LE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 3
; LE-NEXT: ret i16 [[T]]
;
; BE-LABEL: @shrinkShiftExtractElt_i64_to_i16_0(
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <12 x i16>
; BE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 0
; BE-NEXT: ret i16 [[T]]
;
%e = extractelement <3 x i64> %x, i16 0
%s = ashr i64 %e, 48
%t = trunc i64 %s to i16
ret i16 %t
}
define i16 @shrinkExtractElt_i64_to_i16_1(<3 x i64> %x) {
; LE-LABEL: @shrinkExtractElt_i64_to_i16_1(
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <12 x i16>
; LE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 4
; LE-NEXT: ret i16 [[T]]
;
; BE-LABEL: @shrinkExtractElt_i64_to_i16_1(
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <12 x i16>
; BE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 7
; BE-NEXT: ret i16 [[T]]
;
%e = extractelement <3 x i64> %x, i16 1
%t = trunc i64 %e to i16
ret i16 %t
}
define i16 @shrinkExtractElt_i64_to_i16_2(<3 x i64> %x) {
; LE-LABEL: @shrinkExtractElt_i64_to_i16_2(
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <12 x i16>
; LE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 8
; LE-NEXT: ret i16 [[T]]
;
; BE-LABEL: @shrinkExtractElt_i64_to_i16_2(
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X:%.*]] to <12 x i16>
; BE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 11
; BE-NEXT: ret i16 [[T]]
;
%e = extractelement <3 x i64> %x, i16 2
%t = trunc i64 %e to i16
ret i16 %t
}
; Crazy types may be ok.
define i11 @shrinkExtractElt_i33_to_11_2(<3 x i33> %x) {
; LE-LABEL: @shrinkExtractElt_i33_to_11_2(
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i33> [[X:%.*]] to <9 x i11>
; LE-NEXT: [[T:%.*]] = extractelement <9 x i11> [[TMP1]], i64 6
; LE-NEXT: ret i11 [[T]]
;
; BE-LABEL: @shrinkExtractElt_i33_to_11_2(
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i33> [[X:%.*]] to <9 x i11>
; BE-NEXT: [[T:%.*]] = extractelement <9 x i11> [[TMP1]], i64 8
; BE-NEXT: ret i11 [[T]]
;
%e = extractelement <3 x i33> %x, i16 2
%t = trunc i33 %e to i11
ret i11 %t
}
; Do not optimize if it would result in an invalid bitcast instruction.
define i13 @shrinkExtractElt_i67_to_i13_2(<3 x i67> %x) {
; ANY-LABEL: @shrinkExtractElt_i67_to_i13_2(
; ANY-NEXT: [[E:%.*]] = extractelement <3 x i67> [[X:%.*]], i64 2
; ANY-NEXT: [[T:%.*]] = trunc i67 [[E]] to i13
; ANY-NEXT: ret i13 [[T]]
;
%e = extractelement <3 x i67> %x, i459 2
%t = trunc i67 %e to i13
ret i13 %t
}
; Do not optimize if the bitcast instruction would be valid, but the
; transform would be wrong.
define i30 @shrinkExtractElt_i40_to_i30_1(<3 x i40> %x) {
; ANY-LABEL: @shrinkExtractElt_i40_to_i30_1(
; ANY-NEXT: [[E:%.*]] = extractelement <3 x i40> [[X:%.*]], i64 1
; ANY-NEXT: [[T:%.*]] = trunc i40 [[E]] to i30
; ANY-NEXT: ret i30 [[T]]
;
%e = extractelement <3 x i40> %x, i32 1
%t = trunc i40 %e to i30
ret i30 %t
}
; Do not optimize if the shift amount isn't a whole number of truncated bits.
define i16 @shrinkShiftExtractElt_i64_to_i16_0_badshift(<3 x i64> %x) {
; ANY-LABEL: @shrinkShiftExtractElt_i64_to_i16_0_badshift(
; ANY-NEXT: [[E:%.*]] = extractelement <3 x i64> [[X:%.*]], i64 0
; ANY-NEXT: [[S:%.*]] = lshr i64 [[E]], 31
; ANY-NEXT: [[T:%.*]] = trunc i64 [[S]] to i16
; ANY-NEXT: ret i16 [[T]]
;
%e = extractelement <3 x i64> %x, i16 0
%s = lshr i64 %e, 31
%t = trunc i64 %s to i16
ret i16 %t
}
; Do not canonicalize if that would increase the instruction count.
declare void @use(i64)
define i16 @shrinkExtractElt_i64_to_i16_2_extra_use(<3 x i64> %x) {
; ANY-LABEL: @shrinkExtractElt_i64_to_i16_2_extra_use(
; ANY-NEXT: [[E:%.*]] = extractelement <3 x i64> [[X:%.*]], i64 2
; ANY-NEXT: call void @use(i64 [[E]])
; ANY-NEXT: [[T:%.*]] = trunc i64 [[E]] to i16
; ANY-NEXT: ret i16 [[T]]
;
%e = extractelement <3 x i64> %x, i64 2
call void @use(i64 %e)
%t = trunc i64 %e to i16
ret i16 %t
}
; Do not canonicalize if that would increase the instruction count.
define i16 @shrinkShiftExtractElt_i64_to_i16_2_extra_shift_use(<3 x i64> %x) {
; ANY-LABEL: @shrinkShiftExtractElt_i64_to_i16_2_extra_shift_use(
; ANY-NEXT: [[E:%.*]] = extractelement <3 x i64> [[X:%.*]], i64 2
; ANY-NEXT: [[S:%.*]] = lshr i64 [[E]], 48
; ANY-NEXT: call void @use(i64 [[S]])
; ANY-NEXT: [[T:%.*]] = trunc nuw i64 [[S]] to i16
; ANY-NEXT: ret i16 [[T]]
;
%e = extractelement <3 x i64> %x, i64 2
%s = lshr i64 %e, 48
call void @use(i64 %s)
%t = trunc i64 %s to i16
ret i16 %t
}
; OK to reuse the extract if we remove the shift+trunc.
define i16 @shrinkShiftExtractElt_i64_to_i16_2_extra_extract_use(<3 x i64> %x) {
; LE-LABEL: @shrinkShiftExtractElt_i64_to_i16_2_extra_extract_use(
; LE-NEXT: [[E:%.*]] = extractelement <3 x i64> [[X:%.*]], i64 2
; LE-NEXT: call void @use(i64 [[E]])
; LE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X]] to <12 x i16>
; LE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 11
; LE-NEXT: ret i16 [[T]]
;
; BE-LABEL: @shrinkShiftExtractElt_i64_to_i16_2_extra_extract_use(
; BE-NEXT: [[E:%.*]] = extractelement <3 x i64> [[X:%.*]], i64 2
; BE-NEXT: call void @use(i64 [[E]])
; BE-NEXT: [[TMP1:%.*]] = bitcast <3 x i64> [[X]] to <12 x i16>
; BE-NEXT: [[T:%.*]] = extractelement <12 x i16> [[TMP1]], i64 8
; BE-NEXT: ret i16 [[T]]
;
%e = extractelement <3 x i64> %x, i64 2
call void @use(i64 %e)
%s = lshr i64 %e, 48
%t = trunc i64 %s to i16
ret i16 %t
}
; Check to ensure PR45314 remains fixed.
define <4 x i64> @PR45314(<4 x i64> %x) {
; LE-LABEL: @PR45314(
; LE-NEXT: [[TMP1:%.*]] = bitcast <4 x i64> [[X:%.*]] to <8 x i32>
; LE-NEXT: [[S:%.*]] = shufflevector <8 x i32> [[TMP1]], <8 x i32> poison, <8 x i32> zeroinitializer
; LE-NEXT: [[B:%.*]] = bitcast <8 x i32> [[S]] to <4 x i64>
; LE-NEXT: ret <4 x i64> [[B]]
;
; BE-LABEL: @PR45314(
; BE-NEXT: [[TMP1:%.*]] = bitcast <4 x i64> [[X:%.*]] to <8 x i32>
; BE-NEXT: [[S:%.*]] = shufflevector <8 x i32> [[TMP1]], <8 x i32> poison, <8 x i32> <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
; BE-NEXT: [[B:%.*]] = bitcast <8 x i32> [[S]] to <4 x i64>
; BE-NEXT: ret <4 x i64> [[B]]
;
%e = extractelement <4 x i64> %x, i32 0
%t = trunc i64 %e to i32
%i = insertelement <8 x i32> poison, i32 %t, i32 0
%s = shufflevector <8 x i32> %i, <8 x i32> poison, <8 x i32> zeroinitializer
%b = bitcast <8 x i32> %s to <4 x i64>
ret <4 x i64> %b
}