[llvm] [VectorCombine] Support simplification to scalar store for multiple insertelt (PR #132820)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 13 03:24:17 PDT 2026


https://github.com/ParkHanbum updated https://github.com/llvm/llvm-project/pull/132820

>From ddaa63976bcb499407a452d696bcace121716fe8 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Mon, 24 Mar 2025 14:47:00 +0900
Subject: [PATCH 1/9] add testcases for upcoming patch

---
 .../VectorCombine/load-insert-store.ll        | 358 ++++++++++++++++++
 1 file changed, 358 insertions(+)

diff --git a/llvm/test/Transforms/VectorCombine/load-insert-store.ll b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
index 897b113c197cf..2e86ac23b82f3 100644
--- a/llvm/test/Transforms/VectorCombine/load-insert-store.ll
+++ b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
@@ -16,6 +16,86 @@ entry:
   ret void
 }
 
+define void @insert_store2(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 6
+; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 7
+; CHECK-NEXT:    store <8 x i16> [[VEC2]], ptr [[Q]], align 1
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %0, i16 %s, i32 6
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 7
+  store <8 x i16> %vec2, ptr %q, align 1
+  ret void
+}
+
+define void @insert_store2_duplicate_different_values(ptr %p, i16 %a, i16 %b) {
+; CHECK-LABEL: @insert_store_duplicate_different_values(
+; CHECK-NEXT:    [[V:%.*]] = load <8 x i16>, ptr [[P:%.*]], align 16
+; CHECK-NEXT:    [[V1:%.*]] = insertelement <8 x i16> [[V]], i16 [[A:%.*]], i32 3
+; CHECK-NEXT:    [[V2:%.*]] = insertelement <8 x i16> [[V1]], i16 [[B:%.*]], i32 3
+; CHECK-NEXT:    store <8 x i16> [[V2]], ptr [[P]], align 16
+; CHECK-NEXT:    ret void
+;
+  %v = load <8 x i16>, ptr %p
+  %v1 = insertelement <8 x i16> %v, i16 %a, i32 3
+  %v2 = insertelement <8 x i16> %v1, i16 %b, i32 3
+  store <8 x i16> %v2, ptr %p
+  ret void
+}
+
+define void @insert_store3(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store3(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 5
+; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 6
+; CHECK-NEXT:    [[VEC3:%.*]] = insertelement <8 x i16> [[VEC2]], i16 [[S]], i32 7
+; CHECK-NEXT:    store <8 x i16> [[VEC3]], ptr [[Q]], align 1
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %0, i16 %s, i32 5
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 6
+  %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 7
+  store <8 x i16> %vec3, ptr %q, align 1
+  ret void
+}
+
+define void @insert_store8(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store8(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 0
+; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 1
+; CHECK-NEXT:    [[VEC3:%.*]] = insertelement <8 x i16> [[VEC2]], i16 [[S]], i32 2
+; CHECK-NEXT:    [[VEC4:%.*]] = insertelement <8 x i16> [[VEC3]], i16 [[S]], i32 3
+; CHECK-NEXT:    [[VEC5:%.*]] = insertelement <8 x i16> [[VEC4]], i16 [[S]], i32 4
+; CHECK-NEXT:    [[VEC6:%.*]] = insertelement <8 x i16> [[VEC5]], i16 [[S]], i32 5
+; CHECK-NEXT:    [[VEC7:%.*]] = insertelement <8 x i16> [[VEC6]], i16 [[S]], i32 6
+; CHECK-NEXT:    [[VEC8:%.*]] = insertelement <8 x i16> [[VEC7]], i16 [[S]], i32 7
+; CHECK-NEXT:    store <8 x i16> [[VEC8]], ptr [[Q]], align 1
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %0, i16 %s, i32 0
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 1
+  %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 2
+  %vec4 = insertelement <8 x i16> %vec3, i16 %s, i32 3
+  %vec5 = insertelement <8 x i16> %vec4, i16 %s, i32 4
+  %vec6 = insertelement <8 x i16> %vec5, i16 %s, i32 5
+  %vec7 = insertelement <8 x i16> %vec6, i16 %s, i32 6
+  %vec8 = insertelement <8 x i16> %vec7, i16 %s, i32 7
+  store <8 x i16> %vec8, ptr %q, align 1
+  ret void
+}
+
 define void @insert_store_i16_align1(ptr %q, i16 zeroext %s) {
 ; CHECK-LABEL: @insert_store_i16_align1(
 ; CHECK-NEXT:  entry:
@@ -847,3 +927,281 @@ bb:
 
 declare i32 @bar(i32, i1) readonly
 declare double @llvm.log2.f64(double)
+
+define void @insert_store_gap(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_gap(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 2
+; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 5
+; CHECK-NEXT:    store <8 x i16> [[VEC2]], ptr [[Q]], align 16
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %0, i16 %s, i32 2
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 5
+  store <8 x i16> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_reverse(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_reverse(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 7
+; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 6
+; CHECK-NEXT:    [[VEC3:%.*]] = insertelement <8 x i16> [[VEC2]], i16 [[S]], i32 5
+; CHECK-NEXT:    store <8 x i16> [[VEC3]], ptr [[Q]], align 16
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %0, i16 %s, i32 7
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 6
+  %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 5
+  store <8 x i16> %vec3, ptr %q
+  ret void
+}
+
+define void @insert_store_duplicate(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_duplicate(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 3
+; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 3
+; CHECK-NEXT:    store <8 x i16> [[VEC2]], ptr [[Q]], align 16
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %0, i16 %s, i32 3
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 3
+  store <8 x i16> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_i32(ptr %q, i32 zeroext %s) {
+; CHECK-LABEL: @insert_store_i32(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i32>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <4 x i32> [[TMP0]], i32 [[S:%.*]], i32 2
+; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <4 x i32> [[VEC1]], i32 [[S]], i32 3
+; CHECK-NEXT:    store <4 x i32> [[VEC2]], ptr [[Q]], align 16
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = load <4 x i32>, ptr %q
+  %vec1 = insertelement <4 x i32> %0, i32 %s, i32 2
+  %vec2 = insertelement <4 x i32> %vec1, i32 %s, i32 3
+  store <4 x i32> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_i8(ptr %q, i8 zeroext %s) {
+; CHECK-LABEL: @insert_store_i8(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 8
+; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <16 x i8> [[VEC1]], i8 [[S]], i32 9
+; CHECK-NEXT:    store <16 x i8> [[VEC2]], ptr [[Q]], align 16
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = load <16 x i8>, ptr %q
+  %vec1 = insertelement <16 x i8> %0, i8 %s, i32 8
+  %vec2 = insertelement <16 x i8> %vec1, i8 %s, i32 9
+  store <16 x i8> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_alignment(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_alignment(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 0
+; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 4
+; CHECK-NEXT:    store <8 x i16> [[VEC2]], ptr [[Q]], align 16
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = load <8 x i16>, ptr %q, align 16
+  %vec1 = insertelement <8 x i16> %0, i16 %s, i32 0
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 4
+  store <8 x i16> %vec2, ptr %q, align 16
+  ret void
+}
+
+define void @insert_store_size(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_size(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i16>, ptr [[Q:%.*]], align 32
+; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <16 x i16> [[TMP0]], i16 [[S:%.*]], i32 8
+; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <16 x i16> [[VEC1]], i16 [[S]], i32 12
+; CHECK-NEXT:    store <16 x i16> [[VEC2]], ptr [[Q]], align 32
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = load <16 x i16>, ptr %q
+  %vec1 = insertelement <16 x i16> %0, i16 %s, i32 8
+  %vec2 = insertelement <16 x i16> %vec1, i16 %s, i32 12
+  store <16 x i16> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_nonconst4(ptr %q, i8 zeroext %s, i32 %idx1, i32 %idx2, i32 %idx3, i32 %idx4) {
+; CHECK-LABEL: @insert_store_nonconst4(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX1:%.*]]
+; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <16 x i8> [[VECINS1]], i8 [[S]], i32 [[IDX2:%.*]]
+; CHECK-NEXT:    [[VECINS3:%.*]] = insertelement <16 x i8> [[VECINS2]], i8 [[S]], i32 [[IDX3:%.*]]
+; CHECK-NEXT:    [[VECINS4:%.*]] = insertelement <16 x i8> [[VECINS3]], i8 [[S]], i32 [[IDX4:%.*]]
+; CHECK-NEXT:    store <16 x i8> [[VECINS4]], ptr [[Q]], align 16
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = load <16 x i8>, ptr %q
+  %vecins1 = insertelement <16 x i8> %0, i8 %s, i32 %idx1
+  %vecins2 = insertelement <16 x i8> %vecins1, i8 %s, i32 %idx2
+  %vecins3 = insertelement <16 x i8> %vecins2, i8 %s, i32 %idx3
+  %vecins4 = insertelement <16 x i8> %vecins3, i8 %s, i32 %idx4
+  store <16 x i8> %vecins4, ptr %q
+  ret void
+}
+
+define void @insert_store_vscale_nonconst2(ptr %q, i8 zeroext %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_vscale_nonconst2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load <vscale x 16 x i8>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <vscale x 16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX1:%.*]]
+; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <vscale x 16 x i8> [[VECINS1]], i8 [[S]], i32 [[IDX2:%.*]]
+; CHECK-NEXT:    store <vscale x 16 x i8> [[VECINS2]], ptr [[Q]], align 16
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = load <vscale x 16 x i8>, ptr %q
+  %vecins1 = insertelement <vscale x 16 x i8> %0, i8 %s, i32 %idx1
+  %vecins2 = insertelement <vscale x 16 x i8> %vecins1, i8 %s, i32 %idx2
+  store <vscale x 16 x i8> %vecins2, ptr %q
+  ret void
+}
+
+define void @insert_store_nonconst_large_alignment2(ptr %q, i32 zeroext %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_nonconst_large_alignment2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 4
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 4
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
+; CHECK-NEXT:    [[I:%.*]] = load <4 x i32>, ptr [[Q:%.*]], align 128
+; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <4 x i32> [[I]], i32 [[S:%.*]], i32 [[IDX1]]
+; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <4 x i32> [[VECINS1]], i32 [[S]], i32 [[IDX2]]
+; CHECK-NEXT:    store <4 x i32> [[VECINS2]], ptr [[Q]], align 128
+; CHECK-NEXT:    ret void
+;
+entry:
+  %cmp1 = icmp ult i32 %idx1, 4
+  %cmp2 = icmp ult i32 %idx2, 4
+  call void @llvm.assume(i1 %cmp1)
+  call void @llvm.assume(i1 %cmp2)
+  %i = load <4 x i32>, ptr %q, align 128
+  %vecins1 = insertelement <4 x i32> %i, i32 %s, i32 %idx1
+  %vecins2 = insertelement <4 x i32> %vecins1, i32 %s, i32 %idx2
+  store <4 x i32> %vecins2, ptr %q, align 128
+  ret void
+}
+
+define void @insert_store_nonconst_align_maximum_8_2(ptr %q, i64 %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_nonconst_align_maximum_8_2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 2
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
+; CHECK-NEXT:    [[I:%.*]] = load <8 x i64>, ptr [[Q:%.*]], align 8
+; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <8 x i64> [[I]], i64 [[S:%.*]], i32 [[IDX1]]
+; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <8 x i64> [[VECINS1]], i64 [[S]], i32 [[IDX2]]
+; CHECK-NEXT:    store <8 x i64> [[VECINS2]], ptr [[Q]], align 8
+; CHECK-NEXT:    ret void
+;
+  %cmp1 = icmp ult i32 %idx1, 2
+  %cmp2 = icmp ult i32 %idx2, 2
+  call void @llvm.assume(i1 %cmp1)
+  call void @llvm.assume(i1 %cmp2)
+  %i = load <8 x i64>, ptr %q, align 8
+  %vecins1 = insertelement <8 x i64> %i, i64 %s, i32 %idx1
+  %vecins2 = insertelement <8 x i64> %vecins1, i64 %s, i32 %idx2
+  store <8 x i64> %vecins2, ptr %q, align 8
+  ret void
+}
+
+define void @insert_store_nonconst_align_maximum_4_2(ptr %q, i64 %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_nonconst_align_maximum_4_2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 2
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
+; CHECK-NEXT:    [[I:%.*]] = load <8 x i64>, ptr [[Q:%.*]], align 4
+; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <8 x i64> [[I]], i64 [[S:%.*]], i32 [[IDX1]]
+; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <8 x i64> [[VECINS1]], i64 [[S]], i32 [[IDX2]]
+; CHECK-NEXT:    store <8 x i64> [[VECINS2]], ptr [[Q]], align 4
+; CHECK-NEXT:    ret void
+;
+  %cmp1 = icmp ult i32 %idx1, 2
+  %cmp2 = icmp ult i32 %idx2, 2
+  call void @llvm.assume(i1 %cmp1)
+  call void @llvm.assume(i1 %cmp2)
+  %i = load <8 x i64>, ptr %q, align 4
+  %vecins1 = insertelement <8 x i64> %i, i64 %s, i32 %idx1
+  %vecins2 = insertelement <8 x i64> %vecins1, i64 %s, i32 %idx2
+  store <8 x i64> %vecins2, ptr %q, align 4
+  ret void
+}
+
+define void @insert_store_nonconst_align_larger_2(ptr %q, i64 %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_nonconst_align_larger_2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 2
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
+; CHECK-NEXT:    [[I:%.*]] = load <8 x i64>, ptr [[Q:%.*]], align 4
+; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <8 x i64> [[I]], i64 [[S:%.*]], i32 [[IDX1]]
+; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <8 x i64> [[VECINS1]], i64 [[S]], i32 [[IDX2]]
+; CHECK-NEXT:    store <8 x i64> [[VECINS2]], ptr [[Q]], align 2
+; CHECK-NEXT:    ret void
+;
+  %cmp1 = icmp ult i32 %idx1, 2
+  %cmp2 = icmp ult i32 %idx2, 2
+  call void @llvm.assume(i1 %cmp1)
+  call void @llvm.assume(i1 %cmp2)
+  %i = load <8 x i64>, ptr %q, align 4
+  %vecins1 = insertelement <8 x i64> %i, i64 %s, i32 %idx1
+  %vecins2 = insertelement <8 x i64> %vecins1, i64 %s, i32 %idx2
+  store <8 x i64> %vecins2, ptr %q, align 2
+  ret void
+}
+
+define void @insert_store_dynamic_indices_may_alias(
+; CHECK-LABEL: @insert_store_dynamic_indices_may_alias(
+; CHECK-NEXT:    [[CI:%.*]] = icmp ult i32 [[I:%.*]], 8
+; CHECK-NEXT:    [[CJ:%.*]] = icmp ult i32 [[J:%.*]], 8
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CI]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CJ]])
+; CHECK-NEXT:    [[V:%.*]] = load <8 x i16>, ptr [[P:%.*]], align 16
+; CHECK-NEXT:    [[V1:%.*]] = insertelement <8 x i16> [[V]], i16 [[A:%.*]], i32 [[I]]
+; CHECK-NEXT:    [[V2:%.*]] = insertelement <8 x i16> [[V1]], i16 [[B:%.*]], i32 [[J]]
+; CHECK-NEXT:    store <8 x i16> [[V2]], ptr [[P]], align 16
+; CHECK-NEXT:    ret void
+;
+  ptr %p, i16 %a, i16 %b, i32 %i, i32 %j) {
+  %ci = icmp ult i32 %i, 8
+  %cj = icmp ult i32 %j, 8
+  call void @llvm.assume(i1 %ci)
+  call void @llvm.assume(i1 %cj)
+
+  %v = load <8 x i16>, ptr %p
+  %v1 = insertelement <8 x i16> %v, i16 %a, i32 %i
+  %v2 = insertelement <8 x i16> %v1, i16 %b, i32 %j
+  store <8 x i16> %v2, ptr %p
+  ret void
+}

>From b9a30276b3b3924a65e402a39cabb8cd2b28ed1f Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Mon, 24 Mar 2025 15:59:37 +0900
Subject: [PATCH 2/9] [VectorCombine] Support simplification to scalar store
 for multiple insertelt

Previously, we supported simplifying load-insertelt-store to getelementptr-store
when only one insertelt exists.

This patch supports multiple insertelements.

Proof: https://alive2.llvm.org/ce/z/QTspTf
Perf : https://godbolt.org/z/98zxreh7x
---
 .../Transforms/Vectorize/VectorCombine.cpp    | 150 +++++++++----
 .../VectorCombine/load-insert-store.ll        | 200 ++++++++----------
 2 files changed, 202 insertions(+), 148 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 8648125222e2a..4cf665e1b2ef3 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -131,7 +131,7 @@ class VectorCombine {
   bool foldExtractedCmps(Instruction &I);
   bool foldSelectsFromBitcast(Instruction &I);
   bool foldBinopOfReductions(Instruction &I);
-  bool foldSingleElementStore(Instruction &I);
+  bool foldInsertElementsStore(Instruction &I);
   bool scalarizeLoad(Instruction &I);
   bool scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy, Value *Ptr);
   bool scalarizeLoadBitcast(LoadInst *LI, VectorType *VecTy, Value *Ptr);
@@ -1962,62 +1962,138 @@ static Align computeAlignmentAfterScalarization(Align VectorAlignment,
 //   %0 = bitcast <4 x i32>* %a to i32*
 //   %1 = getelementptr inbounds i32, i32* %0, i64 0, i64 1
 //   store i32 %b, i32* %1
-bool VectorCombine::foldSingleElementStore(Instruction &I) {
+bool VectorCombine::foldInsertElementsStore(Instruction &I) {
   if (!TTI.allowVectorElementIndexingUsingGEP())
     return false;
+
   auto *SI = cast<StoreInst>(&I);
   if (!SI->isSimple() || !isa<VectorType>(SI->getValueOperand()->getType()))
     return false;
 
-  // TODO: Combine more complicated patterns (multiple insert) by referencing
-  // TargetTransformInfo.
-  Instruction *Source;
-  Value *NewElement;
-  Value *Idx;
-  if (!match(SI->getValueOperand(),
-             m_InsertElt(m_Instruction(Source), m_Value(NewElement),
-                         m_Value(Idx))))
-    return false;
-
-  if (auto *Load = dyn_cast<LoadInst>(Source)) {
-    auto VecTy = cast<VectorType>(SI->getValueOperand()->getType());
-    Value *SrcAddr = Load->getPointerOperand()->stripPointerCasts();
-    // Don't optimize for atomic/volatile load or store. Ensure memory is not
-    // modified between, vector type matches store size, and index is inbounds.
-    if (!Load->isSimple() || Load->getParent() != SI->getParent() ||
-        !DL->typeSizeEqualsStoreSize(Load->getType()->getScalarType()) ||
-        SrcAddr != SI->getPointerOperand()->stripPointerCasts())
-      return false;
+  Value *Source = SI->getValueOperand();
+  // Track back multiple inserts.
+  SmallVector<std::pair<Value *, Value *>, 4> InsertElements;
+  Value *Base = Source;
+  while (auto *Insert = dyn_cast<InsertElementInst>(Base)) {
+    if (!Insert->hasOneUse())
+      break;
+    Value *InsertVal = Insert->getOperand(1);
+    Value *Idx = Insert->getOperand(2);
+    InsertElements.push_back({InsertVal, Idx});
+    Base = Insert->getOperand(0);
+  }
 
-    if (isMemModifiedBetween(Load->getIterator(), SI->getIterator(),
-                             MemoryLocation::get(SI), AA))
-      return false;
+  if (InsertElements.empty())
+    return false;
+
+  // The chain is collected from the final insertelement back to the base load.
+  // Emit scalar stores in original program order to preserve semantics for
+  // duplicate or dynamically equal indices.
+  std::reverse(InsertElements.begin(), InsertElements.end());
+  auto *Load = dyn_cast<LoadInst>(Base);
+  if (!Load)
+    return false;
+  auto VecTy = cast<VectorType>(SI->getValueOperand()->getType());
+  if (auto *FVT = dyn_cast<FixedVectorType>(VecTy)) {
+    if (InsertElements.size() == FVT->getNumElements()) {
+      Value *FirstVal = InsertElements.front().first;
+      if (all_of(InsertElements,
+                 [FirstVal](const auto &Elt) { return Elt.first == FirstVal; }))
+        return false;
+    }
+  }
+  Value *SrcAddr = Load->getPointerOperand()->stripPointerCasts();
+  // Don't optimize for atomic/volatile load or store. Ensure memory is not
+  // modified between, vector type matches store size, and index is inbounds.
+  if (!Load->isSimple() || Load->getParent() != SI->getParent() ||
+      !DL->typeSizeEqualsStoreSize(Load->getType()->getScalarType()) ||
+      SrcAddr != SI->getPointerOperand()->stripPointerCasts())
+    return false;
+
+  if (isMemModifiedBetween(Load->getIterator(), SI->getIterator(),
+                           MemoryLocation::get(SI), AA))
+    return false;
+
+  for (auto [InsertVal, Idx] : InsertElements) {
     auto ScalarizableIdx =
-        canScalarizeAccess(VecTy, Idx, SQ.getWithInstruction(Load));
+        canScalarizeAccess(VecTy, Idx, SQ.getWithInstruction(&I));
     if (ScalarizableIdx.isUnsafe())
       return false;
 
-    // Ensure we add the load back to the worklist BEFORE its users so they can
-    // erased in the correct order.
-    Worklist.push(Load);
+    // We are only checking legality here. Do not mutate IR before the
+    // profitability check, but also do not leave a pending ToFreeze behind.
+    ScalarizableIdx.discard();
+  }
+  InstructionCost OldCost = TTI.getMemoryOpCost(
+      Instruction::Store, SI->getValueOperand()->getType(), SI->getAlign(),
+      SI->getPointerAddressSpace(), CostKind);
+
+  if (Load->hasOneUse())
+    OldCost += TTI.getMemoryOpCost(Instruction::Load, Load->getType(),
+                                   Load->getAlign(),
+                                   Load->getPointerAddressSpace(), CostKind);
+
+  for (auto [InsertVal, Idx] : InsertElements) {
+    int Index = -1;
+    if (auto *CIdx = dyn_cast<ConstantInt>(Idx))
+      Index = CIdx->getZExtValue();
+
+    OldCost += TTI.getVectorInstrCost(Instruction::InsertElement, VecTy,
+                                      CostKind, Index);
+  }
+
+  InstructionCost NewCost = 0;
+  for (auto [InsertVal, Idx] : InsertElements) {
+    Align ScalarOpAlignment = computeAlignmentAfterScalarization(
+        std::max(SI->getAlign(), Load->getAlign()), InsertVal->getType(), Idx,
+        *DL);
+
+    NewCost += TTI.getMemoryOpCost(Instruction::Store, InsertVal->getType(),
+                                   ScalarOpAlignment,
+                                   SI->getPointerAddressSpace(), CostKind);
+  }
+
+  LLVM_DEBUG(dbgs() << "Found an insert-elements vector store scalarization "
+                       "candidate: "
+                    << I << "\n"
+                    << "  NumInserts: " << InsertElements.size() << "\n"
+                    << "  OldCost: " << OldCost << " vs NewCost: " << NewCost
+                    << "\n");
+
+  if (OldCost <= NewCost)
+    return false;
+
+  // Now we know the transform is profitable. It is safe to mutate IR.
+  for (auto [InsertVal, Idx] : InsertElements) {
+    auto ScalarizableIdx =
+        canScalarizeAccess(VecTy, Idx, SQ.getWithInstruction(Load));
+    assert(!ScalarizableIdx.isUnsafe() && "already checked above");
 
     if (ScalarizableIdx.isSafeWithFreeze())
       ScalarizableIdx.freeze(Builder, *cast<Instruction>(Idx));
+  }
+
+  // Ensure we add the load back to the worklist BEFORE its users so they can
+  // erased in the correct order.
+  Worklist.push(Load);
+  StoreInst *LastStore = nullptr;
+  for (auto [InsertVal, Idx] : InsertElements) {
     Value *GEP = Builder.CreateInBoundsGEP(
         SI->getValueOperand()->getType(), SI->getPointerOperand(),
         {ConstantInt::get(Idx->getType(), 0), Idx});
-    StoreInst *NSI = Builder.CreateStore(NewElement, GEP);
-    NSI->copyMetadata(*SI);
+
+    LastStore = Builder.CreateStore(InsertVal, GEP);
+    LastStore->copyMetadata(*SI);
+
     Align ScalarOpAlignment = computeAlignmentAfterScalarization(
-        std::max(SI->getAlign(), Load->getAlign()), NewElement->getType(), Idx,
+        std::max(SI->getAlign(), Load->getAlign()), InsertVal->getType(), Idx,
         *DL);
-    NSI->setAlignment(ScalarOpAlignment);
-    replaceValue(I, *NSI);
-    eraseInstruction(I);
-    return true;
+    LastStore->setAlignment(ScalarOpAlignment);
   }
 
-  return false;
+  replaceValue(I, *LastStore);
+  eraseInstruction(I);
+  return true;
 }
 
 /// Try to scalarize vector loads feeding extractelement or bitcast
@@ -6454,7 +6530,7 @@ bool VectorCombine::run() {
       return true;
 
     if (Opcode == Instruction::Store)
-      if (foldSingleElementStore(I))
+      if (foldInsertElementsStore(I))
         return true;
 
     // If this is an early pipeline invocation of this pass, we are done.
diff --git a/llvm/test/Transforms/VectorCombine/load-insert-store.ll b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
index 2e86ac23b82f3..9569979ca86a7 100644
--- a/llvm/test/Transforms/VectorCombine/load-insert-store.ll
+++ b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
@@ -18,27 +18,25 @@ entry:
 
 define void @insert_store2(ptr %q, i16 zeroext %s) {
 ; CHECK-LABEL: @insert_store2(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
-; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 6
-; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 7
-; CHECK-NEXT:    store <8 x i16> [[VEC2]], ptr [[Q]], align 1
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 6
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 7
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 2
 ; CHECK-NEXT:    ret void
 ;
-entry:
-  %0 = load <8 x i16>, ptr %q
-  %vec1 = insertelement <8 x i16> %0, i16 %s, i32 6
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 6
   %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 7
   store <8 x i16> %vec2, ptr %q, align 1
   ret void
 }
 
 define void @insert_store2_duplicate_different_values(ptr %p, i16 %a, i16 %b) {
-; CHECK-LABEL: @insert_store_duplicate_different_values(
-; CHECK-NEXT:    [[V:%.*]] = load <8 x i16>, ptr [[P:%.*]], align 16
-; CHECK-NEXT:    [[V1:%.*]] = insertelement <8 x i16> [[V]], i16 [[A:%.*]], i32 3
-; CHECK-NEXT:    [[V2:%.*]] = insertelement <8 x i16> [[V1]], i16 [[B:%.*]], i32 3
-; CHECK-NEXT:    store <8 x i16> [[V2]], ptr [[P]], align 16
+; CHECK-LABEL: @insert_store2_duplicate_different_values(
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[A:%.*]], ptr [[TMP1]], align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[B:%.*]], ptr [[TMP2]], align 2
 ; CHECK-NEXT:    ret void
 ;
   %v = load <8 x i16>, ptr %p
@@ -50,17 +48,16 @@ define void @insert_store2_duplicate_different_values(ptr %p, i16 %a, i16 %b) {
 
 define void @insert_store3(ptr %q, i16 zeroext %s) {
 ; CHECK-LABEL: @insert_store3(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
-; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 5
-; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 6
-; CHECK-NEXT:    [[VEC3:%.*]] = insertelement <8 x i16> [[VEC2]], i16 [[S]], i32 7
-; CHECK-NEXT:    store <8 x i16> [[VEC3]], ptr [[Q]], align 1
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 5
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 6
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 7
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP2]], align 2
 ; CHECK-NEXT:    ret void
 ;
-entry:
-  %0 = load <8 x i16>, ptr %q
-  %vec1 = insertelement <8 x i16> %0, i16 %s, i32 5
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 5
   %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 6
   %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 7
   store <8 x i16> %vec3, ptr %q, align 1
@@ -69,7 +66,6 @@ entry:
 
 define void @insert_store8(ptr %q, i16 zeroext %s) {
 ; CHECK-LABEL: @insert_store8(
-; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
 ; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 0
 ; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 1
@@ -82,9 +78,8 @@ define void @insert_store8(ptr %q, i16 zeroext %s) {
 ; CHECK-NEXT:    store <8 x i16> [[VEC8]], ptr [[Q]], align 1
 ; CHECK-NEXT:    ret void
 ;
-entry:
-  %0 = load <8 x i16>, ptr %q
-  %vec1 = insertelement <8 x i16> %0, i16 %s, i32 0
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 0
   %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 1
   %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 2
   %vec4 = insertelement <8 x i16> %vec3, i16 %s, i32 3
@@ -930,16 +925,14 @@ declare double @llvm.log2.f64(double)
 
 define void @insert_store_gap(ptr %q, i16 zeroext %s) {
 ; CHECK-LABEL: @insert_store_gap(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
-; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 2
-; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 5
-; CHECK-NEXT:    store <8 x i16> [[VEC2]], ptr [[Q]], align 16
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 2
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 5
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 2
 ; CHECK-NEXT:    ret void
 ;
-entry:
-  %0 = load <8 x i16>, ptr %q
-  %vec1 = insertelement <8 x i16> %0, i16 %s, i32 2
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 2
   %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 5
   store <8 x i16> %vec2, ptr %q
   ret void
@@ -947,17 +940,16 @@ entry:
 
 define void @insert_store_reverse(ptr %q, i16 zeroext %s) {
 ; CHECK-LABEL: @insert_store_reverse(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
-; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 7
-; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 6
-; CHECK-NEXT:    [[VEC3:%.*]] = insertelement <8 x i16> [[VEC2]], i16 [[S]], i32 5
-; CHECK-NEXT:    store <8 x i16> [[VEC3]], ptr [[Q]], align 16
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 7
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 6
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 5
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP2]], align 2
 ; CHECK-NEXT:    ret void
 ;
-entry:
-  %0 = load <8 x i16>, ptr %q
-  %vec1 = insertelement <8 x i16> %0, i16 %s, i32 7
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 7
   %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 6
   %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 5
   store <8 x i16> %vec3, ptr %q
@@ -966,16 +958,14 @@ entry:
 
 define void @insert_store_duplicate(ptr %q, i16 zeroext %s) {
 ; CHECK-LABEL: @insert_store_duplicate(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
-; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 3
-; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 3
-; CHECK-NEXT:    store <8 x i16> [[VEC2]], ptr [[Q]], align 16
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 2
 ; CHECK-NEXT:    ret void
 ;
-entry:
-  %0 = load <8 x i16>, ptr %q
-  %vec1 = insertelement <8 x i16> %0, i16 %s, i32 3
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 3
   %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 3
   store <8 x i16> %vec2, ptr %q
   ret void
@@ -983,16 +973,14 @@ entry:
 
 define void @insert_store_i32(ptr %q, i32 zeroext %s) {
 ; CHECK-LABEL: @insert_store_i32(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = load <4 x i32>, ptr [[Q:%.*]], align 16
-; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <4 x i32> [[TMP0]], i32 [[S:%.*]], i32 2
-; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <4 x i32> [[VEC1]], i32 [[S]], i32 3
-; CHECK-NEXT:    store <4 x i32> [[VEC2]], ptr [[Q]], align 16
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q:%.*]], i32 0, i32 2
+; CHECK-NEXT:    store i32 [[S:%.*]], ptr [[TMP0]], align 8
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q]], i32 0, i32 3
+; CHECK-NEXT:    store i32 [[S]], ptr [[TMP1]], align 4
 ; CHECK-NEXT:    ret void
 ;
-entry:
-  %0 = load <4 x i32>, ptr %q
-  %vec1 = insertelement <4 x i32> %0, i32 %s, i32 2
+  %load = load <4 x i32>, ptr %q
+  %vec1 = insertelement <4 x i32> %load, i32 %s, i32 2
   %vec2 = insertelement <4 x i32> %vec1, i32 %s, i32 3
   store <4 x i32> %vec2, ptr %q
   ret void
@@ -1000,16 +988,14 @@ entry:
 
 define void @insert_store_i8(ptr %q, i8 zeroext %s) {
 ; CHECK-LABEL: @insert_store_i8(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
-; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 8
-; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <16 x i8> [[VEC1]], i8 [[S]], i32 9
-; CHECK-NEXT:    store <16 x i8> [[VEC2]], ptr [[Q]], align 16
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 8
+; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 8
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q]], i32 0, i32 9
+; CHECK-NEXT:    store i8 [[S]], ptr [[TMP1]], align 1
 ; CHECK-NEXT:    ret void
 ;
-entry:
-  %0 = load <16 x i8>, ptr %q
-  %vec1 = insertelement <16 x i8> %0, i8 %s, i32 8
+  %load = load <16 x i8>, ptr %q
+  %vec1 = insertelement <16 x i8> %load, i8 %s, i32 8
   %vec2 = insertelement <16 x i8> %vec1, i8 %s, i32 9
   store <16 x i8> %vec2, ptr %q
   ret void
@@ -1017,16 +1003,13 @@ entry:
 
 define void @insert_store_alignment(ptr %q, i16 zeroext %s) {
 ; CHECK-LABEL: @insert_store_alignment(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
-; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 0
-; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 4
-; CHECK-NEXT:    store <8 x i16> [[VEC2]], ptr [[Q]], align 16
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0:%.*]], align 16
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[TMP0]], i32 0, i32 4
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 8
 ; CHECK-NEXT:    ret void
 ;
-entry:
-  %0 = load <8 x i16>, ptr %q, align 16
-  %vec1 = insertelement <8 x i16> %0, i16 %s, i32 0
+  %load = load <8 x i16>, ptr %q, align 16
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 0
   %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 4
   store <8 x i16> %vec2, ptr %q, align 16
   ret void
@@ -1035,15 +1018,15 @@ entry:
 define void @insert_store_size(ptr %q, i16 zeroext %s) {
 ; CHECK-LABEL: @insert_store_size(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i16>, ptr [[Q:%.*]], align 32
-; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <16 x i16> [[TMP0]], i16 [[S:%.*]], i32 8
-; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <16 x i16> [[VEC1]], i16 [[S]], i32 12
-; CHECK-NEXT:    store <16 x i16> [[VEC2]], ptr [[Q]], align 32
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i16>, ptr [[Q:%.*]], i32 0, i32 8
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 16
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i16>, ptr [[Q]], i32 0, i32 12
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 8
 ; CHECK-NEXT:    ret void
 ;
 entry:
-  %0 = load <16 x i16>, ptr %q
-  %vec1 = insertelement <16 x i16> %0, i16 %s, i32 8
+  %load = load <16 x i16>, ptr %q
+  %vec1 = insertelement <16 x i16> %load, i16 %s, i32 8
   %vec2 = insertelement <16 x i16> %vec1, i16 %s, i32 12
   store <16 x i16> %vec2, ptr %q
   ret void
@@ -1061,8 +1044,8 @@ define void @insert_store_nonconst4(ptr %q, i8 zeroext %s, i32 %idx1, i32 %idx2,
 ; CHECK-NEXT:    ret void
 ;
 entry:
-  %0 = load <16 x i8>, ptr %q
-  %vecins1 = insertelement <16 x i8> %0, i8 %s, i32 %idx1
+  %load = load <16 x i8>, ptr %q
+  %vecins1 = insertelement <16 x i8> %load, i8 %s, i32 %idx1
   %vecins2 = insertelement <16 x i8> %vecins1, i8 %s, i32 %idx2
   %vecins3 = insertelement <16 x i8> %vecins2, i8 %s, i32 %idx3
   %vecins4 = insertelement <16 x i8> %vecins3, i8 %s, i32 %idx4
@@ -1072,16 +1055,14 @@ entry:
 
 define void @insert_store_vscale_nonconst2(ptr %q, i8 zeroext %s, i32 %idx1, i32 %idx2) {
 ; CHECK-LABEL: @insert_store_vscale_nonconst2(
-; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[TMP0:%.*]] = load <vscale x 16 x i8>, ptr [[Q:%.*]], align 16
 ; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <vscale x 16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX1:%.*]]
 ; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <vscale x 16 x i8> [[VECINS1]], i8 [[S]], i32 [[IDX2:%.*]]
 ; CHECK-NEXT:    store <vscale x 16 x i8> [[VECINS2]], ptr [[Q]], align 16
 ; CHECK-NEXT:    ret void
 ;
-entry:
-  %0 = load <vscale x 16 x i8>, ptr %q
-  %vecins1 = insertelement <vscale x 16 x i8> %0, i8 %s, i32 %idx1
+  %load = load <vscale x 16 x i8>, ptr %q
+  %vecins1 = insertelement <vscale x 16 x i8> %load, i8 %s, i32 %idx1
   %vecins2 = insertelement <vscale x 16 x i8> %vecins1, i8 %s, i32 %idx2
   store <vscale x 16 x i8> %vecins2, ptr %q
   ret void
@@ -1089,18 +1070,16 @@ entry:
 
 define void @insert_store_nonconst_large_alignment2(ptr %q, i32 zeroext %s, i32 %idx1, i32 %idx2) {
 ; CHECK-LABEL: @insert_store_nonconst_large_alignment2(
-; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 4
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 4
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
-; CHECK-NEXT:    [[I:%.*]] = load <4 x i32>, ptr [[Q:%.*]], align 128
-; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <4 x i32> [[I]], i32 [[S:%.*]], i32 [[IDX1]]
-; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <4 x i32> [[VECINS1]], i32 [[S]], i32 [[IDX2]]
-; CHECK-NEXT:    store <4 x i32> [[VECINS2]], ptr [[Q]], align 128
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
+; CHECK-NEXT:    store i32 [[S:%.*]], ptr [[TMP0]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q]], i32 0, i32 [[IDX2]]
+; CHECK-NEXT:    store i32 [[S]], ptr [[TMP1]], align 4
 ; CHECK-NEXT:    ret void
 ;
-entry:
   %cmp1 = icmp ult i32 %idx1, 4
   %cmp2 = icmp ult i32 %idx2, 4
   call void @llvm.assume(i1 %cmp1)
@@ -1118,10 +1097,10 @@ define void @insert_store_nonconst_align_maximum_8_2(ptr %q, i64 %s, i32 %idx1,
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
-; CHECK-NEXT:    [[I:%.*]] = load <8 x i64>, ptr [[Q:%.*]], align 8
-; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <8 x i64> [[I]], i64 [[S:%.*]], i32 [[IDX1]]
-; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <8 x i64> [[VECINS1]], i64 [[S]], i32 [[IDX2]]
-; CHECK-NEXT:    store <8 x i64> [[VECINS2]], ptr [[Q]], align 8
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
+; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 8
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q]], i32 0, i32 [[IDX2]]
+; CHECK-NEXT:    store i64 [[S]], ptr [[TMP2]], align 8
 ; CHECK-NEXT:    ret void
 ;
   %cmp1 = icmp ult i32 %idx1, 2
@@ -1141,10 +1120,10 @@ define void @insert_store_nonconst_align_maximum_4_2(ptr %q, i64 %s, i32 %idx1,
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
-; CHECK-NEXT:    [[I:%.*]] = load <8 x i64>, ptr [[Q:%.*]], align 4
-; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <8 x i64> [[I]], i64 [[S:%.*]], i32 [[IDX1]]
-; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <8 x i64> [[VECINS1]], i64 [[S]], i32 [[IDX2]]
-; CHECK-NEXT:    store <8 x i64> [[VECINS2]], ptr [[Q]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
+; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q]], i32 0, i32 [[IDX2]]
+; CHECK-NEXT:    store i64 [[S]], ptr [[TMP2]], align 4
 ; CHECK-NEXT:    ret void
 ;
   %cmp1 = icmp ult i32 %idx1, 2
@@ -1164,10 +1143,10 @@ define void @insert_store_nonconst_align_larger_2(ptr %q, i64 %s, i32 %idx1, i32
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
-; CHECK-NEXT:    [[I:%.*]] = load <8 x i64>, ptr [[Q:%.*]], align 4
-; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <8 x i64> [[I]], i64 [[S:%.*]], i32 [[IDX1]]
-; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <8 x i64> [[VECINS1]], i64 [[S]], i32 [[IDX2]]
-; CHECK-NEXT:    store <8 x i64> [[VECINS2]], ptr [[Q]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
+; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q]], i32 0, i32 [[IDX2]]
+; CHECK-NEXT:    store i64 [[S]], ptr [[TMP2]], align 4
 ; CHECK-NEXT:    ret void
 ;
   %cmp1 = icmp ult i32 %idx1, 2
@@ -1181,19 +1160,18 @@ define void @insert_store_nonconst_align_larger_2(ptr %q, i64 %s, i32 %idx1, i32
   ret void
 }
 
-define void @insert_store_dynamic_indices_may_alias(
+define void @insert_store_dynamic_indices_may_alias(ptr %p, i16 %a, i16 %b, i32 %i, i32 %j) {
 ; CHECK-LABEL: @insert_store_dynamic_indices_may_alias(
 ; CHECK-NEXT:    [[CI:%.*]] = icmp ult i32 [[I:%.*]], 8
 ; CHECK-NEXT:    [[CJ:%.*]] = icmp ult i32 [[J:%.*]], 8
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CI]])
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CJ]])
-; CHECK-NEXT:    [[V:%.*]] = load <8 x i16>, ptr [[P:%.*]], align 16
-; CHECK-NEXT:    [[V1:%.*]] = insertelement <8 x i16> [[V]], i16 [[A:%.*]], i32 [[I]]
-; CHECK-NEXT:    [[V2:%.*]] = insertelement <8 x i16> [[V1]], i16 [[B:%.*]], i32 [[J]]
-; CHECK-NEXT:    store <8 x i16> [[V2]], ptr [[P]], align 16
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 [[I]]
+; CHECK-NEXT:    store i16 [[A:%.*]], ptr [[TMP1]], align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 [[J]]
+; CHECK-NEXT:    store i16 [[B:%.*]], ptr [[TMP2]], align 2
 ; CHECK-NEXT:    ret void
 ;
-  ptr %p, i16 %a, i16 %b, i32 %i, i32 %j) {
   %ci = icmp ult i32 %i, 8
   %cj = icmp ult i32 %j, 8
   call void @llvm.assume(i1 %ci)

>From dc5019e5229eb6c0d2db2668fa1abe5ff460bf30 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Sat, 11 Jul 2026 00:06:19 +0900
Subject: [PATCH 3/9] check more common targets

---
 llvm/test/Transforms/VectorCombine/load-insert-store.ll | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/llvm/test/Transforms/VectorCombine/load-insert-store.ll b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
index 9569979ca86a7..03471f18d170b 100644
--- a/llvm/test/Transforms/VectorCombine/load-insert-store.ll
+++ b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
@@ -1,6 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -passes=vector-combine -data-layout=e < %s | FileCheck %s
-; RUN: opt -S -passes=vector-combine -data-layout=E < %s | FileCheck %s
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64 < %s | FileCheck %s --check-prefixes=CHECK,X64
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v2 < %s | FileCheck %s --check-prefixes=CHECK,X64V2
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v3 < %s | FileCheck %s --check-prefixes=CHECK,X64V3
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %s | FileCheck %s --check-prefixes=CHECK,X64V4
 
 define void @insert_store(ptr %q, i8 zeroext %s) {
 ; CHECK-LABEL: @insert_store(

>From abf15dc74f4fb2cf32a4dab2b4161b7d1bfd1c30 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Sat, 11 Jul 2026 00:20:55 +0900
Subject: [PATCH 4/9] add testcase for freeze case

---
 .../VectorCombine/load-insert-store.ll        | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/llvm/test/Transforms/VectorCombine/load-insert-store.ll b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
index 03471f18d170b..8601a4eebcb44 100644
--- a/llvm/test/Transforms/VectorCombine/load-insert-store.ll
+++ b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
@@ -810,6 +810,24 @@ define void @insert_store_mem_modify_nonconst_index(ptr %p, i8 %s) {
   ret void
 }
 
+define void @insert_store_multi_nonconst_index_freeze(ptr %p, i8 %s, i8 %x, i8 %y) {
+; CHECK-LABEL: @insert_store_multi_nonconst_index_freeze(
+; CHECK-NEXT:    [[S_FROZEN:%.*]] = freeze i8 [[S:%.*]]
+; CHECK-NEXT:    [[IDX:%.*]] = and i8 [[S_FROZEN]], 1
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds <4 x i8>, ptr [[P:%.*]], i8 0, i8 [[IDX]]
+; CHECK-NEXT:    store i8 [[X:%.*]], ptr [[GEP1]], align 1
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <4 x i8>, ptr [[P]], i32 0, i32 2
+; CHECK-NEXT:    store i8 [[Y:%.*]], ptr [[TMP2]], align 2
+; CHECK-NEXT:    ret void
+;
+  %ld = load <4 x i8>, ptr %p, align 4
+  %idx = and i8 %s, 1
+  %ins0 = insertelement <4 x i8> %ld, i8 %x, i8 %idx
+  %ins1 = insertelement <4 x i8> %ins0, i8 %y, i32 2
+  store <4 x i8> %ins1, ptr %p, align 4
+  ret void
+}
+
 ; Check cases when calls may modify memory
 define void @insert_store_with_call(ptr %p, ptr %q, i8 %s) {
 ; CHECK-LABEL: @insert_store_with_call(
@@ -1185,3 +1203,8 @@ define void @insert_store_dynamic_indices_may_alias(ptr %p, i16 %a, i16 %b, i32
   store <8 x i16> %v2, ptr %p
   ret void
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; X64: {{.*}}
+; X64V2: {{.*}}
+; X64V3: {{.*}}
+; X64V4: {{.*}}

>From bef337406c2ed66e65ca7730d7b345d3cffe5e30 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Mon, 13 Jul 2026 16:55:19 +0900
Subject: [PATCH 5/9] visualized the function documentation comments

---
 .../Transforms/Vectorize/VectorCombine.cpp    | 70 +++++++++++++------
 1 file changed, 50 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 4cf665e1b2ef3..a3edd53932fc7 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -131,7 +131,7 @@ class VectorCombine {
   bool foldExtractedCmps(Instruction &I);
   bool foldSelectsFromBitcast(Instruction &I);
   bool foldBinopOfReductions(Instruction &I);
-  bool foldInsertElementsStore(Instruction &I);
+  bool foldInsertElementsToStores(Instruction &I);
   bool scalarizeLoad(Instruction &I);
   bool scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy, Value *Ptr);
   bool scalarizeLoadBitcast(LoadInst *LI, VectorType *VecTy, Value *Ptr);
@@ -1954,15 +1954,40 @@ static Align computeAlignmentAfterScalarization(Align VectorAlignment,
   return commonAlignment(VectorAlignment, DL.getTypeStoreSize(ScalarType));
 }
 
-// Combine patterns like:
-//   %0 = load <4 x i32>, <4 x i32>* %a
-//   %1 = insertelement <4 x i32> %0, i32 %b, i32 1
-//   store <4 x i32> %1, <4 x i32>* %a
-// to:
-//   %0 = bitcast <4 x i32>* %a to i32*
-//   %1 = getelementptr inbounds i32, i32* %0, i64 0, i64 1
-//   store i32 %b, i32* %1
-bool VectorCombine::foldInsertElementsStore(Instruction &I) {
+/// Fold a vector store fed by a single-use insertelement chain into scalar
+/// stores.
+///
+/// Before:
+///
+///   %p --> vector load --> insert %x, lane 1 --> insert %y, lane 3
+///                                                      |
+///                                                      v
+///                                              vector store to %p
+///
+///   Vector lanes:        [ 0 ] [ 1 ] [ 2 ] [ 3 ]
+///   Stored value:        [ old |  x  | old |  y  ]  (one vector store)
+///
+/// After:
+///
+///                  +--> GEP(%p, lane 1) --> store %x
+///   %p -------------+
+///                  +--> GEP(%p, lane 3) --> store %y
+///
+///   Vector lanes:        [ 0 ] [ 1 ] [ 2 ] [ 3 ]
+///   Scalar stores:              x             y
+///                            store at 1       store at 3
+///
+///   Step 1. Gate:
+///        target supports vector-element GEP addressing
+///
+///   Step 2. Trace:
+///        vector store <-- insertelement <-- ... <-- insertelement <-- load
+///
+///   Steps 3-5. Validate:
+///        reject unprofitable full overwrites; require simple accesses, a common
+///        address/block, no memory write in between, and scalarizable indices.
+bool VectorCombine::foldInsertElementsToStores(Instruction &I) {
+  // Step 1: The target must support addressing a vector element with a GEP.
   if (!TTI.allowVectorElementIndexingUsingGEP())
     return false;
 
@@ -1970,8 +1995,9 @@ bool VectorCombine::foldInsertElementsStore(Instruction &I) {
   if (!SI->isSimple() || !isa<VectorType>(SI->getValueOperand()->getType()))
     return false;
 
+  // Step 2: Collect a single-use insertelement chain, starting at the vector
+  // store and walking back to the candidate load.
   Value *Source = SI->getValueOperand();
-  // Track back multiple inserts.
   SmallVector<std::pair<Value *, Value *>, 4> InsertElements;
   Value *Base = Source;
   while (auto *Insert = dyn_cast<InsertElementInst>(Base)) {
@@ -1986,14 +2012,16 @@ bool VectorCombine::foldInsertElementsStore(Instruction &I) {
   if (InsertElements.empty())
     return false;
 
-  // The chain is collected from the final insertelement back to the base load.
-  // Emit scalar stores in original program order to preserve semantics for
-  // duplicate or dynamically equal indices.
+  // The backwards walk collected the inserts in reverse program order. Restore
+  // it now so later scalar stores preserve writes to duplicate/equal indices.
   std::reverse(InsertElements.begin(), InsertElements.end());
   auto *Load = dyn_cast<LoadInst>(Base);
   if (!Load)
     return false;
   auto VecTy = cast<VectorType>(SI->getValueOperand()->getType());
+
+  // Step 3: Avoid replacing a complete overwrite with scalar stores when every
+  // lane receives the same value; keeping the vector operation is preferable.
   if (auto *FVT = dyn_cast<FixedVectorType>(VecTy)) {
     if (InsertElements.size() == FVT->getNumElements()) {
       Value *FirstVal = InsertElements.front().first;
@@ -2003,8 +2031,9 @@ bool VectorCombine::foldInsertElementsStore(Instruction &I) {
     }
   }
   Value *SrcAddr = Load->getPointerOperand()->stripPointerCasts();
-  // Don't optimize for atomic/volatile load or store. Ensure memory is not
-  // modified between, vector type matches store size, and index is inbounds.
+  // Step 4: Establish the load/store update is legal: both accesses are simple,
+  // have the same base address and block, have scalar-sized elements, and no
+  // intervening operation modifies the updated memory.
   if (!Load->isSimple() || Load->getParent() != SI->getParent() ||
       !DL->typeSizeEqualsStoreSize(Load->getType()->getScalarType()) ||
       SrcAddr != SI->getPointerOperand()->stripPointerCasts())
@@ -2014,6 +2043,9 @@ bool VectorCombine::foldInsertElementsStore(Instruction &I) {
                            MemoryLocation::get(SI), AA))
     return false;
 
+  // Step 5: Validate every index before changing IR. A safe-with-freeze result
+  // is recorded by ScalarizationResult, so discard it until profitability is
+  // known; otherwise a rejected candidate could leave a freeze behind.
   for (auto [InsertVal, Idx] : InsertElements) {
     auto ScalarizableIdx =
         canScalarizeAccess(VecTy, Idx, SQ.getWithInstruction(&I));
@@ -2024,6 +2056,7 @@ bool VectorCombine::foldInsertElementsStore(Instruction &I) {
     // profitability check, but also do not leave a pending ToFreeze behind.
     ScalarizableIdx.discard();
   }
+
   InstructionCost OldCost = TTI.getMemoryOpCost(
       Instruction::Store, SI->getValueOperand()->getType(), SI->getAlign(),
       SI->getPointerAddressSpace(), CostKind);
@@ -2063,7 +2096,6 @@ bool VectorCombine::foldInsertElementsStore(Instruction &I) {
   if (OldCost <= NewCost)
     return false;
 
-  // Now we know the transform is profitable. It is safe to mutate IR.
   for (auto [InsertVal, Idx] : InsertElements) {
     auto ScalarizableIdx =
         canScalarizeAccess(VecTy, Idx, SQ.getWithInstruction(Load));
@@ -2073,8 +2105,6 @@ bool VectorCombine::foldInsertElementsStore(Instruction &I) {
       ScalarizableIdx.freeze(Builder, *cast<Instruction>(Idx));
   }
 
-  // Ensure we add the load back to the worklist BEFORE its users so they can
-  // erased in the correct order.
   Worklist.push(Load);
   StoreInst *LastStore = nullptr;
   for (auto [InsertVal, Idx] : InsertElements) {
@@ -6530,7 +6560,7 @@ bool VectorCombine::run() {
       return true;
 
     if (Opcode == Instruction::Store)
-      if (foldInsertElementsStore(I))
+      if (foldInsertElementsToStores(I))
         return true;
 
     // If this is an early pipeline invocation of this pass, we are done.

>From bd9c951553f62d92a0ba8259f04c5e24bcc3d32c Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Mon, 13 Jul 2026 16:55:54 +0900
Subject: [PATCH 6/9] update testcases

---
 .../AArch64/load-insert-store.ll              | 39 ++++++++++++++++++
 .../VectorCombine/X86/load-insert-store.ll    | 41 +++++++++++++++++++
 .../VectorCombine/load-insert-store.ll        | 12 ++----
 3 files changed, 83 insertions(+), 9 deletions(-)
 create mode 100644 llvm/test/Transforms/VectorCombine/AArch64/load-insert-store.ll
 create mode 100644 llvm/test/Transforms/VectorCombine/X86/load-insert-store.ll

diff --git a/llvm/test/Transforms/VectorCombine/AArch64/load-insert-store.ll b/llvm/test/Transforms/VectorCombine/AArch64/load-insert-store.ll
new file mode 100644
index 0000000000000..c2ef3aa0daff0
--- /dev/null
+++ b/llvm/test/Transforms/VectorCombine/AArch64/load-insert-store.ll
@@ -0,0 +1,39 @@
+; RUN: opt -S -passes=vector-combine -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s
+; RUN: opt -S -passes=vector-combine -mtriple=aarch64_be-unknown-linux-gnu < %s | FileCheck %s
+
+; Use real little- and big-endian targets to verify that an insertelement lane
+; is scalarized to the same memory element on both byte orders.
+define void @insert_store2(ptr %p, i16 %x, i16 %y) {
+; CHECK-LABEL: @insert_store2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[GEP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 6
+; CHECK-NEXT:    store i16 [[X:%.*]], ptr [[GEP0]], align 1
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 7
+; CHECK-NEXT:    store i16 [[Y:%.*]], ptr [[GEP1]], align 1
+; CHECK-NEXT:    ret void
+;
+entry:
+  %load = load <8 x i16>, ptr %p, align 1
+  %insert0 = insertelement <8 x i16> %load, i16 %x, i32 6
+  %insert1 = insertelement <8 x i16> %insert0, i16 %y, i32 7
+  store <8 x i16> %insert1, ptr %p, align 1
+  ret void
+}
+
+; A duplicate lane must still be written in insertion order on both targets.
+define void @insert_store_duplicate(ptr %p, i16 %x, i16 %y) {
+; CHECK-LABEL: @insert_store_duplicate(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[GEP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[X:%.*]], ptr [[GEP0]], align 1
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[Y:%.*]], ptr [[GEP1]], align 1
+; CHECK-NEXT:    ret void
+;
+entry:
+  %load = load <8 x i16>, ptr %p, align 1
+  %insert0 = insertelement <8 x i16> %load, i16 %x, i32 3
+  %insert1 = insertelement <8 x i16> %insert0, i16 %y, i32 3
+  store <8 x i16> %insert1, ptr %p, align 1
+  ret void
+}
diff --git a/llvm/test/Transforms/VectorCombine/X86/load-insert-store.ll b/llvm/test/Transforms/VectorCombine/X86/load-insert-store.ll
new file mode 100644
index 0000000000000..b68389d0f1372
--- /dev/null
+++ b/llvm/test/Transforms/VectorCombine/X86/load-insert-store.ll
@@ -0,0 +1,41 @@
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64 < %s | FileCheck %s
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v2 < %s | FileCheck %s
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v3 < %s | FileCheck %s
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %s | FileCheck %s
+
+; Scalarization profitability is target-dependent. Check it for each x86-64
+; microarchitecture level that this transform is expected to support.
+define void @insert_store2(ptr %p, i16 %x, i16 %y) {
+; CHECK-LABEL: @insert_store2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[GEP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 6
+; CHECK-NEXT:    store i16 [[X:%.*]], ptr [[GEP0]], align 1
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 7
+; CHECK-NEXT:    store i16 [[Y:%.*]], ptr [[GEP1]], align 1
+; CHECK-NEXT:    ret void
+;
+entry:
+  %load = load <8 x i16>, ptr %p, align 1
+  %insert0 = insertelement <8 x i16> %load, i16 %x, i32 6
+  %insert1 = insertelement <8 x i16> %insert0, i16 %y, i32 7
+  store <8 x i16> %insert1, ptr %p, align 1
+  ret void
+}
+
+; Keep the program order of stores when two inserts select the same element.
+define void @insert_store_duplicate(ptr %p, i16 %x, i16 %y) {
+; CHECK-LABEL: @insert_store_duplicate(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[GEP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[X:%.*]], ptr [[GEP0]], align 1
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[Y:%.*]], ptr [[GEP1]], align 1
+; CHECK-NEXT:    ret void
+;
+entry:
+  %load = load <8 x i16>, ptr %p, align 1
+  %insert0 = insertelement <8 x i16> %load, i16 %x, i32 3
+  %insert1 = insertelement <8 x i16> %insert0, i16 %y, i32 3
+  store <8 x i16> %insert1, ptr %p, align 1
+  ret void
+}
diff --git a/llvm/test/Transforms/VectorCombine/load-insert-store.ll b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
index 8601a4eebcb44..1cf1d65d1b346 100644
--- a/llvm/test/Transforms/VectorCombine/load-insert-store.ll
+++ b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
@@ -1,8 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64 < %s | FileCheck %s --check-prefixes=CHECK,X64
-; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v2 < %s | FileCheck %s --check-prefixes=CHECK,X64V2
-; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v3 < %s | FileCheck %s --check-prefixes=CHECK,X64V3
-; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %s | FileCheck %s --check-prefixes=CHECK,X64V4
+; Verify scalar stores use the same vector-element address for both byte orders.
+; RUN: opt -S -passes=vector-combine -data-layout=e < %s | FileCheck %s
+; RUN: opt -S -passes=vector-combine -data-layout=E < %s | FileCheck %s
 
 define void @insert_store(ptr %q, i8 zeroext %s) {
 ; CHECK-LABEL: @insert_store(
@@ -1203,8 +1202,3 @@ define void @insert_store_dynamic_indices_may_alias(ptr %p, i16 %a, i16 %b, i32
   store <8 x i16> %v2, ptr %p
   ret void
 }
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; X64: {{.*}}
-; X64V2: {{.*}}
-; X64V3: {{.*}}
-; X64V4: {{.*}}

>From 9a80588142d6454170b3df328467c52ceb205254 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Mon, 13 Jul 2026 17:15:12 +0900
Subject: [PATCH 7/9] moved the test cases to each architecture-specific
 directory

---
 .../AArch64/load-insert-store.ll              | 365 ++++++++++++++++-
 .../VectorCombine/X86/load-insert-store.ll    | 371 +++++++++++++++++-
 .../VectorCombine/load-insert-store.ll        | 354 -----------------
 3 files changed, 722 insertions(+), 368 deletions(-)

diff --git a/llvm/test/Transforms/VectorCombine/AArch64/load-insert-store.ll b/llvm/test/Transforms/VectorCombine/AArch64/load-insert-store.ll
index c2ef3aa0daff0..ea2329c3a0ddb 100644
--- a/llvm/test/Transforms/VectorCombine/AArch64/load-insert-store.ll
+++ b/llvm/test/Transforms/VectorCombine/AArch64/load-insert-store.ll
@@ -1,18 +1,20 @@
-; RUN: opt -S -passes=vector-combine -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s
-; RUN: opt -S -passes=vector-combine -mtriple=aarch64_be-unknown-linux-gnu < %s | FileCheck %s
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Run the complete multi-insert suite for both AArch64 byte orders.
+; RUN: opt -S -passes=vector-combine -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,LE
+; RUN: opt -S -passes=vector-combine -mtriple=aarch64_be-unknown-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,BE
+
+declare void @llvm.assume(i1)
 
 ; Use real little- and big-endian targets to verify that an insertelement lane
 ; is scalarized to the same memory element on both byte orders.
 define void @insert_store2(ptr %p, i16 %x, i16 %y) {
 ; CHECK-LABEL: @insert_store2(
-; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[GEP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 6
 ; CHECK-NEXT:    store i16 [[X:%.*]], ptr [[GEP0]], align 1
 ; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 7
 ; CHECK-NEXT:    store i16 [[Y:%.*]], ptr [[GEP1]], align 1
 ; CHECK-NEXT:    ret void
 ;
-entry:
   %load = load <8 x i16>, ptr %p, align 1
   %insert0 = insertelement <8 x i16> %load, i16 %x, i32 6
   %insert1 = insertelement <8 x i16> %insert0, i16 %y, i32 7
@@ -20,20 +22,371 @@ entry:
   ret void
 }
 
+define void @insert_store2_same_value(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store2_same_value(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 6
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 7
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 2
+; CHECK-NEXT:    ret void
+;
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 6
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 7
+  store <8 x i16> %vec2, ptr %q, align 1
+  ret void
+}
+
+define void @insert_store2_duplicate_different_values(ptr %p, i16 %a, i16 %b) {
+; CHECK-LABEL: @insert_store2_duplicate_different_values(
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[A:%.*]], ptr [[TMP1]], align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[B:%.*]], ptr [[TMP2]], align 2
+; CHECK-NEXT:    ret void
+;
+  %v = load <8 x i16>, ptr %p
+  %v1 = insertelement <8 x i16> %v, i16 %a, i32 3
+  %v2 = insertelement <8 x i16> %v1, i16 %b, i32 3
+  store <8 x i16> %v2, ptr %p
+  ret void
+}
+
+define void @insert_store3(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store3(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 5
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 6
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 7
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP2]], align 2
+; CHECK-NEXT:    ret void
+;
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 5
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 6
+  %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 7
+  store <8 x i16> %vec3, ptr %q, align 1
+  ret void
+}
+
+define void @insert_store8(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store8(
+; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 0
+; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 1
+; CHECK-NEXT:    [[VEC3:%.*]] = insertelement <8 x i16> [[VEC2]], i16 [[S]], i32 2
+; CHECK-NEXT:    [[VEC4:%.*]] = insertelement <8 x i16> [[VEC3]], i16 [[S]], i32 3
+; CHECK-NEXT:    [[VEC5:%.*]] = insertelement <8 x i16> [[VEC4]], i16 [[S]], i32 4
+; CHECK-NEXT:    [[VEC6:%.*]] = insertelement <8 x i16> [[VEC5]], i16 [[S]], i32 5
+; CHECK-NEXT:    [[VEC7:%.*]] = insertelement <8 x i16> [[VEC6]], i16 [[S]], i32 6
+; CHECK-NEXT:    [[VEC8:%.*]] = insertelement <8 x i16> [[VEC7]], i16 [[S]], i32 7
+; CHECK-NEXT:    store <8 x i16> [[VEC8]], ptr [[Q]], align 1
+; CHECK-NEXT:    ret void
+;
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 0
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 1
+  %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 2
+  %vec4 = insertelement <8 x i16> %vec3, i16 %s, i32 3
+  %vec5 = insertelement <8 x i16> %vec4, i16 %s, i32 4
+  %vec6 = insertelement <8 x i16> %vec5, i16 %s, i32 5
+  %vec7 = insertelement <8 x i16> %vec6, i16 %s, i32 6
+  %vec8 = insertelement <8 x i16> %vec7, i16 %s, i32 7
+  store <8 x i16> %vec8, ptr %q, align 1
+  ret void
+}
+
+define void @insert_store_multi_nonconst_index_freeze(ptr %p, i8 %s, i8 %x, i8 %y) {
+; CHECK-LABEL: @insert_store_multi_nonconst_index_freeze(
+; CHECK-NEXT:    [[S_FROZEN:%.*]] = freeze i8 [[S:%.*]]
+; CHECK-NEXT:    [[IDX:%.*]] = and i8 [[S_FROZEN]], 1
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds <4 x i8>, ptr [[P:%.*]], i8 0, i8 [[IDX]]
+; CHECK-NEXT:    store i8 [[X:%.*]], ptr [[GEP1]], align 1
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <4 x i8>, ptr [[P]], i32 0, i32 2
+; CHECK-NEXT:    store i8 [[Y:%.*]], ptr [[TMP2]], align 2
+; CHECK-NEXT:    ret void
+;
+  %ld = load <4 x i8>, ptr %p, align 4
+  %idx = and i8 %s, 1
+  %ins0 = insertelement <4 x i8> %ld, i8 %x, i8 %idx
+  %ins1 = insertelement <4 x i8> %ins0, i8 %y, i32 2
+  store <4 x i8> %ins1, ptr %p, align 4
+  ret void
+}
+
+define void @insert_store_gap(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_gap(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 2
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 5
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 2
+; CHECK-NEXT:    ret void
+;
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 2
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 5
+  store <8 x i16> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_reverse(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_reverse(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 7
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 6
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 5
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP2]], align 2
+; CHECK-NEXT:    ret void
+;
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 7
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 6
+  %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 5
+  store <8 x i16> %vec3, ptr %q
+  ret void
+}
+
 ; A duplicate lane must still be written in insertion order on both targets.
 define void @insert_store_duplicate(ptr %p, i16 %x, i16 %y) {
 ; CHECK-LABEL: @insert_store_duplicate(
-; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[GEP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 3
 ; CHECK-NEXT:    store i16 [[X:%.*]], ptr [[GEP0]], align 1
 ; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 3
 ; CHECK-NEXT:    store i16 [[Y:%.*]], ptr [[GEP1]], align 1
 ; CHECK-NEXT:    ret void
 ;
-entry:
   %load = load <8 x i16>, ptr %p, align 1
   %insert0 = insertelement <8 x i16> %load, i16 %x, i32 3
   %insert1 = insertelement <8 x i16> %insert0, i16 %y, i32 3
   store <8 x i16> %insert1, ptr %p, align 1
   ret void
 }
+
+define void @insert_store_duplicate_same_value(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_duplicate_same_value(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 2
+; CHECK-NEXT:    ret void
+;
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 3
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 3
+  store <8 x i16> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_i32(ptr %q, i32 zeroext %s) {
+; CHECK-LABEL: @insert_store_i32(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q:%.*]], i32 0, i32 2
+; CHECK-NEXT:    store i32 [[S:%.*]], ptr [[TMP0]], align 8
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q]], i32 0, i32 3
+; CHECK-NEXT:    store i32 [[S]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    ret void
+;
+  %load = load <4 x i32>, ptr %q
+  %vec1 = insertelement <4 x i32> %load, i32 %s, i32 2
+  %vec2 = insertelement <4 x i32> %vec1, i32 %s, i32 3
+  store <4 x i32> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_i8(ptr %q, i8 zeroext %s) {
+; CHECK-LABEL: @insert_store_i8(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 8
+; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 8
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q]], i32 0, i32 9
+; CHECK-NEXT:    store i8 [[S]], ptr [[TMP1]], align 1
+; CHECK-NEXT:    ret void
+;
+  %load = load <16 x i8>, ptr %q
+  %vec1 = insertelement <16 x i8> %load, i8 %s, i32 8
+  %vec2 = insertelement <16 x i8> %vec1, i8 %s, i32 9
+  store <16 x i8> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_alignment(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_alignment(
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0:%.*]], align 16
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[TMP0]], i32 0, i32 4
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 8
+; CHECK-NEXT:    ret void
+;
+  %load = load <8 x i16>, ptr %q, align 16
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 0
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 4
+  store <8 x i16> %vec2, ptr %q, align 16
+  ret void
+}
+
+define void @insert_store_size(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_size(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i16>, ptr [[Q:%.*]], i32 0, i32 8
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 16
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i16>, ptr [[Q]], i32 0, i32 12
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 8
+; CHECK-NEXT:    ret void
+;
+  %load = load <16 x i16>, ptr %q
+  %vec1 = insertelement <16 x i16> %load, i16 %s, i32 8
+  %vec2 = insertelement <16 x i16> %vec1, i16 %s, i32 12
+  store <16 x i16> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_nonconst4(ptr %q, i8 zeroext %s, i32 %idx1, i32 %idx2, i32 %idx3, i32 %idx4) {
+; CHECK-LABEL: @insert_store_nonconst4(
+; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX1:%.*]]
+; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <16 x i8> [[VECINS1]], i8 [[S]], i32 [[IDX2:%.*]]
+; CHECK-NEXT:    [[VECINS3:%.*]] = insertelement <16 x i8> [[VECINS2]], i8 [[S]], i32 [[IDX3:%.*]]
+; CHECK-NEXT:    [[VECINS4:%.*]] = insertelement <16 x i8> [[VECINS3]], i8 [[S]], i32 [[IDX4:%.*]]
+; CHECK-NEXT:    store <16 x i8> [[VECINS4]], ptr [[Q]], align 16
+; CHECK-NEXT:    ret void
+;
+  %load = load <16 x i8>, ptr %q
+  %vecins1 = insertelement <16 x i8> %load, i8 %s, i32 %idx1
+  %vecins2 = insertelement <16 x i8> %vecins1, i8 %s, i32 %idx2
+  %vecins3 = insertelement <16 x i8> %vecins2, i8 %s, i32 %idx3
+  %vecins4 = insertelement <16 x i8> %vecins3, i8 %s, i32 %idx4
+  store <16 x i8> %vecins4, ptr %q
+  ret void
+}
+
+define void @insert_store_vscale_nonconst2(ptr %q, i8 zeroext %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_vscale_nonconst2(
+; CHECK-NEXT:    [[TMP0:%.*]] = load <vscale x 16 x i8>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <vscale x 16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX1:%.*]]
+; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <vscale x 16 x i8> [[VECINS1]], i8 [[S]], i32 [[IDX2:%.*]]
+; CHECK-NEXT:    store <vscale x 16 x i8> [[VECINS2]], ptr [[Q]], align 16
+; CHECK-NEXT:    ret void
+;
+  %load = load <vscale x 16 x i8>, ptr %q
+  %vecins1 = insertelement <vscale x 16 x i8> %load, i8 %s, i32 %idx1
+  %vecins2 = insertelement <vscale x 16 x i8> %vecins1, i8 %s, i32 %idx2
+  store <vscale x 16 x i8> %vecins2, ptr %q
+  ret void
+}
+
+define void @insert_store_nonconst_large_alignment2(ptr %q, i32 zeroext %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_nonconst_large_alignment2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 4
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 4
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
+; CHECK-NEXT:    store i32 [[S:%.*]], ptr [[TMP0]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q]], i32 0, i32 [[IDX2]]
+; CHECK-NEXT:    store i32 [[S]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    ret void
+;
+  %cmp1 = icmp ult i32 %idx1, 4
+  %cmp2 = icmp ult i32 %idx2, 4
+  call void @llvm.assume(i1 %cmp1)
+  call void @llvm.assume(i1 %cmp2)
+  %i = load <4 x i32>, ptr %q, align 128
+  %vecins1 = insertelement <4 x i32> %i, i32 %s, i32 %idx1
+  %vecins2 = insertelement <4 x i32> %vecins1, i32 %s, i32 %idx2
+  store <4 x i32> %vecins2, ptr %q, align 128
+  ret void
+}
+
+define void @insert_store_nonconst_align_maximum_8_2(ptr %q, i64 %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_nonconst_align_maximum_8_2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 2
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
+; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 8
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q]], i32 0, i32 [[IDX2]]
+; CHECK-NEXT:    store i64 [[S]], ptr [[TMP2]], align 8
+; CHECK-NEXT:    ret void
+;
+  %cmp1 = icmp ult i32 %idx1, 2
+  %cmp2 = icmp ult i32 %idx2, 2
+  call void @llvm.assume(i1 %cmp1)
+  call void @llvm.assume(i1 %cmp2)
+  %i = load <8 x i64>, ptr %q, align 8
+  %vecins1 = insertelement <8 x i64> %i, i64 %s, i32 %idx1
+  %vecins2 = insertelement <8 x i64> %vecins1, i64 %s, i32 %idx2
+  store <8 x i64> %vecins2, ptr %q, align 8
+  ret void
+}
+
+define void @insert_store_nonconst_align_maximum_4_2(ptr %q, i64 %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_nonconst_align_maximum_4_2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 2
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
+; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q]], i32 0, i32 [[IDX2]]
+; CHECK-NEXT:    store i64 [[S]], ptr [[TMP2]], align 4
+; CHECK-NEXT:    ret void
+;
+  %cmp1 = icmp ult i32 %idx1, 2
+  %cmp2 = icmp ult i32 %idx2, 2
+  call void @llvm.assume(i1 %cmp1)
+  call void @llvm.assume(i1 %cmp2)
+  %i = load <8 x i64>, ptr %q, align 4
+  %vecins1 = insertelement <8 x i64> %i, i64 %s, i32 %idx1
+  %vecins2 = insertelement <8 x i64> %vecins1, i64 %s, i32 %idx2
+  store <8 x i64> %vecins2, ptr %q, align 4
+  ret void
+}
+
+define void @insert_store_nonconst_align_larger_2(ptr %q, i64 %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_nonconst_align_larger_2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 2
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
+; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q]], i32 0, i32 [[IDX2]]
+; CHECK-NEXT:    store i64 [[S]], ptr [[TMP2]], align 4
+; CHECK-NEXT:    ret void
+;
+  %cmp1 = icmp ult i32 %idx1, 2
+  %cmp2 = icmp ult i32 %idx2, 2
+  call void @llvm.assume(i1 %cmp1)
+  call void @llvm.assume(i1 %cmp2)
+  %i = load <8 x i64>, ptr %q, align 4
+  %vecins1 = insertelement <8 x i64> %i, i64 %s, i32 %idx1
+  %vecins2 = insertelement <8 x i64> %vecins1, i64 %s, i32 %idx2
+  store <8 x i64> %vecins2, ptr %q, align 2
+  ret void
+}
+
+define void @insert_store_dynamic_indices_may_alias(ptr %p, i16 %a, i16 %b, i32 %i, i32 %j) {
+; CHECK-LABEL: @insert_store_dynamic_indices_may_alias(
+; CHECK-NEXT:    [[CI:%.*]] = icmp ult i32 [[I:%.*]], 8
+; CHECK-NEXT:    [[CJ:%.*]] = icmp ult i32 [[J:%.*]], 8
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CI]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CJ]])
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 [[I]]
+; CHECK-NEXT:    store i16 [[A:%.*]], ptr [[TMP1]], align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 [[J]]
+; CHECK-NEXT:    store i16 [[B:%.*]], ptr [[TMP2]], align 2
+; CHECK-NEXT:    ret void
+;
+  %ci = icmp ult i32 %i, 8
+  %cj = icmp ult i32 %j, 8
+  call void @llvm.assume(i1 %ci)
+  call void @llvm.assume(i1 %cj)
+
+  %v = load <8 x i16>, ptr %p
+  %v1 = insertelement <8 x i16> %v, i16 %a, i32 %i
+  %v2 = insertelement <8 x i16> %v1, i16 %b, i32 %j
+  store <8 x i16> %v2, ptr %p
+  ret void
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; BE: {{.*}}
+; LE: {{.*}}
diff --git a/llvm/test/Transforms/VectorCombine/X86/load-insert-store.ll b/llvm/test/Transforms/VectorCombine/X86/load-insert-store.ll
index b68389d0f1372..ae3741153517a 100644
--- a/llvm/test/Transforms/VectorCombine/X86/load-insert-store.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/load-insert-store.ll
@@ -1,20 +1,22 @@
-; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64 < %s | FileCheck %s
-; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v2 < %s | FileCheck %s
-; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v3 < %s | FileCheck %s
-; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %s | FileCheck %s
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; Run the multi-insert suite for each supported x86-64 CPU level.
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64 < %s | FileCheck %s --check-prefixes=CHECK,X64
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v2 < %s | FileCheck %s --check-prefixes=CHECK,X64V2
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v3 < %s | FileCheck %s --check-prefixes=CHECK,X64V3
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %s | FileCheck %s --check-prefixes=CHECK,X64V4
+
+declare void @llvm.assume(i1)
 
 ; Scalarization profitability is target-dependent. Check it for each x86-64
 ; microarchitecture level that this transform is expected to support.
 define void @insert_store2(ptr %p, i16 %x, i16 %y) {
 ; CHECK-LABEL: @insert_store2(
-; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[GEP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 6
 ; CHECK-NEXT:    store i16 [[X:%.*]], ptr [[GEP0]], align 1
 ; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 7
 ; CHECK-NEXT:    store i16 [[Y:%.*]], ptr [[GEP1]], align 1
 ; CHECK-NEXT:    ret void
 ;
-entry:
   %load = load <8 x i16>, ptr %p, align 1
   %insert0 = insertelement <8 x i16> %load, i16 %x, i32 6
   %insert1 = insertelement <8 x i16> %insert0, i16 %y, i32 7
@@ -22,20 +24,373 @@ entry:
   ret void
 }
 
+define void @insert_store2_same_value(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store2_same_value(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 6
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 7
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 2
+; CHECK-NEXT:    ret void
+;
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 6
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 7
+  store <8 x i16> %vec2, ptr %q, align 1
+  ret void
+}
+
+define void @insert_store2_duplicate_different_values(ptr %p, i16 %a, i16 %b) {
+; CHECK-LABEL: @insert_store2_duplicate_different_values(
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[A:%.*]], ptr [[TMP1]], align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[B:%.*]], ptr [[TMP2]], align 2
+; CHECK-NEXT:    ret void
+;
+  %v = load <8 x i16>, ptr %p
+  %v1 = insertelement <8 x i16> %v, i16 %a, i32 3
+  %v2 = insertelement <8 x i16> %v1, i16 %b, i32 3
+  store <8 x i16> %v2, ptr %p
+  ret void
+}
+
+define void @insert_store3(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store3(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 5
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 6
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 7
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP2]], align 2
+; CHECK-NEXT:    ret void
+;
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 5
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 6
+  %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 7
+  store <8 x i16> %vec3, ptr %q, align 1
+  ret void
+}
+
+define void @insert_store8(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store8(
+; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 0
+; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 1
+; CHECK-NEXT:    [[VEC3:%.*]] = insertelement <8 x i16> [[VEC2]], i16 [[S]], i32 2
+; CHECK-NEXT:    [[VEC4:%.*]] = insertelement <8 x i16> [[VEC3]], i16 [[S]], i32 3
+; CHECK-NEXT:    [[VEC5:%.*]] = insertelement <8 x i16> [[VEC4]], i16 [[S]], i32 4
+; CHECK-NEXT:    [[VEC6:%.*]] = insertelement <8 x i16> [[VEC5]], i16 [[S]], i32 5
+; CHECK-NEXT:    [[VEC7:%.*]] = insertelement <8 x i16> [[VEC6]], i16 [[S]], i32 6
+; CHECK-NEXT:    [[VEC8:%.*]] = insertelement <8 x i16> [[VEC7]], i16 [[S]], i32 7
+; CHECK-NEXT:    store <8 x i16> [[VEC8]], ptr [[Q]], align 1
+; CHECK-NEXT:    ret void
+;
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 0
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 1
+  %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 2
+  %vec4 = insertelement <8 x i16> %vec3, i16 %s, i32 3
+  %vec5 = insertelement <8 x i16> %vec4, i16 %s, i32 4
+  %vec6 = insertelement <8 x i16> %vec5, i16 %s, i32 5
+  %vec7 = insertelement <8 x i16> %vec6, i16 %s, i32 6
+  %vec8 = insertelement <8 x i16> %vec7, i16 %s, i32 7
+  store <8 x i16> %vec8, ptr %q, align 1
+  ret void
+}
+
+define void @insert_store_multi_nonconst_index_freeze(ptr %p, i8 %s, i8 %x, i8 %y) {
+; CHECK-LABEL: @insert_store_multi_nonconst_index_freeze(
+; CHECK-NEXT:    [[S_FROZEN:%.*]] = freeze i8 [[S:%.*]]
+; CHECK-NEXT:    [[IDX:%.*]] = and i8 [[S_FROZEN]], 1
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds <4 x i8>, ptr [[P:%.*]], i8 0, i8 [[IDX]]
+; CHECK-NEXT:    store i8 [[X:%.*]], ptr [[GEP1]], align 1
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <4 x i8>, ptr [[P]], i32 0, i32 2
+; CHECK-NEXT:    store i8 [[Y:%.*]], ptr [[TMP2]], align 2
+; CHECK-NEXT:    ret void
+;
+  %ld = load <4 x i8>, ptr %p, align 4
+  %idx = and i8 %s, 1
+  %ins0 = insertelement <4 x i8> %ld, i8 %x, i8 %idx
+  %ins1 = insertelement <4 x i8> %ins0, i8 %y, i32 2
+  store <4 x i8> %ins1, ptr %p, align 4
+  ret void
+}
+
+define void @insert_store_gap(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_gap(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 2
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 5
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 2
+; CHECK-NEXT:    ret void
+;
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 2
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 5
+  store <8 x i16> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_reverse(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_reverse(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 7
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 6
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 5
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP2]], align 2
+; CHECK-NEXT:    ret void
+;
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 7
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 6
+  %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 5
+  store <8 x i16> %vec3, ptr %q
+  ret void
+}
+
 ; Keep the program order of stores when two inserts select the same element.
 define void @insert_store_duplicate(ptr %p, i16 %x, i16 %y) {
 ; CHECK-LABEL: @insert_store_duplicate(
-; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[GEP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 3
 ; CHECK-NEXT:    store i16 [[X:%.*]], ptr [[GEP0]], align 1
 ; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 3
 ; CHECK-NEXT:    store i16 [[Y:%.*]], ptr [[GEP1]], align 1
 ; CHECK-NEXT:    ret void
 ;
-entry:
   %load = load <8 x i16>, ptr %p, align 1
   %insert0 = insertelement <8 x i16> %load, i16 %x, i32 3
   %insert1 = insertelement <8 x i16> %insert0, i16 %y, i32 3
   store <8 x i16> %insert1, ptr %p, align 1
   ret void
 }
+
+define void @insert_store_duplicate_same_value(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_duplicate_same_value(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 3
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 2
+; CHECK-NEXT:    ret void
+;
+  %load = load <8 x i16>, ptr %q
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 3
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 3
+  store <8 x i16> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_i32(ptr %q, i32 zeroext %s) {
+; CHECK-LABEL: @insert_store_i32(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q:%.*]], i32 0, i32 2
+; CHECK-NEXT:    store i32 [[S:%.*]], ptr [[TMP0]], align 8
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q]], i32 0, i32 3
+; CHECK-NEXT:    store i32 [[S]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    ret void
+;
+  %load = load <4 x i32>, ptr %q
+  %vec1 = insertelement <4 x i32> %load, i32 %s, i32 2
+  %vec2 = insertelement <4 x i32> %vec1, i32 %s, i32 3
+  store <4 x i32> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_i8(ptr %q, i8 zeroext %s) {
+; CHECK-LABEL: @insert_store_i8(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 8
+; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 8
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q]], i32 0, i32 9
+; CHECK-NEXT:    store i8 [[S]], ptr [[TMP1]], align 1
+; CHECK-NEXT:    ret void
+;
+  %load = load <16 x i8>, ptr %q
+  %vec1 = insertelement <16 x i8> %load, i8 %s, i32 8
+  %vec2 = insertelement <16 x i8> %vec1, i8 %s, i32 9
+  store <16 x i8> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_alignment(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_alignment(
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0:%.*]], align 16
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[TMP0]], i32 0, i32 4
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 8
+; CHECK-NEXT:    ret void
+;
+  %load = load <8 x i16>, ptr %q, align 16
+  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 0
+  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 4
+  store <8 x i16> %vec2, ptr %q, align 16
+  ret void
+}
+
+define void @insert_store_size(ptr %q, i16 zeroext %s) {
+; CHECK-LABEL: @insert_store_size(
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i16>, ptr [[Q:%.*]], i32 0, i32 8
+; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 16
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i16>, ptr [[Q]], i32 0, i32 12
+; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 8
+; CHECK-NEXT:    ret void
+;
+  %load = load <16 x i16>, ptr %q
+  %vec1 = insertelement <16 x i16> %load, i16 %s, i32 8
+  %vec2 = insertelement <16 x i16> %vec1, i16 %s, i32 12
+  store <16 x i16> %vec2, ptr %q
+  ret void
+}
+
+define void @insert_store_nonconst4(ptr %q, i8 zeroext %s, i32 %idx1, i32 %idx2, i32 %idx3, i32 %idx4) {
+; CHECK-LABEL: @insert_store_nonconst4(
+; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX1:%.*]]
+; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <16 x i8> [[VECINS1]], i8 [[S]], i32 [[IDX2:%.*]]
+; CHECK-NEXT:    [[VECINS3:%.*]] = insertelement <16 x i8> [[VECINS2]], i8 [[S]], i32 [[IDX3:%.*]]
+; CHECK-NEXT:    [[VECINS4:%.*]] = insertelement <16 x i8> [[VECINS3]], i8 [[S]], i32 [[IDX4:%.*]]
+; CHECK-NEXT:    store <16 x i8> [[VECINS4]], ptr [[Q]], align 16
+; CHECK-NEXT:    ret void
+;
+  %load = load <16 x i8>, ptr %q
+  %vecins1 = insertelement <16 x i8> %load, i8 %s, i32 %idx1
+  %vecins2 = insertelement <16 x i8> %vecins1, i8 %s, i32 %idx2
+  %vecins3 = insertelement <16 x i8> %vecins2, i8 %s, i32 %idx3
+  %vecins4 = insertelement <16 x i8> %vecins3, i8 %s, i32 %idx4
+  store <16 x i8> %vecins4, ptr %q
+  ret void
+}
+
+define void @insert_store_vscale_nonconst2(ptr %q, i8 zeroext %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_vscale_nonconst2(
+; CHECK-NEXT:    [[TMP0:%.*]] = load <vscale x 16 x i8>, ptr [[Q:%.*]], align 16
+; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <vscale x 16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX1:%.*]]
+; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <vscale x 16 x i8> [[VECINS1]], i8 [[S]], i32 [[IDX2:%.*]]
+; CHECK-NEXT:    store <vscale x 16 x i8> [[VECINS2]], ptr [[Q]], align 16
+; CHECK-NEXT:    ret void
+;
+  %load = load <vscale x 16 x i8>, ptr %q
+  %vecins1 = insertelement <vscale x 16 x i8> %load, i8 %s, i32 %idx1
+  %vecins2 = insertelement <vscale x 16 x i8> %vecins1, i8 %s, i32 %idx2
+  store <vscale x 16 x i8> %vecins2, ptr %q
+  ret void
+}
+
+define void @insert_store_nonconst_large_alignment2(ptr %q, i32 zeroext %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_nonconst_large_alignment2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 4
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 4
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
+; CHECK-NEXT:    store i32 [[S:%.*]], ptr [[TMP0]], align 4
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q]], i32 0, i32 [[IDX2]]
+; CHECK-NEXT:    store i32 [[S]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    ret void
+;
+  %cmp1 = icmp ult i32 %idx1, 4
+  %cmp2 = icmp ult i32 %idx2, 4
+  call void @llvm.assume(i1 %cmp1)
+  call void @llvm.assume(i1 %cmp2)
+  %i = load <4 x i32>, ptr %q, align 128
+  %vecins1 = insertelement <4 x i32> %i, i32 %s, i32 %idx1
+  %vecins2 = insertelement <4 x i32> %vecins1, i32 %s, i32 %idx2
+  store <4 x i32> %vecins2, ptr %q, align 128
+  ret void
+}
+
+define void @insert_store_nonconst_align_maximum_8_2(ptr %q, i64 %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_nonconst_align_maximum_8_2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 2
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
+; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 8
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q]], i32 0, i32 [[IDX2]]
+; CHECK-NEXT:    store i64 [[S]], ptr [[TMP2]], align 8
+; CHECK-NEXT:    ret void
+;
+  %cmp1 = icmp ult i32 %idx1, 2
+  %cmp2 = icmp ult i32 %idx2, 2
+  call void @llvm.assume(i1 %cmp1)
+  call void @llvm.assume(i1 %cmp2)
+  %i = load <8 x i64>, ptr %q, align 8
+  %vecins1 = insertelement <8 x i64> %i, i64 %s, i32 %idx1
+  %vecins2 = insertelement <8 x i64> %vecins1, i64 %s, i32 %idx2
+  store <8 x i64> %vecins2, ptr %q, align 8
+  ret void
+}
+
+define void @insert_store_nonconst_align_maximum_4_2(ptr %q, i64 %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_nonconst_align_maximum_4_2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 2
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
+; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q]], i32 0, i32 [[IDX2]]
+; CHECK-NEXT:    store i64 [[S]], ptr [[TMP2]], align 4
+; CHECK-NEXT:    ret void
+;
+  %cmp1 = icmp ult i32 %idx1, 2
+  %cmp2 = icmp ult i32 %idx2, 2
+  call void @llvm.assume(i1 %cmp1)
+  call void @llvm.assume(i1 %cmp2)
+  %i = load <8 x i64>, ptr %q, align 4
+  %vecins1 = insertelement <8 x i64> %i, i64 %s, i32 %idx1
+  %vecins2 = insertelement <8 x i64> %vecins1, i64 %s, i32 %idx2
+  store <8 x i64> %vecins2, ptr %q, align 4
+  ret void
+}
+
+define void @insert_store_nonconst_align_larger_2(ptr %q, i64 %s, i32 %idx1, i32 %idx2) {
+; CHECK-LABEL: @insert_store_nonconst_align_larger_2(
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 2
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
+; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q]], i32 0, i32 [[IDX2]]
+; CHECK-NEXT:    store i64 [[S]], ptr [[TMP2]], align 4
+; CHECK-NEXT:    ret void
+;
+  %cmp1 = icmp ult i32 %idx1, 2
+  %cmp2 = icmp ult i32 %idx2, 2
+  call void @llvm.assume(i1 %cmp1)
+  call void @llvm.assume(i1 %cmp2)
+  %i = load <8 x i64>, ptr %q, align 4
+  %vecins1 = insertelement <8 x i64> %i, i64 %s, i32 %idx1
+  %vecins2 = insertelement <8 x i64> %vecins1, i64 %s, i32 %idx2
+  store <8 x i64> %vecins2, ptr %q, align 2
+  ret void
+}
+
+define void @insert_store_dynamic_indices_may_alias(ptr %p, i16 %a, i16 %b, i32 %i, i32 %j) {
+; CHECK-LABEL: @insert_store_dynamic_indices_may_alias(
+; CHECK-NEXT:    [[CI:%.*]] = icmp ult i32 [[I:%.*]], 8
+; CHECK-NEXT:    [[CJ:%.*]] = icmp ult i32 [[J:%.*]], 8
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CI]])
+; CHECK-NEXT:    call void @llvm.assume(i1 [[CJ]])
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 [[I]]
+; CHECK-NEXT:    store i16 [[A:%.*]], ptr [[TMP1]], align 2
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 [[J]]
+; CHECK-NEXT:    store i16 [[B:%.*]], ptr [[TMP2]], align 2
+; CHECK-NEXT:    ret void
+;
+  %ci = icmp ult i32 %i, 8
+  %cj = icmp ult i32 %j, 8
+  call void @llvm.assume(i1 %ci)
+  call void @llvm.assume(i1 %cj)
+
+  %v = load <8 x i16>, ptr %p
+  %v1 = insertelement <8 x i16> %v, i16 %a, i32 %i
+  %v2 = insertelement <8 x i16> %v1, i16 %b, i32 %j
+  store <8 x i16> %v2, ptr %p
+  ret void
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; X64: {{.*}}
+; X64V2: {{.*}}
+; X64V3: {{.*}}
+; X64V4: {{.*}}
diff --git a/llvm/test/Transforms/VectorCombine/load-insert-store.ll b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
index 1cf1d65d1b346..06375f4ac29e1 100644
--- a/llvm/test/Transforms/VectorCombine/load-insert-store.ll
+++ b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
@@ -17,81 +17,6 @@ entry:
   ret void
 }
 
-define void @insert_store2(ptr %q, i16 zeroext %s) {
-; CHECK-LABEL: @insert_store2(
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 6
-; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 4
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 7
-; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 2
-; CHECK-NEXT:    ret void
-;
-  %load = load <8 x i16>, ptr %q
-  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 6
-  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 7
-  store <8 x i16> %vec2, ptr %q, align 1
-  ret void
-}
-
-define void @insert_store2_duplicate_different_values(ptr %p, i16 %a, i16 %b) {
-; CHECK-LABEL: @insert_store2_duplicate_different_values(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 3
-; CHECK-NEXT:    store i16 [[A:%.*]], ptr [[TMP1]], align 2
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 3
-; CHECK-NEXT:    store i16 [[B:%.*]], ptr [[TMP2]], align 2
-; CHECK-NEXT:    ret void
-;
-  %v = load <8 x i16>, ptr %p
-  %v1 = insertelement <8 x i16> %v, i16 %a, i32 3
-  %v2 = insertelement <8 x i16> %v1, i16 %b, i32 3
-  store <8 x i16> %v2, ptr %p
-  ret void
-}
-
-define void @insert_store3(ptr %q, i16 zeroext %s) {
-; CHECK-LABEL: @insert_store3(
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 5
-; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 6
-; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 4
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 7
-; CHECK-NEXT:    store i16 [[S]], ptr [[TMP2]], align 2
-; CHECK-NEXT:    ret void
-;
-  %load = load <8 x i16>, ptr %q
-  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 5
-  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 6
-  %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 7
-  store <8 x i16> %vec3, ptr %q, align 1
-  ret void
-}
-
-define void @insert_store8(ptr %q, i16 zeroext %s) {
-; CHECK-LABEL: @insert_store8(
-; CHECK-NEXT:    [[TMP0:%.*]] = load <8 x i16>, ptr [[Q:%.*]], align 16
-; CHECK-NEXT:    [[VEC1:%.*]] = insertelement <8 x i16> [[TMP0]], i16 [[S:%.*]], i32 0
-; CHECK-NEXT:    [[VEC2:%.*]] = insertelement <8 x i16> [[VEC1]], i16 [[S]], i32 1
-; CHECK-NEXT:    [[VEC3:%.*]] = insertelement <8 x i16> [[VEC2]], i16 [[S]], i32 2
-; CHECK-NEXT:    [[VEC4:%.*]] = insertelement <8 x i16> [[VEC3]], i16 [[S]], i32 3
-; CHECK-NEXT:    [[VEC5:%.*]] = insertelement <8 x i16> [[VEC4]], i16 [[S]], i32 4
-; CHECK-NEXT:    [[VEC6:%.*]] = insertelement <8 x i16> [[VEC5]], i16 [[S]], i32 5
-; CHECK-NEXT:    [[VEC7:%.*]] = insertelement <8 x i16> [[VEC6]], i16 [[S]], i32 6
-; CHECK-NEXT:    [[VEC8:%.*]] = insertelement <8 x i16> [[VEC7]], i16 [[S]], i32 7
-; CHECK-NEXT:    store <8 x i16> [[VEC8]], ptr [[Q]], align 1
-; CHECK-NEXT:    ret void
-;
-  %load = load <8 x i16>, ptr %q
-  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 0
-  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 1
-  %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 2
-  %vec4 = insertelement <8 x i16> %vec3, i16 %s, i32 3
-  %vec5 = insertelement <8 x i16> %vec4, i16 %s, i32 4
-  %vec6 = insertelement <8 x i16> %vec5, i16 %s, i32 5
-  %vec7 = insertelement <8 x i16> %vec6, i16 %s, i32 6
-  %vec8 = insertelement <8 x i16> %vec7, i16 %s, i32 7
-  store <8 x i16> %vec8, ptr %q, align 1
-  ret void
-}
-
 define void @insert_store_i16_align1(ptr %q, i16 zeroext %s) {
 ; CHECK-LABEL: @insert_store_i16_align1(
 ; CHECK-NEXT:  entry:
@@ -809,24 +734,6 @@ define void @insert_store_mem_modify_nonconst_index(ptr %p, i8 %s) {
   ret void
 }
 
-define void @insert_store_multi_nonconst_index_freeze(ptr %p, i8 %s, i8 %x, i8 %y) {
-; CHECK-LABEL: @insert_store_multi_nonconst_index_freeze(
-; CHECK-NEXT:    [[S_FROZEN:%.*]] = freeze i8 [[S:%.*]]
-; CHECK-NEXT:    [[IDX:%.*]] = and i8 [[S_FROZEN]], 1
-; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds <4 x i8>, ptr [[P:%.*]], i8 0, i8 [[IDX]]
-; CHECK-NEXT:    store i8 [[X:%.*]], ptr [[GEP1]], align 1
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <4 x i8>, ptr [[P]], i32 0, i32 2
-; CHECK-NEXT:    store i8 [[Y:%.*]], ptr [[TMP2]], align 2
-; CHECK-NEXT:    ret void
-;
-  %ld = load <4 x i8>, ptr %p, align 4
-  %idx = and i8 %s, 1
-  %ins0 = insertelement <4 x i8> %ld, i8 %x, i8 %idx
-  %ins1 = insertelement <4 x i8> %ins0, i8 %y, i32 2
-  store <4 x i8> %ins1, ptr %p, align 4
-  ret void
-}
-
 ; Check cases when calls may modify memory
 define void @insert_store_with_call(ptr %p, ptr %q, i8 %s) {
 ; CHECK-LABEL: @insert_store_with_call(
@@ -941,264 +848,3 @@ bb:
 
 declare i32 @bar(i32, i1) readonly
 declare double @llvm.log2.f64(double)
-
-define void @insert_store_gap(ptr %q, i16 zeroext %s) {
-; CHECK-LABEL: @insert_store_gap(
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 2
-; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 4
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 5
-; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 2
-; CHECK-NEXT:    ret void
-;
-  %load = load <8 x i16>, ptr %q
-  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 2
-  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 5
-  store <8 x i16> %vec2, ptr %q
-  ret void
-}
-
-define void @insert_store_reverse(ptr %q, i16 zeroext %s) {
-; CHECK-LABEL: @insert_store_reverse(
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 7
-; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 6
-; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 4
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 5
-; CHECK-NEXT:    store i16 [[S]], ptr [[TMP2]], align 2
-; CHECK-NEXT:    ret void
-;
-  %load = load <8 x i16>, ptr %q
-  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 7
-  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 6
-  %vec3 = insertelement <8 x i16> %vec2, i16 %s, i32 5
-  store <8 x i16> %vec3, ptr %q
-  ret void
-}
-
-define void @insert_store_duplicate(ptr %q, i16 zeroext %s) {
-; CHECK-LABEL: @insert_store_duplicate(
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 3
-; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q]], i32 0, i32 3
-; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 2
-; CHECK-NEXT:    ret void
-;
-  %load = load <8 x i16>, ptr %q
-  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 3
-  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 3
-  store <8 x i16> %vec2, ptr %q
-  ret void
-}
-
-define void @insert_store_i32(ptr %q, i32 zeroext %s) {
-; CHECK-LABEL: @insert_store_i32(
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q:%.*]], i32 0, i32 2
-; CHECK-NEXT:    store i32 [[S:%.*]], ptr [[TMP0]], align 8
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q]], i32 0, i32 3
-; CHECK-NEXT:    store i32 [[S]], ptr [[TMP1]], align 4
-; CHECK-NEXT:    ret void
-;
-  %load = load <4 x i32>, ptr %q
-  %vec1 = insertelement <4 x i32> %load, i32 %s, i32 2
-  %vec2 = insertelement <4 x i32> %vec1, i32 %s, i32 3
-  store <4 x i32> %vec2, ptr %q
-  ret void
-}
-
-define void @insert_store_i8(ptr %q, i8 zeroext %s) {
-; CHECK-LABEL: @insert_store_i8(
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 8
-; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 8
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q]], i32 0, i32 9
-; CHECK-NEXT:    store i8 [[S]], ptr [[TMP1]], align 1
-; CHECK-NEXT:    ret void
-;
-  %load = load <16 x i8>, ptr %q
-  %vec1 = insertelement <16 x i8> %load, i8 %s, i32 8
-  %vec2 = insertelement <16 x i8> %vec1, i8 %s, i32 9
-  store <16 x i8> %vec2, ptr %q
-  ret void
-}
-
-define void @insert_store_alignment(ptr %q, i16 zeroext %s) {
-; CHECK-LABEL: @insert_store_alignment(
-; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0:%.*]], align 16
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[TMP0]], i32 0, i32 4
-; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 8
-; CHECK-NEXT:    ret void
-;
-  %load = load <8 x i16>, ptr %q, align 16
-  %vec1 = insertelement <8 x i16> %load, i16 %s, i32 0
-  %vec2 = insertelement <8 x i16> %vec1, i16 %s, i32 4
-  store <8 x i16> %vec2, ptr %q, align 16
-  ret void
-}
-
-define void @insert_store_size(ptr %q, i16 zeroext %s) {
-; CHECK-LABEL: @insert_store_size(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i16>, ptr [[Q:%.*]], i32 0, i32 8
-; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 16
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i16>, ptr [[Q]], i32 0, i32 12
-; CHECK-NEXT:    store i16 [[S]], ptr [[TMP1]], align 8
-; CHECK-NEXT:    ret void
-;
-entry:
-  %load = load <16 x i16>, ptr %q
-  %vec1 = insertelement <16 x i16> %load, i16 %s, i32 8
-  %vec2 = insertelement <16 x i16> %vec1, i16 %s, i32 12
-  store <16 x i16> %vec2, ptr %q
-  ret void
-}
-
-define void @insert_store_nonconst4(ptr %q, i8 zeroext %s, i32 %idx1, i32 %idx2, i32 %idx3, i32 %idx4) {
-; CHECK-LABEL: @insert_store_nonconst4(
-; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = load <16 x i8>, ptr [[Q:%.*]], align 16
-; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX1:%.*]]
-; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <16 x i8> [[VECINS1]], i8 [[S]], i32 [[IDX2:%.*]]
-; CHECK-NEXT:    [[VECINS3:%.*]] = insertelement <16 x i8> [[VECINS2]], i8 [[S]], i32 [[IDX3:%.*]]
-; CHECK-NEXT:    [[VECINS4:%.*]] = insertelement <16 x i8> [[VECINS3]], i8 [[S]], i32 [[IDX4:%.*]]
-; CHECK-NEXT:    store <16 x i8> [[VECINS4]], ptr [[Q]], align 16
-; CHECK-NEXT:    ret void
-;
-entry:
-  %load = load <16 x i8>, ptr %q
-  %vecins1 = insertelement <16 x i8> %load, i8 %s, i32 %idx1
-  %vecins2 = insertelement <16 x i8> %vecins1, i8 %s, i32 %idx2
-  %vecins3 = insertelement <16 x i8> %vecins2, i8 %s, i32 %idx3
-  %vecins4 = insertelement <16 x i8> %vecins3, i8 %s, i32 %idx4
-  store <16 x i8> %vecins4, ptr %q
-  ret void
-}
-
-define void @insert_store_vscale_nonconst2(ptr %q, i8 zeroext %s, i32 %idx1, i32 %idx2) {
-; CHECK-LABEL: @insert_store_vscale_nonconst2(
-; CHECK-NEXT:    [[TMP0:%.*]] = load <vscale x 16 x i8>, ptr [[Q:%.*]], align 16
-; CHECK-NEXT:    [[VECINS1:%.*]] = insertelement <vscale x 16 x i8> [[TMP0]], i8 [[S:%.*]], i32 [[IDX1:%.*]]
-; CHECK-NEXT:    [[VECINS2:%.*]] = insertelement <vscale x 16 x i8> [[VECINS1]], i8 [[S]], i32 [[IDX2:%.*]]
-; CHECK-NEXT:    store <vscale x 16 x i8> [[VECINS2]], ptr [[Q]], align 16
-; CHECK-NEXT:    ret void
-;
-  %load = load <vscale x 16 x i8>, ptr %q
-  %vecins1 = insertelement <vscale x 16 x i8> %load, i8 %s, i32 %idx1
-  %vecins2 = insertelement <vscale x 16 x i8> %vecins1, i8 %s, i32 %idx2
-  store <vscale x 16 x i8> %vecins2, ptr %q
-  ret void
-}
-
-define void @insert_store_nonconst_large_alignment2(ptr %q, i32 zeroext %s, i32 %idx1, i32 %idx2) {
-; CHECK-LABEL: @insert_store_nonconst_large_alignment2(
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 4
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 4
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
-; CHECK-NEXT:    store i32 [[S:%.*]], ptr [[TMP0]], align 4
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q]], i32 0, i32 [[IDX2]]
-; CHECK-NEXT:    store i32 [[S]], ptr [[TMP1]], align 4
-; CHECK-NEXT:    ret void
-;
-  %cmp1 = icmp ult i32 %idx1, 4
-  %cmp2 = icmp ult i32 %idx2, 4
-  call void @llvm.assume(i1 %cmp1)
-  call void @llvm.assume(i1 %cmp2)
-  %i = load <4 x i32>, ptr %q, align 128
-  %vecins1 = insertelement <4 x i32> %i, i32 %s, i32 %idx1
-  %vecins2 = insertelement <4 x i32> %vecins1, i32 %s, i32 %idx2
-  store <4 x i32> %vecins2, ptr %q, align 128
-  ret void
-}
-
-define void @insert_store_nonconst_align_maximum_8_2(ptr %q, i64 %s, i32 %idx1, i32 %idx2) {
-; CHECK-LABEL: @insert_store_nonconst_align_maximum_8_2(
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 2
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
-; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 8
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q]], i32 0, i32 [[IDX2]]
-; CHECK-NEXT:    store i64 [[S]], ptr [[TMP2]], align 8
-; CHECK-NEXT:    ret void
-;
-  %cmp1 = icmp ult i32 %idx1, 2
-  %cmp2 = icmp ult i32 %idx2, 2
-  call void @llvm.assume(i1 %cmp1)
-  call void @llvm.assume(i1 %cmp2)
-  %i = load <8 x i64>, ptr %q, align 8
-  %vecins1 = insertelement <8 x i64> %i, i64 %s, i32 %idx1
-  %vecins2 = insertelement <8 x i64> %vecins1, i64 %s, i32 %idx2
-  store <8 x i64> %vecins2, ptr %q, align 8
-  ret void
-}
-
-define void @insert_store_nonconst_align_maximum_4_2(ptr %q, i64 %s, i32 %idx1, i32 %idx2) {
-; CHECK-LABEL: @insert_store_nonconst_align_maximum_4_2(
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 2
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
-; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 4
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q]], i32 0, i32 [[IDX2]]
-; CHECK-NEXT:    store i64 [[S]], ptr [[TMP2]], align 4
-; CHECK-NEXT:    ret void
-;
-  %cmp1 = icmp ult i32 %idx1, 2
-  %cmp2 = icmp ult i32 %idx2, 2
-  call void @llvm.assume(i1 %cmp1)
-  call void @llvm.assume(i1 %cmp2)
-  %i = load <8 x i64>, ptr %q, align 4
-  %vecins1 = insertelement <8 x i64> %i, i64 %s, i32 %idx1
-  %vecins2 = insertelement <8 x i64> %vecins1, i64 %s, i32 %idx2
-  store <8 x i64> %vecins2, ptr %q, align 4
-  ret void
-}
-
-define void @insert_store_nonconst_align_larger_2(ptr %q, i64 %s, i32 %idx1, i32 %idx2) {
-; CHECK-LABEL: @insert_store_nonconst_align_larger_2(
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[IDX1:%.*]], 2
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp ult i32 [[IDX2:%.*]], 2
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP1]])
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP2]])
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX1]]
-; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 4
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q]], i32 0, i32 [[IDX2]]
-; CHECK-NEXT:    store i64 [[S]], ptr [[TMP2]], align 4
-; CHECK-NEXT:    ret void
-;
-  %cmp1 = icmp ult i32 %idx1, 2
-  %cmp2 = icmp ult i32 %idx2, 2
-  call void @llvm.assume(i1 %cmp1)
-  call void @llvm.assume(i1 %cmp2)
-  %i = load <8 x i64>, ptr %q, align 4
-  %vecins1 = insertelement <8 x i64> %i, i64 %s, i32 %idx1
-  %vecins2 = insertelement <8 x i64> %vecins1, i64 %s, i32 %idx2
-  store <8 x i64> %vecins2, ptr %q, align 2
-  ret void
-}
-
-define void @insert_store_dynamic_indices_may_alias(ptr %p, i16 %a, i16 %b, i32 %i, i32 %j) {
-; CHECK-LABEL: @insert_store_dynamic_indices_may_alias(
-; CHECK-NEXT:    [[CI:%.*]] = icmp ult i32 [[I:%.*]], 8
-; CHECK-NEXT:    [[CJ:%.*]] = icmp ult i32 [[J:%.*]], 8
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CI]])
-; CHECK-NEXT:    call void @llvm.assume(i1 [[CJ]])
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P:%.*]], i32 0, i32 [[I]]
-; CHECK-NEXT:    store i16 [[A:%.*]], ptr [[TMP1]], align 2
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i16>, ptr [[P]], i32 0, i32 [[J]]
-; CHECK-NEXT:    store i16 [[B:%.*]], ptr [[TMP2]], align 2
-; CHECK-NEXT:    ret void
-;
-  %ci = icmp ult i32 %i, 8
-  %cj = icmp ult i32 %j, 8
-  call void @llvm.assume(i1 %ci)
-  call void @llvm.assume(i1 %cj)
-
-  %v = load <8 x i16>, ptr %p
-  %v1 = insertelement <8 x i16> %v, i16 %a, i32 %i
-  %v2 = insertelement <8 x i16> %v1, i16 %b, i32 %j
-  store <8 x i16> %v2, ptr %p
-  ret void
-}

>From 4d31d8713d109ed285283b2024e7e1717a256135 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Mon, 13 Jul 2026 17:58:09 +0900
Subject: [PATCH 8/9] formatting

---
 llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index a3edd53932fc7..37cf049a8d4e0 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1984,8 +1984,9 @@ static Align computeAlignmentAfterScalarization(Align VectorAlignment,
 ///        vector store <-- insertelement <-- ... <-- insertelement <-- load
 ///
 ///   Steps 3-5. Validate:
-///        reject unprofitable full overwrites; require simple accesses, a common
-///        address/block, no memory write in between, and scalarizable indices.
+///        reject unprofitable full overwrites; require simple accesses, a
+///        common address/block, no memory write in between, and scalarizable
+///        indices.
 bool VectorCombine::foldInsertElementsToStores(Instruction &I) {
   // Step 1: The target must support addressing a vector element with a GEP.
   if (!TTI.allowVectorElementIndexingUsingGEP())

>From 988f7e631be099c2afdb1d59e2ddbe5f138bd50f Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Mon, 13 Jul 2026 19:23:58 +0900
Subject: [PATCH 9/9] remove check prefix because it has same results

---
 .../VectorCombine/AArch64/load-insert-store.ll      |  7 ++-----
 .../VectorCombine/X86/load-insert-store.ll          | 13 ++++---------
 2 files changed, 6 insertions(+), 14 deletions(-)

diff --git a/llvm/test/Transforms/VectorCombine/AArch64/load-insert-store.ll b/llvm/test/Transforms/VectorCombine/AArch64/load-insert-store.ll
index ea2329c3a0ddb..a8dbe116aa35c 100644
--- a/llvm/test/Transforms/VectorCombine/AArch64/load-insert-store.ll
+++ b/llvm/test/Transforms/VectorCombine/AArch64/load-insert-store.ll
@@ -1,7 +1,7 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; Run the complete multi-insert suite for both AArch64 byte orders.
-; RUN: opt -S -passes=vector-combine -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,LE
-; RUN: opt -S -passes=vector-combine -mtriple=aarch64_be-unknown-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,BE
+; RUN: opt -S -passes=vector-combine -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s
+; RUN: opt -S -passes=vector-combine -mtriple=aarch64_be-unknown-linux-gnu < %s | FileCheck %s
 
 declare void @llvm.assume(i1)
 
@@ -387,6 +387,3 @@ define void @insert_store_dynamic_indices_may_alias(ptr %p, i16 %a, i16 %b, i32
   store <8 x i16> %v2, ptr %p
   ret void
 }
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; BE: {{.*}}
-; LE: {{.*}}
diff --git a/llvm/test/Transforms/VectorCombine/X86/load-insert-store.ll b/llvm/test/Transforms/VectorCombine/X86/load-insert-store.ll
index ae3741153517a..332473f019eaa 100644
--- a/llvm/test/Transforms/VectorCombine/X86/load-insert-store.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/load-insert-store.ll
@@ -1,9 +1,9 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; Run the multi-insert suite for each supported x86-64 CPU level.
-; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64 < %s | FileCheck %s --check-prefixes=CHECK,X64
-; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v2 < %s | FileCheck %s --check-prefixes=CHECK,X64V2
-; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v3 < %s | FileCheck %s --check-prefixes=CHECK,X64V3
-; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %s | FileCheck %s --check-prefixes=CHECK,X64V4
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64 < %s | FileCheck %s
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v2 < %s | FileCheck %s
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v3 < %s | FileCheck %s
+; RUN: opt -S -passes=vector-combine -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %s | FileCheck %s
 
 declare void @llvm.assume(i1)
 
@@ -389,8 +389,3 @@ define void @insert_store_dynamic_indices_may_alias(ptr %p, i16 %a, i16 %b, i32
   store <8 x i16> %v2, ptr %p
   ret void
 }
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; X64: {{.*}}
-; X64V2: {{.*}}
-; X64V3: {{.*}}
-; X64V4: {{.*}}



More information about the llvm-commits mailing list