; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -instcombine -S | FileCheck %s ; llvm.experimental.vector.insert canonicalizes to shufflevector in the fixed case. In the ; scalable case, we lower to the INSERT_SUBVECTOR ISD node. declare <8 x i32> @llvm.experimental.vector.insert.v8i32.v2i32(<8 x i32> %vec, <2 x i32> %subvec, i64 %idx) declare <8 x i32> @llvm.experimental.vector.insert.v8i32.v3i32(<8 x i32> %vec, <3 x i32> %subvec, i64 %idx) declare <8 x i32> @llvm.experimental.vector.insert.v8i32.v4i32(<8 x i32> %vec, <4 x i32> %subvec, i64 %idx) declare <8 x i32> @llvm.experimental.vector.insert.v8i32.v8i32(<8 x i32> %vec, <8 x i32> %subvec, i64 %idx) declare @llvm.experimental.vector.insert.nxv4i32.v4i32( %vec, <4 x i32> %subvec, i64 %idx) ; ============================================================================ ; ; Trivial cases ; ============================================================================ ; ; An insert that entirely overwrites an with another is a ; nop. define <8 x i32> @trivial_nop(<8 x i32> %vec, <8 x i32> %subvec) { ; CHECK-LABEL: @trivial_nop( ; CHECK-NEXT: ret <8 x i32> [[SUBVEC:%.*]] ; %1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v8i32(<8 x i32> %vec, <8 x i32> %subvec, i64 0) ret <8 x i32> %1 } ; ============================================================================ ; ; Valid canonicalizations ; ============================================================================ ; define <8 x i32> @valid_insertion_a(<8 x i32> %vec, <2 x i32> %subvec) { ; CHECK-LABEL: @valid_insertion_a( ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x i32> [[SUBVEC:%.*]], <2 x i32> undef, <8 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[TMP1]], <8 x i32> [[VEC:%.*]], <8 x i32> ; CHECK-NEXT: ret <8 x i32> [[TMP2]] ; %1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v2i32(<8 x i32> %vec, <2 x i32> %subvec, i64 0) ret <8 x i32> %1 } define <8 x i32> @valid_insertion_b(<8 x i32> %vec, <2 x i32> %subvec) { ; CHECK-LABEL: @valid_insertion_b( ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x i32> [[SUBVEC:%.*]], <2 x i32> undef, <8 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[VEC:%.*]], <8 x i32> [[TMP1]], <8 x i32> ; CHECK-NEXT: ret <8 x i32> [[TMP2]] ; %1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v2i32(<8 x i32> %vec, <2 x i32> %subvec, i64 2) ret <8 x i32> %1 } define <8 x i32> @valid_insertion_c(<8 x i32> %vec, <2 x i32> %subvec) { ; CHECK-LABEL: @valid_insertion_c( ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x i32> [[SUBVEC:%.*]], <2 x i32> undef, <8 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[VEC:%.*]], <8 x i32> [[TMP1]], <8 x i32> ; CHECK-NEXT: ret <8 x i32> [[TMP2]] ; %1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v2i32(<8 x i32> %vec, <2 x i32> %subvec, i64 4) ret <8 x i32> %1 } define <8 x i32> @valid_insertion_d(<8 x i32> %vec, <2 x i32> %subvec) { ; CHECK-LABEL: @valid_insertion_d( ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x i32> [[SUBVEC:%.*]], <2 x i32> undef, <8 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[VEC:%.*]], <8 x i32> [[TMP1]], <8 x i32> ; CHECK-NEXT: ret <8 x i32> [[TMP2]] ; %1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v2i32(<8 x i32> %vec, <2 x i32> %subvec, i64 6) ret <8 x i32> %1 } define <8 x i32> @valid_insertion_e(<8 x i32> %vec, <4 x i32> %subvec) { ; CHECK-LABEL: @valid_insertion_e( ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <4 x i32> [[SUBVEC:%.*]], <4 x i32> undef, <8 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[TMP1]], <8 x i32> [[VEC:%.*]], <8 x i32> ; CHECK-NEXT: ret <8 x i32> [[TMP2]] ; %1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v4i32(<8 x i32> %vec, <4 x i32> %subvec, i64 0) ret <8 x i32> %1 } define <8 x i32> @valid_insertion_f(<8 x i32> %vec, <4 x i32> %subvec) { ; CHECK-LABEL: @valid_insertion_f( ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <4 x i32> [[SUBVEC:%.*]], <4 x i32> undef, <8 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[VEC:%.*]], <8 x i32> [[TMP1]], <8 x i32> ; CHECK-NEXT: ret <8 x i32> [[TMP2]] ; %1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v4i32(<8 x i32> %vec, <4 x i32> %subvec, i64 4) ret <8 x i32> %1 } define <8 x i32> @valid_insertion_g(<8 x i32> %vec, <3 x i32> %subvec) { ; CHECK-LABEL: @valid_insertion_g( ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <3 x i32> [[SUBVEC:%.*]], <3 x i32> undef, <8 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[TMP1]], <8 x i32> [[VEC:%.*]], <8 x i32> ; CHECK-NEXT: ret <8 x i32> [[TMP2]] ; %1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v3i32(<8 x i32> %vec, <3 x i32> %subvec, i64 0) ret <8 x i32> %1 } define <8 x i32> @valid_insertion_h(<8 x i32> %vec, <3 x i32> %subvec) { ; CHECK-LABEL: @valid_insertion_h( ; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <3 x i32> [[SUBVEC:%.*]], <3 x i32> undef, <8 x i32> ; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[VEC:%.*]], <8 x i32> [[TMP1]], <8 x i32> ; CHECK-NEXT: ret <8 x i32> [[TMP2]] ; %1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v3i32(<8 x i32> %vec, <3 x i32> %subvec, i64 3) ret <8 x i32> %1 } ; ============================================================================ ; ; Invalid canonicalizations ; ============================================================================ ; ; Idx must be the be a constant multiple of the subvector's minimum vector ; length, otherwise the result is undefined. define <8 x i32> @idx_not_constant_multiple(<8 x i32> %vec, <4 x i32> %subvec) { ; CHECK-LABEL: @idx_not_constant_multiple( ; CHECK-NEXT: ret <8 x i32> undef ; %1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v4i32(<8 x i32> %vec, <4 x i32> %subvec, i64 2) ret <8 x i32> %1 } ; If the insertion overruns the vector, the result is undefined. define <8 x i32> @insert_overrun(<8 x i32> %vec, <8 x i32> %subvec) { ; CHECK-LABEL: @insert_overrun( ; CHECK-NEXT: ret <8 x i32> undef ; %1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v8i32(<8 x i32> %vec, <8 x i32> %subvec, i64 4) ret <8 x i32> %1 } ; ============================================================================ ; ; Scalable cases ; ============================================================================ ; ; Scalable insertions should not be canonicalized. This will be lowered to the ; INSERT_SUBVECTOR ISD node later. define @scalable_insert( %vec, <4 x i32> %subvec) { ; CHECK-LABEL: @scalable_insert( ; CHECK-NEXT: [[TMP1:%.*]] = call @llvm.experimental.vector.insert.nxv4i32.v4i32( [[VEC:%.*]], <4 x i32> [[SUBVEC:%.*]], i64 0) ; CHECK-NEXT: ret [[TMP1]] ; %1 = call @llvm.experimental.vector.insert.nxv4i32.v4i32( %vec, <4 x i32> %subvec, i64 0) ret %1 }