blob: ec1ffa84df0f51e7090f1553ea7dfc3f41336dd4 [file] [edit]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mattr=+sse2 | FileCheck %s --check-prefixes=CHECK,SSE
; RUN: opt < %s -passes=vector-combine -S -mtriple=x86_64-- -mattr=+avx2 | FileCheck %s --check-prefixes=CHECK,AVX
; Insertelement chains whose elements are all parts of the same scalar can be
; a bitcast of the scalar and a shuffle.
define <2 x i32> @swapped_halves(i64 %x) {
; CHECK-LABEL: define <2 x i32> @swapped_halves(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[X]] to <2 x i32>
; CHECK-NEXT: [[V1:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> poison, <2 x i32> <i32 1, i32 0>
; CHECK-NEXT: ret <2 x i32> [[V1]]
;
%hi = lshr i64 %x, 32
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %x to i32
%v0 = insertelement <2 x i32> poison, i32 %t1, i64 0
%v1 = insertelement <2 x i32> %v0, i32 %t0, i64 1
ret <2 x i32> %v1
}
define <2 x float> @swapped_halves_float(i64 %x) {
; CHECK-LABEL: define <2 x float> @swapped_halves_float(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[X]] to <2 x float>
; CHECK-NEXT: [[V1:%.*]] = shufflevector <2 x float> [[TMP1]], <2 x float> poison, <2 x i32> <i32 1, i32 0>
; CHECK-NEXT: ret <2 x float> [[V1]]
;
%hi = lshr i64 %x, 32
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %x to i32
%f1 = bitcast i32 %t1 to float
%f0 = bitcast i32 %t0 to float
%v0 = insertelement <2 x float> poison, float %f1, i64 0
%v1 = insertelement <2 x float> %v0, float %f0, i64 1
ret <2 x float> %v1
}
define <4 x i16> @reversed_quarters(i64 %x) {
; CHECK-LABEL: define <4 x i16> @reversed_quarters(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[X]] to <4 x i16>
; CHECK-NEXT: [[V3:%.*]] = shufflevector <4 x i16> [[TMP1]], <4 x i16> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
; CHECK-NEXT: ret <4 x i16> [[V3]]
;
%s1 = lshr i64 %x, 16
%s2 = lshr i64 %x, 32
%s3 = lshr i64 %x, 48
%t0 = trunc i64 %x to i16
%t1 = trunc i64 %s1 to i16
%t2 = trunc i64 %s2 to i16
%t3 = trunc i64 %s3 to i16
%v0 = insertelement <4 x i16> poison, i16 %t3, i64 0
%v1 = insertelement <4 x i16> %v0, i16 %t2, i64 1
%v2 = insertelement <4 x i16> %v1, i16 %t1, i64 2
%v3 = insertelement <4 x i16> %v2, i16 %t0, i64 3
ret <4 x i16> %v3
}
define <4 x i32> @reversed_i128(i128 %x) {
; CHECK-LABEL: define <4 x i32> @reversed_i128(
; CHECK-SAME: i128 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i128 [[X]] to <4 x i32>
; CHECK-NEXT: [[V3:%.*]] = shufflevector <4 x i32> [[TMP1]], <4 x i32> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
; CHECK-NEXT: ret <4 x i32> [[V3]]
;
%s1 = lshr i128 %x, 32
%s2 = lshr i128 %x, 64
%s3 = lshr i128 %x, 96
%t0 = trunc i128 %x to i32
%t1 = trunc i128 %s1 to i32
%t2 = trunc i128 %s2 to i32
%t3 = trunc i128 %s3 to i32
%v0 = insertelement <4 x i32> poison, i32 %t3, i64 0
%v1 = insertelement <4 x i32> %v0, i32 %t2, i64 1
%v2 = insertelement <4 x i32> %v1, i32 %t1, i64 2
%v3 = insertelement <4 x i32> %v2, i32 %t0, i64 3
ret <4 x i32> %v3
}
; The scalar has fewer parts than the vector has elements.
define <4 x i32> @repeated_halves(i64 %x) {
; CHECK-LABEL: define <4 x i32> @repeated_halves(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[X]] to <2 x i32>
; CHECK-NEXT: [[V3:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> poison, <4 x i32> <i32 1, i32 0, i32 1, i32 0>
; CHECK-NEXT: ret <4 x i32> [[V3]]
;
%hi = lshr i64 %x, 32
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %x to i32
%v0 = insertelement <4 x i32> poison, i32 %t1, i64 0
%v1 = insertelement <4 x i32> %v0, i32 %t0, i64 1
%v2 = insertelement <4 x i32> %v1, i32 %t1, i64 2
%v3 = insertelement <4 x i32> %v2, i32 %t0, i64 3
ret <4 x i32> %v3
}
; The scalar has more parts than the vector has elements.
define <2 x i16> @odd_quarters(i64 %x) {
; CHECK-LABEL: define <2 x i16> @odd_quarters(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[X]] to <4 x i16>
; CHECK-NEXT: [[V1:%.*]] = shufflevector <4 x i16> [[TMP1]], <4 x i16> poison, <2 x i32> <i32 3, i32 1>
; CHECK-NEXT: ret <2 x i16> [[V1]]
;
%s1 = lshr i64 %x, 16
%s3 = lshr i64 %x, 48
%t1 = trunc i64 %s1 to i16
%t3 = trunc i64 %s3 to i16
%v0 = insertelement <2 x i16> poison, i16 %t3, i64 0
%v1 = insertelement <2 x i16> %v0, i16 %t1, i64 1
ret <2 x i16> %v1
}
define <4 x i16> @in_order_quarters(i64 %x) {
; CHECK-LABEL: define <4 x i16> @in_order_quarters(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[V3:%.*]] = bitcast i64 [[X]] to <4 x i16>
; CHECK-NEXT: ret <4 x i16> [[V3]]
;
%s1 = lshr i64 %x, 16
%s2 = lshr i64 %x, 32
%s3 = lshr i64 %x, 48
%t0 = trunc i64 %x to i16
%t1 = trunc i64 %s1 to i16
%t2 = trunc i64 %s2 to i16
%t3 = trunc i64 %s3 to i16
%v0 = insertelement <4 x i16> poison, i16 %t0, i64 0
%v1 = insertelement <4 x i16> %v0, i16 %t1, i64 1
%v2 = insertelement <4 x i16> %v1, i16 %t2, i64 2
%v3 = insertelement <4 x i16> %v2, i16 %t3, i64 3
ret <4 x i16> %v3
}
; Elements that are not inserted stay poison.
define <4 x i16> @missing_elts(i64 %x) {
; CHECK-LABEL: define <4 x i16> @missing_elts(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[X]] to <4 x i16>
; CHECK-NEXT: [[V1:%.*]] = shufflevector <4 x i16> [[TMP1]], <4 x i16> poison, <4 x i32> <i32 3, i32 poison, i32 2, i32 poison>
; CHECK-NEXT: ret <4 x i16> [[V1]]
;
%s2 = lshr i64 %x, 32
%s3 = lshr i64 %x, 48
%t2 = trunc i64 %s2 to i16
%t3 = trunc i64 %s3 to i16
%v0 = insertelement <4 x i16> poison, i16 %t3, i64 0
%v1 = insertelement <4 x i16> %v0, i16 %t2, i64 2
ret <4 x i16> %v1
}
; A single part is a scalar insert or a splat, which is left in its canonical
; form.
define <2 x i32> @splat_low_half(i64 %x) {
; CHECK-LABEL: define <2 x i32> @splat_low_half(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[T:%.*]] = trunc i64 [[X]] to i32
; CHECK-NEXT: [[V:%.*]] = insertelement <2 x i32> poison, i32 [[T]], i64 0
; CHECK-NEXT: [[S:%.*]] = shufflevector <2 x i32> [[V]], <2 x i32> poison, <2 x i32> zeroinitializer
; CHECK-NEXT: ret <2 x i32> [[S]]
;
%t = trunc i64 %x to i32
%v = insertelement <2 x i32> poison, i32 %t, i64 0
%s = shufflevector <2 x i32> %v, <2 x i32> poison, <2 x i32> zeroinitializer
ret <2 x i32> %s
}
define <4 x float> @splat_low_float(i64 %x) {
; CHECK-LABEL: define <4 x float> @splat_low_float(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[T:%.*]] = trunc i64 [[X]] to i32
; CHECK-NEXT: [[F:%.*]] = bitcast i32 [[T]] to float
; CHECK-NEXT: [[V:%.*]] = insertelement <4 x float> poison, float [[F]], i64 0
; CHECK-NEXT: [[S:%.*]] = shufflevector <4 x float> [[V]], <4 x float> poison, <4 x i32> zeroinitializer
; CHECK-NEXT: ret <4 x float> [[S]]
;
%t = trunc i64 %x to i32
%f = bitcast i32 %t to float
%v = insertelement <4 x float> poison, float %f, i64 0
%s = shufflevector <4 x float> %v, <4 x float> poison, <4 x i32> zeroinitializer
ret <4 x float> %s
}
define <2 x i32> @splat_high_half(i64 %x) {
; CHECK-LABEL: define <2 x i32> @splat_high_half(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[HI:%.*]] = lshr i64 [[X]], 32
; CHECK-NEXT: [[T1:%.*]] = trunc i64 [[HI]] to i32
; CHECK-NEXT: [[V0:%.*]] = insertelement <2 x i32> poison, i32 [[T1]], i64 0
; CHECK-NEXT: [[V1:%.*]] = insertelement <2 x i32> [[V0]], i32 [[T1]], i64 1
; CHECK-NEXT: ret <2 x i32> [[V1]]
;
%hi = lshr i64 %x, 32
%t1 = trunc i64 %hi to i32
%v0 = insertelement <2 x i32> poison, i32 %t1, i64 0
%v1 = insertelement <2 x i32> %v0, i32 %t1, i64 1
ret <2 x i32> %v1
}
; Only the last insert to an element counts.
define <2 x i32> @overwritten_elt(i64 %x, i32 %y) {
; CHECK-LABEL: define <2 x i32> @overwritten_elt(
; CHECK-SAME: i64 [[X:%.*]], i32 [[Y:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[X]] to <2 x i32>
; CHECK-NEXT: [[V2:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> poison, <2 x i32> <i32 1, i32 0>
; CHECK-NEXT: ret <2 x i32> [[V2]]
;
%hi = lshr i64 %x, 32
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %x to i32
%v0 = insertelement <2 x i32> poison, i32 %y, i64 0
%v1 = insertelement <2 x i32> %v0, i32 %t0, i64 1
%v2 = insertelement <2 x i32> %v1, i32 %t1, i64 0
ret <2 x i32> %v2
}
define <2 x i32> @double_source(double %d) {
; CHECK-LABEL: define <2 x i32> @double_source(
; CHECK-SAME: double [[D:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[X:%.*]] = bitcast double [[D]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[X]] to <2 x i32>
; CHECK-NEXT: [[V1:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> poison, <2 x i32> <i32 1, i32 0>
; CHECK-NEXT: ret <2 x i32> [[V1]]
;
%x = bitcast double %d to i64
%hi = lshr i64 %x, 32
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %x to i32
%v0 = insertelement <2 x i32> poison, i32 %t1, i64 0
%v1 = insertelement <2 x i32> %v0, i32 %t0, i64 1
ret <2 x i32> %v1
}
; Every element is inserted, so the base does not matter.
define <2 x i32> @overwritten_base(i64 %x, <2 x i32> %base) {
; CHECK-LABEL: define <2 x i32> @overwritten_base(
; CHECK-SAME: i64 [[X:%.*]], <2 x i32> [[BASE:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64 [[X]] to <2 x i32>
; CHECK-NEXT: [[V1:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> poison, <2 x i32> <i32 1, i32 0>
; CHECK-NEXT: ret <2 x i32> [[V1]]
;
%hi = lshr i64 %x, 32
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %x to i32
%v0 = insertelement <2 x i32> %base, i32 %t1, i64 0
%v1 = insertelement <2 x i32> %v0, i32 %t0, i64 1
ret <2 x i32> %v1
}
define <2 x i32> @swapped_halves_extra_use(i64 %x, ptr %p) {
; SSE-LABEL: define <2 x i32> @swapped_halves_extra_use(
; SSE-SAME: i64 [[X:%.*]], ptr [[P:%.*]]) #[[ATTR0]] {
; SSE-NEXT: [[HI:%.*]] = lshr i64 [[X]], 32
; SSE-NEXT: [[T1:%.*]] = trunc i64 [[HI]] to i32
; SSE-NEXT: store i32 [[T1]], ptr [[P]], align 4
; SSE-NEXT: [[TMP1:%.*]] = bitcast i64 [[X]] to <2 x i32>
; SSE-NEXT: [[V1:%.*]] = shufflevector <2 x i32> [[TMP1]], <2 x i32> poison, <2 x i32> <i32 1, i32 0>
; SSE-NEXT: ret <2 x i32> [[V1]]
;
; AVX-LABEL: define <2 x i32> @swapped_halves_extra_use(
; AVX-SAME: i64 [[X:%.*]], ptr [[P:%.*]]) #[[ATTR0]] {
; AVX-NEXT: [[HI:%.*]] = lshr i64 [[X]], 32
; AVX-NEXT: [[T1:%.*]] = trunc i64 [[HI]] to i32
; AVX-NEXT: [[T0:%.*]] = trunc i64 [[X]] to i32
; AVX-NEXT: store i32 [[T1]], ptr [[P]], align 4
; AVX-NEXT: [[V0:%.*]] = insertelement <2 x i32> poison, i32 [[T1]], i64 0
; AVX-NEXT: [[V1:%.*]] = insertelement <2 x i32> [[V0]], i32 [[T0]], i64 1
; AVX-NEXT: ret <2 x i32> [[V1]]
;
%hi = lshr i64 %x, 32
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %x to i32
store i32 %t1, ptr %p
%v0 = insertelement <2 x i32> poison, i32 %t1, i64 0
%v1 = insertelement <2 x i32> %v0, i32 %t0, i64 1
ret <2 x i32> %v1
}
; Negative tests
define <2 x i32> @different_sources(i64 %x, i64 %y) {
; CHECK-LABEL: define <2 x i32> @different_sources(
; CHECK-SAME: i64 [[X:%.*]], i64 [[Y:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[HI:%.*]] = lshr i64 [[X]], 32
; CHECK-NEXT: [[T1:%.*]] = trunc i64 [[HI]] to i32
; CHECK-NEXT: [[T0:%.*]] = trunc i64 [[Y]] to i32
; CHECK-NEXT: [[V0:%.*]] = insertelement <2 x i32> poison, i32 [[T1]], i64 0
; CHECK-NEXT: [[V1:%.*]] = insertelement <2 x i32> [[V0]], i32 [[T0]], i64 1
; CHECK-NEXT: ret <2 x i32> [[V1]]
;
%hi = lshr i64 %x, 32
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %y to i32
%v0 = insertelement <2 x i32> poison, i32 %t1, i64 0
%v1 = insertelement <2 x i32> %v0, i32 %t0, i64 1
ret <2 x i32> %v1
}
define <2 x i32> @unaligned_shift(i64 %x) {
; CHECK-LABEL: define <2 x i32> @unaligned_shift(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[HI:%.*]] = lshr i64 [[X]], 16
; CHECK-NEXT: [[T1:%.*]] = trunc i64 [[HI]] to i32
; CHECK-NEXT: [[T0:%.*]] = trunc i64 [[X]] to i32
; CHECK-NEXT: [[V0:%.*]] = insertelement <2 x i32> poison, i32 [[T1]], i64 0
; CHECK-NEXT: [[V1:%.*]] = insertelement <2 x i32> [[V0]], i32 [[T0]], i64 1
; CHECK-NEXT: ret <2 x i32> [[V1]]
;
%hi = lshr i64 %x, 16
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %x to i32
%v0 = insertelement <2 x i32> poison, i32 %t1, i64 0
%v1 = insertelement <2 x i32> %v0, i32 %t0, i64 1
ret <2 x i32> %v1
}
define <2 x i32> @ashr(i64 %x) {
; CHECK-LABEL: define <2 x i32> @ashr(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[HI:%.*]] = ashr i64 [[X]], 32
; CHECK-NEXT: [[T1:%.*]] = trunc i64 [[HI]] to i32
; CHECK-NEXT: [[T0:%.*]] = trunc i64 [[X]] to i32
; CHECK-NEXT: [[V0:%.*]] = insertelement <2 x i32> poison, i32 [[T1]], i64 0
; CHECK-NEXT: [[V1:%.*]] = insertelement <2 x i32> [[V0]], i32 [[T0]], i64 1
; CHECK-NEXT: ret <2 x i32> [[V1]]
;
%hi = ashr i64 %x, 32
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %x to i32
%v0 = insertelement <2 x i32> poison, i32 %t1, i64 0
%v1 = insertelement <2 x i32> %v0, i32 %t0, i64 1
ret <2 x i32> %v1
}
define <2 x i32> @variable_shift(i64 %x, i64 %s) {
; CHECK-LABEL: define <2 x i32> @variable_shift(
; CHECK-SAME: i64 [[X:%.*]], i64 [[S:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[HI:%.*]] = lshr i64 [[X]], [[S]]
; CHECK-NEXT: [[T1:%.*]] = trunc i64 [[HI]] to i32
; CHECK-NEXT: [[T0:%.*]] = trunc i64 [[X]] to i32
; CHECK-NEXT: [[V0:%.*]] = insertelement <2 x i32> poison, i32 [[T1]], i64 0
; CHECK-NEXT: [[V1:%.*]] = insertelement <2 x i32> [[V0]], i32 [[T0]], i64 1
; CHECK-NEXT: ret <2 x i32> [[V1]]
;
%hi = lshr i64 %x, %s
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %x to i32
%v0 = insertelement <2 x i32> poison, i32 %t1, i64 0
%v1 = insertelement <2 x i32> %v0, i32 %t0, i64 1
ret <2 x i32> %v1
}
define <2 x i32> @variable_index(i64 %x, i64 %i) {
; CHECK-LABEL: define <2 x i32> @variable_index(
; CHECK-SAME: i64 [[X:%.*]], i64 [[I:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[HI:%.*]] = lshr i64 [[X]], 32
; CHECK-NEXT: [[T1:%.*]] = trunc i64 [[HI]] to i32
; CHECK-NEXT: [[T0:%.*]] = trunc i64 [[X]] to i32
; CHECK-NEXT: [[V0:%.*]] = insertelement <2 x i32> poison, i32 [[T1]], i64 [[I]]
; CHECK-NEXT: [[V1:%.*]] = insertelement <2 x i32> [[V0]], i32 [[T0]], i64 1
; CHECK-NEXT: ret <2 x i32> [[V1]]
;
%hi = lshr i64 %x, 32
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %x to i32
%v0 = insertelement <2 x i32> poison, i32 %t1, i64 %i
%v1 = insertelement <2 x i32> %v0, i32 %t0, i64 1
ret <2 x i32> %v1
}
define <2 x i32> @non_poison_base(i64 %x, <2 x i32> %base) {
; CHECK-LABEL: define <2 x i32> @non_poison_base(
; CHECK-SAME: i64 [[X:%.*]], <2 x i32> [[BASE:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[HI:%.*]] = lshr i64 [[X]], 32
; CHECK-NEXT: [[T1:%.*]] = trunc i64 [[HI]] to i32
; CHECK-NEXT: [[V0:%.*]] = insertelement <2 x i32> [[BASE]], i32 [[T1]], i64 0
; CHECK-NEXT: ret <2 x i32> [[V0]]
;
%hi = lshr i64 %x, 32
%t1 = trunc i64 %hi to i32
%v0 = insertelement <2 x i32> %base, i32 %t1, i64 0
ret <2 x i32> %v0
}
; The elements that are not inserted would become poison instead of %base.
define <4 x i16> @non_poison_base_missing_elts(i64 %x, <4 x i16> %base) {
; CHECK-LABEL: define <4 x i16> @non_poison_base_missing_elts(
; CHECK-SAME: i64 [[X:%.*]], <4 x i16> [[BASE:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[S2:%.*]] = lshr i64 [[X]], 32
; CHECK-NEXT: [[S3:%.*]] = lshr i64 [[X]], 48
; CHECK-NEXT: [[T2:%.*]] = trunc i64 [[S2]] to i16
; CHECK-NEXT: [[T3:%.*]] = trunc i64 [[S3]] to i16
; CHECK-NEXT: [[V0:%.*]] = insertelement <4 x i16> [[BASE]], i16 [[T3]], i64 0
; CHECK-NEXT: [[V1:%.*]] = insertelement <4 x i16> [[V0]], i16 [[T2]], i64 2
; CHECK-NEXT: ret <4 x i16> [[V1]]
;
%s2 = lshr i64 %x, 32
%s3 = lshr i64 %x, 48
%t2 = trunc i64 %s2 to i16
%t3 = trunc i64 %s3 to i16
%v0 = insertelement <4 x i16> %base, i16 %t3, i64 0
%v1 = insertelement <4 x i16> %v0, i16 %t2, i64 2
ret <4 x i16> %v1
}
define <2 x i32> @out_of_range_index(i64 %x) {
; CHECK-LABEL: define <2 x i32> @out_of_range_index(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[HI:%.*]] = lshr i64 [[X]], 32
; CHECK-NEXT: [[T1:%.*]] = trunc i64 [[HI]] to i32
; CHECK-NEXT: [[T0:%.*]] = trunc i64 [[X]] to i32
; CHECK-NEXT: [[V0:%.*]] = insertelement <2 x i32> poison, i32 [[T1]], i64 0
; CHECK-NEXT: [[V1:%.*]] = insertelement <2 x i32> [[V0]], i32 [[T0]], i64 2
; CHECK-NEXT: ret <2 x i32> [[V1]]
;
%hi = lshr i64 %x, 32
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %x to i32
%v0 = insertelement <2 x i32> poison, i32 %t1, i64 0
%v1 = insertelement <2 x i32> %v0, i32 %t0, i64 2
ret <2 x i32> %v1
}
define <2 x i32> @out_of_range_shift(i64 %x) {
; CHECK-LABEL: define <2 x i32> @out_of_range_shift(
; CHECK-SAME: i64 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[HI:%.*]] = lshr i64 [[X]], 64
; CHECK-NEXT: [[T1:%.*]] = trunc i64 [[HI]] to i32
; CHECK-NEXT: [[T0:%.*]] = trunc i64 [[X]] to i32
; CHECK-NEXT: [[V0:%.*]] = insertelement <2 x i32> poison, i32 [[T1]], i64 0
; CHECK-NEXT: [[V1:%.*]] = insertelement <2 x i32> [[V0]], i32 [[T0]], i64 1
; CHECK-NEXT: ret <2 x i32> [[V1]]
;
%hi = lshr i64 %x, 64
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %x to i32
%v0 = insertelement <2 x i32> poison, i32 %t1, i64 0
%v1 = insertelement <2 x i32> %v0, i32 %t0, i64 1
ret <2 x i32> %v1
}
; The intermediate vector is used elsewhere, so the chain ends there.
define <2 x i32> @extra_use_of_insert(i64 %x, ptr %p) {
; CHECK-LABEL: define <2 x i32> @extra_use_of_insert(
; CHECK-SAME: i64 [[X:%.*]], ptr [[P:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[HI:%.*]] = lshr i64 [[X]], 32
; CHECK-NEXT: [[T1:%.*]] = trunc i64 [[HI]] to i32
; CHECK-NEXT: [[T0:%.*]] = trunc i64 [[X]] to i32
; CHECK-NEXT: [[V0:%.*]] = insertelement <2 x i32> poison, i32 [[T1]], i64 0
; CHECK-NEXT: store <2 x i32> [[V0]], ptr [[P]], align 8
; CHECK-NEXT: [[V1:%.*]] = insertelement <2 x i32> [[V0]], i32 [[T0]], i64 1
; CHECK-NEXT: ret <2 x i32> [[V1]]
;
%hi = lshr i64 %x, 32
%t1 = trunc i64 %hi to i32
%t0 = trunc i64 %x to i32
%v0 = insertelement <2 x i32> poison, i32 %t1, i64 0
store <2 x i32> %v0, ptr %p
%v1 = insertelement <2 x i32> %v0, i32 %t0, i64 1
ret <2 x i32> %v1
}
; The scalar is not a whole number of elements.
define <2 x i32> @partial_source(i48 %x) {
; CHECK-LABEL: define <2 x i32> @partial_source(
; CHECK-SAME: i48 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[HI:%.*]] = lshr i48 [[X]], 32
; CHECK-NEXT: [[T1:%.*]] = trunc i48 [[HI]] to i32
; CHECK-NEXT: [[T0:%.*]] = trunc i48 [[X]] to i32
; CHECK-NEXT: [[V0:%.*]] = insertelement <2 x i32> poison, i32 [[T1]], i64 0
; CHECK-NEXT: [[V1:%.*]] = insertelement <2 x i32> [[V0]], i32 [[T0]], i64 1
; CHECK-NEXT: ret <2 x i32> [[V1]]
;
%hi = lshr i48 %x, 32
%t1 = trunc i48 %hi to i32
%t0 = trunc i48 %x to i32
%v0 = insertelement <2 x i32> poison, i32 %t1, i64 0
%v1 = insertelement <2 x i32> %v0, i32 %t0, i64 1
ret <2 x i32> %v1
}
; Elements are truncated from each element of a vector, not from its bits.
define <2 x i32> @vector_trunc(<2 x i32> %x) {
; CHECK-LABEL: define <2 x i32> @vector_trunc(
; CHECK-SAME: <2 x i32> [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[T:%.*]] = trunc <2 x i32> [[X]] to <2 x i16>
; CHECK-NEXT: [[B:%.*]] = bitcast <2 x i16> [[T]] to i32
; CHECK-NEXT: [[V0:%.*]] = insertelement <2 x i32> poison, i32 [[B]], i64 1
; CHECK-NEXT: ret <2 x i32> [[V0]]
;
%t = trunc <2 x i32> %x to <2 x i16>
%b = bitcast <2 x i16> %t to i32
%v0 = insertelement <2 x i32> poison, i32 %b, i64 1
ret <2 x i32> %v0
}
define <8 x i1> @bool_elts(i8 %x) {
; CHECK-LABEL: define <8 x i1> @bool_elts(
; CHECK-SAME: i8 [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[S1:%.*]] = lshr i8 [[X]], 1
; CHECK-NEXT: [[T1:%.*]] = trunc i8 [[S1]] to i1
; CHECK-NEXT: [[T0:%.*]] = trunc i8 [[X]] to i1
; CHECK-NEXT: [[V0:%.*]] = insertelement <8 x i1> poison, i1 [[T1]], i64 0
; CHECK-NEXT: [[V1:%.*]] = insertelement <8 x i1> [[V0]], i1 [[T0]], i64 1
; CHECK-NEXT: ret <8 x i1> [[V1]]
;
%s1 = lshr i8 %x, 1
%t1 = trunc i8 %s1 to i1
%t0 = trunc i8 %x to i1
%v0 = insertelement <8 x i1> poison, i1 %t1, i64 0
%v1 = insertelement <8 x i1> %v0, i1 %t0, i64 1
ret <8 x i1> %v1
}