| ; 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 |
| } |