[llvm] [VectorCombine] Preserve unsigned indices in scalarized GEPs (PR #212470)

via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 16 11:01:11 PDT 2026


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

>From c357204de2f7e4c8a67afecec5dec5f5c6593162 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Tue, 28 Jul 2026 19:34:22 +0900
Subject: [PATCH 1/7] Add scalarized GEP index regression coverage

---
 .../X86/load-extractelement-scalarization.ll  |  44 ++++++
 .../scalarized-gep-index-representability.ll  | 125 ++++++++++++++++++
 2 files changed, 169 insertions(+)
 create mode 100644 llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll

diff --git a/llvm/test/Transforms/VectorCombine/X86/load-extractelement-scalarization.ll b/llvm/test/Transforms/VectorCombine/X86/load-extractelement-scalarization.ll
index 61c35b6cd152e..9b7676b0c9a9a 100644
--- a/llvm/test/Transforms/VectorCombine/X86/load-extractelement-scalarization.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/load-extractelement-scalarization.ll
@@ -60,3 +60,47 @@ define i64 @dont_scalarize_atomic_bitcast(ptr %p) {
   %bitcast = bitcast <2 x i32> %load to i64
   ret i64 %bitcast
 }
+
+define i8 @load_extract_narrow_unsigned_constant(ptr %p) {
+; CHECK-LABEL: @load_extract_narrow_unsigned_constant(
+; CHECK-NEXT:    [[P8:%.*]] = getelementptr inbounds <16 x i8>, ptr [[P:%.*]], i32 0, i4 -8
+; CHECK-NEXT:    [[X:%.*]] = load i8, ptr [[P8]], align 1
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %v = load <16 x i8>, ptr %p, align 1
+  %x = extractelement <16 x i8> %v, i4 -8
+  ret i8 %x
+}
+
+define i8 @load_extract_narrow_unsigned_dynamic(ptr %p, i4 noundef %idx) {
+; CHECK-LABEL: @load_extract_narrow_unsigned_dynamic(
+; CHECK-NEXT:    [[BOUNDED:%.*]] = urem i4 [[IDX:%.*]], -1
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds <15 x i8>, ptr [[P:%.*]], i32 0, i4 [[BOUNDED]]
+; CHECK-NEXT:    [[X:%.*]] = load i8, ptr [[GEP]], align 1
+; CHECK-NEXT:    ret i8 [[X]]
+;
+  %bounded = urem i4 %idx, -1
+  %v = load <15 x i8>, ptr %p, align 1
+  %x = extractelement <15 x i8> %v, i4 %bounded
+  ret i8 %x
+}
+
+; Record the current profitability result before accounting for the dynamic
+; zext needed to preserve the unsigned lane number.
+define float @load_extract_narrow_unsigned_dynamic_unprofitable(
+    ptr %p, i2 noundef %idx) optsize {
+; CHECK-LABEL: @load_extract_narrow_unsigned_dynamic_unprofitable(
+; CHECK-NEXT:    [[BOUNDED:%.*]] = urem i2 [[IDX:%.*]], -1
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds <3 x float>, ptr [[P:%.*]], i32 0, i2 [[BOUNDED]]
+; CHECK-NEXT:    [[X:%.*]] = load float, ptr [[GEP]], align 1
+; CHECK-NEXT:    [[Y:%.*]] = load float, ptr [[P]], align 1
+; CHECK-NEXT:    [[SUM:%.*]] = fadd float [[X]], [[Y]]
+; CHECK-NEXT:    ret float [[SUM]]
+;
+  %bounded = urem i2 %idx, -1
+  %v = load <3 x float>, ptr %p, align 1
+  %x = extractelement <3 x float> %v, i2 %bounded
+  %y = extractelement <3 x float> %v, i2 0
+  %sum = fadd float %x, %y
+  ret float %sum
+}
diff --git a/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll b/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll
new file mode 100644
index 0000000000000..19a184afcb724
--- /dev/null
+++ b/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll
@@ -0,0 +1,125 @@
+; RUN: split-file %s %t
+; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %t/load.ll  | FileCheck %s --check-prefix=LOAD
+; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %t/store.ll | FileCheck %s --check-prefix=STORE
+; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %t/packed-stride.ll | FileCheck %s --check-prefix=PACKED
+; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %t/p32-index.ll | FileCheck %s --check-prefix=P32
+; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %t/p32-load-index.ll | FileCheck %s --check-prefix=P32LOAD
+
+;--- load.ll
+target datalayout = "e-p:64:64:64:8"
+
+; The lane range fits in the vector index, but its maximum byte offset does not
+; fit in the signed GEP index type. The transform must reject the candidate
+; without leaving a freeze behind or asserting on the pending freeze state.
+define i16 @load_extract_unrepresentable_offset(ptr %p, i8 %idx) {
+; LOAD-LABEL: define i16 @load_extract_unrepresentable_offset(
+; LOAD-SAME: ptr [[P:%.*]], i8 [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
+; LOAD-NEXT:    [[IDX_FROZEN:%.*]] = freeze i8 [[IDX]]
+; LOAD-NEXT:    [[BOUNDED:%.*]] = and i8 [[IDX_FROZEN]], 127
+; LOAD-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <128 x i16>, ptr [[P]], i32 0, i8 [[BOUNDED]]
+; LOAD-NEXT:    [[X:%.*]] = load i16, ptr [[TMP1]], align 2
+; LOAD-NEXT:    ret i16 [[X]]
+;
+  %bounded = and i8 %idx, 127
+  %v = load <128 x i16>, ptr %p, align 2
+  %x = extractelement <128 x i16> %v, i8 %bounded
+  ret i16 %x
+}
+
+;--- store.ll
+target datalayout = "e-p:64:64:64:8"
+
+define void @insert_store_unrepresentable_offset(ptr %p, i16 %x, i8 %idx) {
+; STORE-LABEL: define void @insert_store_unrepresentable_offset(
+; STORE-SAME: ptr [[P:%.*]], i16 [[X:%.*]], i8 [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
+; STORE-NEXT:    [[IDX_FROZEN:%.*]] = freeze i8 [[IDX]]
+; STORE-NEXT:    [[BOUNDED:%.*]] = and i8 [[IDX_FROZEN]], 127
+; STORE-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <128 x i16>, ptr [[P]], i8 0, i8 [[BOUNDED]]
+; STORE-NEXT:    store i16 [[X]], ptr [[TMP1]], align 2
+; STORE-NEXT:    ret void
+;
+  %bounded = and i8 %idx, 127
+  %v = load <128 x i16>, ptr %p, align 2
+  %v1 = insertelement <128 x i16> %v, i16 %x, i8 %bounded
+  store <128 x i16> %v1, ptr %p, align 2
+  ret void
+}
+
+;--- packed-stride.ll
+target datalayout = "e-p:64:64:64:8-i24:32:32"
+
+; Vector elements are tightly packed. For i24, the 3-byte element store size
+; keeps the maximum offset (42 * 3) representable by the signed i8 GEP index;
+; the 4-byte ABI allocation size does not.
+define void @insert_store_packed_i24_stride(ptr %p, i24 %x, i6 %idx) {
+; PACKED-LABEL: define void @insert_store_packed_i24_stride(
+; PACKED-SAME: ptr [[P:%.*]], i24 [[X:%.*]], i6 [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
+; PACKED-NEXT:    [[IDX_FROZEN:%.*]] = freeze i6 [[IDX]]
+; PACKED-NEXT:    [[BOUNDED:%.*]] = urem i6 [[IDX_FROZEN]], -21
+; PACKED-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <43 x i24>, ptr [[P]], i6 0, i6 [[BOUNDED]]
+; PACKED-NEXT:    store i24 [[X]], ptr [[TMP1]], align 1
+; PACKED-NEXT:    ret void
+;
+  %bounded = urem i6 %idx, 43
+  %v = load <43 x i24>, ptr %p, align 1
+  %v1 = insertelement <43 x i24> %v, i24 %x, i6 %bounded
+  store <43 x i24> %v1, ptr %p, align 1
+  ret void
+}
+
+;--- p32-index.ll
+target datalayout = "e-p:64:64:64:32"
+
+; A pointer's index type, rather than its pointer width, determines the
+; zero-extension destination type.
+define void @insert_store_dynamic_p32_index(ptr %p, i8 %x, i4 %idx) {
+; P32-LABEL: define void @insert_store_dynamic_p32_index(
+; P32-SAME: ptr [[P:%.*]], i8 [[X:%.*]], i4 [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
+; P32-NEXT:    [[IDX_FROZEN:%.*]] = freeze i4 [[IDX]]
+; P32-NEXT:    [[BOUNDED:%.*]] = urem i4 [[IDX_FROZEN]], -1
+; P32-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <15 x i8>, ptr [[P]], i4 0, i4 [[BOUNDED]]
+; P32-NEXT:    store i8 [[X]], ptr [[TMP1]], align 1
+; P32-NEXT:    ret void
+;
+  %bounded = urem i4 %idx, 15
+  %v = load <15 x i8>, ptr %p, align 1
+  %v1 = insertelement <15 x i8> %v, i8 %x, i4 %bounded
+  store <15 x i8> %v1, ptr %p, align 1
+  ret void
+}
+
+; The i4 bit pattern -2 denotes unsigned lane 14. Materializing it for an i32
+; GEP index must not create an instruction or reinterpret it as a negative
+; signed index.
+define void @insert_store_constant_high_bit_p32_index(ptr %p, i8 %x) {
+; P32-LABEL: define void @insert_store_constant_high_bit_p32_index(
+; P32-SAME: ptr [[P:%.*]], i8 [[X:%.*]]) #[[ATTR0]] {
+; P32-NEXT:    [[GEP:%.*]] = getelementptr inbounds <15 x i8>, ptr [[P]], i4 0, i4 -2
+; P32-NEXT:    store i8 [[X]], ptr [[GEP]], align 1
+; P32-NEXT:    ret void
+;
+  %v = load <15 x i8>, ptr %p, align 1
+  %v1 = insertelement <15 x i8> %v, i8 %x, i4 -2
+  store <15 x i8> %v1, ptr %p, align 1
+  ret void
+}
+
+;--- p32-load-index.ll
+target datalayout = "e-p:64:64:64:32"
+
+; scalarizeLoadExtract records index information before it replaces each
+; extract. The lookup must recover the 32-bit GEP index type for this extract.
+define i8 @load_extract_dynamic_p32_index(ptr %p, i4 %idx) {
+; P32LOAD-LABEL: define i8 @load_extract_dynamic_p32_index(
+; P32LOAD-SAME: ptr [[P:%.*]], i4 [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
+; P32LOAD-NEXT:    [[IDX_FROZEN:%.*]] = freeze i4 [[IDX]]
+; P32LOAD-NEXT:    [[BOUNDED:%.*]] = urem i4 [[IDX_FROZEN]], -1
+; P32LOAD-NEXT:    [[GEP:%.*]] = getelementptr inbounds <15 x i8>, ptr [[P]], i32 0, i4 [[BOUNDED]]
+; P32LOAD-NEXT:    [[X:%.*]] = load i8, ptr [[GEP]], align 1
+; P32LOAD-NEXT:    ret i8 [[X]]
+;
+  %bounded = urem i4 %idx, 15
+  %v = load <15 x i8>, ptr %p, align 1
+  %x = extractelement <15 x i8> %v, i4 %bounded
+  ret i8 %x
+}

>From 63a726849acf1306ebd52395a20cb9fcedf87a4c Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Tue, 28 Jul 2026 19:35:12 +0900
Subject: [PATCH 2/7] [VectorCombine] Preserve unsigned indices in scalarized
 GEPs

Scalarized load and store GEPs currently reuse the extract/insert index
directly. Narrow integer indices are unsigned lane numbers, but GEP
sign-extends them to the pointer index type, which can select the wrong
address.Check that the largest byte offset is representable, zero-extend
narrow indices when required, account for the cast cost, and use the
element store size when checking packed layouts. Update all affected
regression expectations.

Fixes #212468

Assisted-by: Codex
---
 .../Transforms/Vectorize/VectorCombine.cpp    | 135 +++++++++++++++++-
 ...load-extract-insert-store-scalarization.ll |  10 +-
 .../load-extractelement-scalarization.ll      |  36 ++---
 .../X86/load-extractelement-scalarization.ll  |  17 +--
 .../scalarized-gep-index-representability.ll  |  32 ++---
 llvm/test/Transforms/VectorCombine/alias.ll   |   8 +-
 6 files changed, 182 insertions(+), 56 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 726f564b1aad9..2a1dda6b9de9e 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1942,6 +1942,102 @@ static ScalarizationResult canScalarizeAccess(VectorType *VecTy, Value *Idx,
   return ScalarizationResult::unsafe();
 }
 
+struct ScalarizedGEPIndexInfo {
+  IntegerType *GEPIndexTy;
+  bool NeedsZExt;
+};
+
+/// Return true and populate \p Info if the unsigned vector index \p Idx can be
+/// represented by an inbounds GEP. Record whether an explicit zero-extension
+/// is required to preserve its value when GEP converts the index to the pointer
+/// index type.
+///
+///   unsigned lane range
+///                |
+///                v
+///   MaxByteOffset = MaxLane * element store size
+///                |
+///                +-- unavailable or outside signed GEP range --> reject
+///                |
+///                v
+///   narrow Idx may set its sign bit?
+///          | yes                 | no
+///          v                     v
+///   NeedsZExt = true      NeedsZExt = false
+static bool getScalarizedGEPIndexInfo(VectorType *VecTy, Value *Idx,
+                                      Type *PtrTy, const DataLayout &DL,
+                                      ScalarizedGEPIndexInfo &Info) {
+  auto *GEPIndexTy = cast<IntegerType>(DL.getIndexType(PtrTy));
+  unsigned SrcBits = Idx->getType()->getIntegerBitWidth();
+  unsigned GEPBits = GEPIndexTy->getBitWidth();
+  uint64_t NumElements = VecTy->getElementCount().getKnownMinValue();
+
+  uint64_t MaxLane = NumElements - 1;
+  if (auto *C = dyn_cast<ConstantInt>(Idx)) {
+    if (C->getValue().uge(NumElements))
+      return false;
+    MaxLane = C->getZExtValue();
+  }
+
+  Type *ElemTy = VecTy->getElementType();
+  if (!DL.typeSizeEqualsStoreSize(ElemTy))
+    return false;
+
+  TypeSize ElemStride = DL.getTypeStoreSize(ElemTy);
+  if (ElemStride.isScalable())
+    return false;
+
+  // Compare both values in a common width:
+  //
+  //   MaxLane (uint64_t) * ElemStride (uint64_t)   signed_max(GEPBits)
+  //                         |                               |
+  //                         v                               v
+  //             ByteOffset (up to 128 bits)        sext to WideBits
+  //                         \                               /
+  //                          +------------ ugt ------------+
+  //                                       |
+  //                                greater -> reject
+  //
+  // WideBits = max(GEPBits, 128) prevents the multiplication from wrapping
+  // and preserves the GEP limit during the comparison.
+  unsigned WideBits = std::max(GEPBits, 128u);
+  APInt MaxLaneValue(WideBits, MaxLane);
+  APInt ByteOffset = MaxLaneValue;
+  ByteOffset *= APInt(WideBits, ElemStride.getFixedValue());
+  APInt MaxGEPOffset = APInt::getSignedMaxValue(GEPBits).sext(WideBits);
+  // Reject offsets outside the GEP's positive signed range. Compare as
+  // unsigned because the full 128-bit product may set its sign bit.
+  if (ByteOffset.ugt(MaxGEPOffset))
+    return false;
+
+  // GEP sign-extends narrow indices, so request a zext if a valid unsigned
+  // lane may set the source sign bit.
+  bool NeedsZExt = false;
+  if (SrcBits < GEPBits) {
+    APInt SignedMax = APInt::getSignedMaxValue(SrcBits).zext(WideBits);
+    NeedsZExt = MaxLaneValue.ugt(SignedMax);
+  }
+  Info = {GEPIndexTy, NeedsZExt};
+  return true;
+}
+
+/// Materialize an index for a scalarized GEP after profitability is known.
+static Value *materializeScalarizedGEPIndex(Value *Idx,
+                                            const ScalarizedGEPIndexInfo &Info,
+                                            IRBuilderBase &Builder) {
+  if (!Info.NeedsZExt)
+    return Idx;
+
+  unsigned DstBits = Info.GEPIndexTy->getBitWidth();
+  assert(Idx->getType()->getIntegerBitWidth() < DstBits &&
+         "Expected a widening zero-extension");
+
+  if (auto *C = dyn_cast<ConstantInt>(Idx))
+    return ConstantInt::get(Info.GEPIndexTy, C->getValue().zext(DstBits));
+
+  return Builder.CreateZExt(Idx, Info.GEPIndexTy, Idx->getName() + ".gepidx");
+}
+
 /// The memory operation on a vector of \p ScalarType had alignment of
 /// \p VectorAlignment. Compute the maximal, but conservatively correct,
 /// alignment that will be valid for the memory operation on a single scalar
@@ -1998,15 +2094,24 @@ bool VectorCombine::foldSingleElementStore(Instruction &I) {
     if (ScalarizableIdx.isUnsafe())
       return false;
 
+    ScalarizedGEPIndexInfo GEPIndexInfo;
+    if (!getScalarizedGEPIndexInfo(VecTy, Idx, SI->getPointerOperandType(), *DL,
+                                   GEPIndexInfo)) {
+      ScalarizableIdx.discard();
+      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);
 
     if (ScalarizableIdx.isSafeWithFreeze())
       ScalarizableIdx.freeze(Builder, *cast<Instruction>(Idx));
+    Value *GEPIdx =
+        materializeScalarizedGEPIndex(Idx, GEPIndexInfo, Builder);
     Value *GEP = Builder.CreateInBoundsGEP(
         SI->getValueOperand()->getType(), SI->getPointerOperand(),
-        {ConstantInt::get(Idx->getType(), 0), Idx});
+        {ConstantInt::get(GEPIdx->getType(), 0), GEPIdx});
     StoreInst *NSI = Builder.CreateStore(NewElement, GEP);
     NSI->copyMetadata(*SI);
     Align ScalarOpAlignment = computeAlignmentAfterScalarization(
@@ -2087,6 +2192,7 @@ bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
     return false;
 
   DenseMap<ExtractElementInst *, ScalarizationResult> NeedFreeze;
+  DenseMap<ExtractElementInst *, ScalarizedGEPIndexInfo> GEPIndexInfos;
   llvm::scope_exit FailureGuard([&]() {
     // If the transform is aborted, discard the ScalarizationResults.
     for (auto &Pair : NeedFreeze)
@@ -2105,6 +2211,17 @@ bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
                                         SQ.getWithInstruction(LI));
     if (ScalarIdx.isUnsafe())
       return false;
+
+    ScalarizedGEPIndexInfo GEPIndexInfo;
+    if (!getScalarizedGEPIndexInfo(VecTy, UI->getIndexOperand(),
+                                   LI->getPointerOperandType(), *DL,
+                                   GEPIndexInfo)) {
+      ScalarIdx.discard();
+      return false;
+    }
+
+    GEPIndexInfos.try_emplace(UI, GEPIndexInfo);
+
     if (ScalarIdx.isSafeWithFreeze()) {
       NeedFreeze.try_emplace(UI, ScalarIdx);
       ScalarIdx.discard();
@@ -2119,6 +2236,11 @@ bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
                             Align(1), LI->getPointerAddressSpace(), CostKind);
     ScalarizedCost += TTI.getAddressComputationCost(LI->getPointerOperandType(),
                                                     nullptr, nullptr, CostKind);
+    if (!Index && GEPIndexInfo.NeedsZExt)
+      ScalarizedCost +=
+          TTI.getCastInstrCost(Instruction::ZExt, GEPIndexInfo.GEPIndexTy,
+                               UI->getIndexOperand()->getType(),
+                               TTI::CastContextHint::None, CostKind);
   }
 
   LLVM_DEBUG(dbgs() << "Found all extractions of a vector load: " << *LI
@@ -2140,13 +2262,16 @@ bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
     Value *Idx = EI->getIndexOperand();
 
     // Insert 'freeze' for poison indexes.
-    auto It = NeedFreeze.find(EI);
-    if (It != NeedFreeze.end())
+    if (auto It = NeedFreeze.find(EI); It != NeedFreeze.end())
       It->second.freeze(Builder, *cast<Instruction>(Idx));
 
     Builder.SetInsertPoint(EI);
-    Value *GEP =
-        Builder.CreateInBoundsGEP(VecTy, Ptr, {Builder.getInt32(0), Idx});
+    auto It = GEPIndexInfos.find(EI);
+    assert(It != GEPIndexInfos.end() &&
+           "Missing scalarized GEP index information");
+    Value *GEPIdx = materializeScalarizedGEPIndex(Idx, It->second, Builder);
+    Value *GEP = Builder.CreateInBoundsGEP(
+        VecTy, Ptr, {ConstantInt::get(GEPIdx->getType(), 0), GEPIdx});
     auto *NewLoad = cast<LoadInst>(
         Builder.CreateLoad(ElemType, GEP, EI->getName() + ".scalar"));
 
diff --git a/llvm/test/Transforms/VectorCombine/AArch64/load-extract-insert-store-scalarization.ll b/llvm/test/Transforms/VectorCombine/AArch64/load-extract-insert-store-scalarization.ll
index 391215b3e4159..5925378bb99a1 100644
--- a/llvm/test/Transforms/VectorCombine/AArch64/load-extract-insert-store-scalarization.ll
+++ b/llvm/test/Transforms/VectorCombine/AArch64/load-extract-insert-store-scalarization.ll
@@ -8,7 +8,7 @@ define void @load_extract_insert_store_const_idx(ptr %A) {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[EXT_0:%.*]] = load double, ptr [[TMP0:%.*]], align 8
 ; CHECK-NEXT:    [[MUL:%.*]] = fmul double 2.000000e+01, [[EXT_0]]
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <225 x double>, ptr [[TMP0]], i32 0, i64 1
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <225 x double>, ptr [[TMP0]], i64 0, i64 1
 ; CHECK-NEXT:    [[EXT_1:%.*]] = load double, ptr [[TMP1]], align 8
 ; CHECK-NEXT:    [[SUB:%.*]] = fsub double [[EXT_1]], [[MUL]]
 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <225 x double>, ptr [[TMP0]], i64 0, i64 1
@@ -33,10 +33,10 @@ define void @load_extract_insert_store_var_idx_assume_valid(i64 %idx.1, i64 %idx
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_1]])
 ; CHECK-NEXT:    [[CMP_2:%.*]] = icmp ult i64 [[IDX_2:%.*]], 225
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_2]])
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <225 x double>, ptr [[A:%.*]], i32 0, i64 [[IDX_1]]
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <225 x double>, ptr [[A:%.*]], i64 0, i64 [[IDX_1]]
 ; CHECK-NEXT:    [[EXT_0:%.*]] = load double, ptr [[TMP0]], align 8
 ; CHECK-NEXT:    [[MUL:%.*]] = fmul double 2.000000e+01, [[EXT_0]]
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <225 x double>, ptr [[A]], i32 0, i64 [[IDX_2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <225 x double>, ptr [[A]], i64 0, i64 [[IDX_2]]
 ; CHECK-NEXT:    [[EXT_1:%.*]] = load double, ptr [[TMP1]], align 8
 ; CHECK-NEXT:    [[SUB:%.*]] = fsub double [[EXT_1]], [[MUL]]
 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <225 x double>, ptr [[A]], i64 0, i64 [[IDX_1]]
@@ -70,10 +70,10 @@ define void @load_extract_insert_store_var_idx_assume_valid_in_dominating_block(
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_2]])
 ; CHECK-NEXT:    br i1 [[C_1:%.*]], label [[LOOP:%.*]], label [[EXIT:%.*]]
 ; CHECK:       loop:
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <225 x double>, ptr [[A:%.*]], i32 0, i64 [[IDX_1]]
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <225 x double>, ptr [[A:%.*]], i64 0, i64 [[IDX_1]]
 ; CHECK-NEXT:    [[EXT_0:%.*]] = load double, ptr [[TMP0]], align 8
 ; CHECK-NEXT:    [[MUL:%.*]] = fmul double 2.000000e+01, [[EXT_0]]
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <225 x double>, ptr [[A]], i32 0, i64 [[IDX_2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <225 x double>, ptr [[A]], i64 0, i64 [[IDX_2]]
 ; CHECK-NEXT:    [[EXT_1:%.*]] = load double, ptr [[TMP1]], align 8
 ; CHECK-NEXT:    [[SUB:%.*]] = fsub double [[EXT_1]], [[MUL]]
 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <225 x double>, ptr [[A]], i64 0, i64 [[IDX_1]]
diff --git a/llvm/test/Transforms/VectorCombine/AArch64/load-extractelement-scalarization.ll b/llvm/test/Transforms/VectorCombine/AArch64/load-extractelement-scalarization.ll
index d4278c86383a1..50ca00536856c 100644
--- a/llvm/test/Transforms/VectorCombine/AArch64/load-extractelement-scalarization.ll
+++ b/llvm/test/Transforms/VectorCombine/AArch64/load-extractelement-scalarization.ll
@@ -123,7 +123,7 @@ define i32 @load_extract_idx_var_i64_known_valid_by_assume(ptr %x, i64 %idx) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 4
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
 ; CHECK-NEXT:    call void @maythrow()
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i64 [[IDX]]
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 [[IDX]]
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP0]], align 4
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -142,7 +142,7 @@ define i32 @vscale_load_extract_idx_var_i64_known_valid_by_assume(ptr %x, i64 %i
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[IDX:%.*]], 4
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
 ; CHECK-NEXT:    call void @maythrow()
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 4 x i32>, ptr [[X:%.*]], i32 0, i64 [[IDX]]
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 4 x i32>, ptr [[X:%.*]], i64 0, i64 [[IDX]]
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP0]], align 4
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -165,7 +165,7 @@ define i32 @load_extract_idx_var_i64_known_valid_by_assume_in_dominating_block(p
 ; CHECK-NEXT:    br i1 [[C_1:%.*]], label [[LOOP:%.*]], label [[EXIT:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    call void @maythrow()
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i64 [[IDX]]
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 [[IDX]]
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP0]], align 4
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP]], label [[EXIT]]
@@ -310,7 +310,7 @@ define i32 @load_extract_idx_var_i64_known_valid_by_and(ptr %x, i64 %idx) {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[IDX_FROZEN:%.*]] = freeze i64 [[IDX:%.*]]
 ; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i64 [[IDX_FROZEN]], 3
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]]
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 [[IDX_CLAMPED]]
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP0]], align 4
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -326,7 +326,7 @@ define i32 @vscale_load_extract_idx_var_i64_known_valid_by_and(ptr %x, i64 %idx)
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[IDX_FROZEN:%.*]] = freeze i64 [[IDX:%.*]]
 ; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i64 [[IDX_FROZEN]], 3
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 4 x i32>, ptr [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]]
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 4 x i32>, ptr [[X:%.*]], i64 0, i64 [[IDX_CLAMPED]]
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP0]], align 4
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -341,7 +341,7 @@ define i32 @load_extract_idx_var_i64_known_valid_by_and_noundef(ptr %x, i64 noun
 ; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_and_noundef(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i64 [[IDX:%.*]], 3
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]]
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 [[IDX_CLAMPED]]
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP0]], align 4
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -387,7 +387,7 @@ define i32 @load_extract_idx_var_i64_known_valid_by_urem(ptr %x, i64 %idx) {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[IDX_FROZEN:%.*]] = freeze i64 [[IDX:%.*]]
 ; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i64 [[IDX_FROZEN]], 4
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]]
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 [[IDX_CLAMPED]]
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP0]], align 4
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -403,7 +403,7 @@ define i32 @vscale_load_extract_idx_var_i64_known_valid_by_urem(ptr %x, i64 %idx
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[IDX_FROZEN:%.*]] = freeze i64 [[IDX:%.*]]
 ; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i64 [[IDX_FROZEN]], 4
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 4 x i32>, ptr [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]]
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 4 x i32>, ptr [[X:%.*]], i64 0, i64 [[IDX_CLAMPED]]
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP0]], align 4
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -418,7 +418,7 @@ define i32 @load_extract_idx_var_i64_known_valid_by_urem_noundef(ptr %x, i64 nou
 ; CHECK-LABEL: @load_extract_idx_var_i64_known_valid_by_urem_noundef(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i64 [[IDX:%.*]], 4
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]]
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 [[IDX_CLAMPED]]
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP0]], align 4
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -743,9 +743,9 @@ define i32 @load_multiple_extracts_with_variable_indices_large_vector_only_all_v
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_IDX_0]])
 ; CHECK-NEXT:    [[CMP_IDX_1:%.*]] = icmp ult i64 [[IDX_1:%.*]], 16
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP_IDX_1]])
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X:%.*]], i32 0, i64 [[IDX_0]]
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X:%.*]], i64 0, i64 [[IDX_0]]
 ; CHECK-NEXT:    [[E_0:%.*]] = load i32, ptr [[TMP1]], align 4
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X]], i32 0, i64 [[IDX_1]]
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X]], i64 0, i64 [[IDX_1]]
 ; CHECK-NEXT:    [[E_1:%.*]] = load i32, ptr [[TMP2]], align 4
 ; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
 ; CHECK-NEXT:    ret i32 [[RES]]
@@ -786,9 +786,9 @@ define i32 @load_multiple_extracts_with_variable_indices_large_vector_all_valid_
 ; CHECK-NEXT:    [[IDX_0_CLAMPED:%.*]] = and i64 [[IDX_0_FROZEN]], 15
 ; CHECK-NEXT:    [[IDX_1_FROZEN:%.*]] = freeze i64 [[IDX_1:%.*]]
 ; CHECK-NEXT:    [[IDX_1_CLAMPED:%.*]] = and i64 [[IDX_1_FROZEN]], 15
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X:%.*]], i32 0, i64 [[IDX_0_CLAMPED]]
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X:%.*]], i64 0, i64 [[IDX_0_CLAMPED]]
 ; CHECK-NEXT:    [[E_0:%.*]] = load i32, ptr [[TMP1]], align 4
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X]], i32 0, i64 [[IDX_1_CLAMPED]]
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X]], i64 0, i64 [[IDX_1_CLAMPED]]
 ; CHECK-NEXT:    [[E_1:%.*]] = load i32, ptr [[TMP2]], align 4
 ; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
 ; CHECK-NEXT:    ret i32 [[RES]]
@@ -807,9 +807,9 @@ define i32 @load_multiple_extracts_with_unique_variable_indices_large_vector_val
 ; LIMIT-DEFAULT-LABEL: @load_multiple_extracts_with_unique_variable_indices_large_vector_valid_by_and(
 ; LIMIT-DEFAULT-NEXT:    [[IDX_FROZEN:%.*]] = freeze i64 [[IDX:%.*]]
 ; LIMIT-DEFAULT-NEXT:    [[IDX_CLAMPED:%.*]] = and i64 [[IDX_FROZEN]], 15
-; LIMIT-DEFAULT-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]]
+; LIMIT-DEFAULT-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X:%.*]], i64 0, i64 [[IDX_CLAMPED]]
 ; LIMIT-DEFAULT-NEXT:    [[E_0:%.*]] = load i32, ptr [[TMP1]], align 4
-; LIMIT-DEFAULT-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <16 x i32>, ptr [[Y:%.*]], i32 0, i64 [[IDX_CLAMPED]]
+; LIMIT-DEFAULT-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <16 x i32>, ptr [[Y:%.*]], i64 0, i64 [[IDX_CLAMPED]]
 ; LIMIT-DEFAULT-NEXT:    [[E_1:%.*]] = load i32, ptr [[TMP2]], align 4
 ; LIMIT-DEFAULT-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
 ; LIMIT-DEFAULT-NEXT:    ret i32 [[RES]]
@@ -818,7 +818,7 @@ define i32 @load_multiple_extracts_with_unique_variable_indices_large_vector_val
 ; LIMIT2-NEXT:    [[IDX_FROZEN:%.*]] = freeze i64 [[IDX:%.*]]
 ; LIMIT2-NEXT:    [[IDX_CLAMPED:%.*]] = and i64 [[IDX_FROZEN]], 15
 ; LIMIT2-NEXT:    [[LY:%.*]] = load <16 x i32>, ptr [[Y:%.*]], align 64
-; LIMIT2-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X:%.*]], i32 0, i64 [[IDX_CLAMPED]]
+; LIMIT2-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X:%.*]], i64 0, i64 [[IDX_CLAMPED]]
 ; LIMIT2-NEXT:    [[E_0:%.*]] = load i32, ptr [[TMP1]], align 4
 ; LIMIT2-NEXT:    [[E_1:%.*]] = extractelement <16 x i32> [[LY]], i64 [[IDX_CLAMPED]]
 ; LIMIT2-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
@@ -839,9 +839,9 @@ define i32 @load_multiple_extracts_with_variable_indices_large_vector_all_valid_
 ; CHECK-NEXT:    [[IDX_0_FROZEN:%.*]] = freeze i64 [[IDX_0:%.*]]
 ; CHECK-NEXT:    [[IDX_0_CLAMPED:%.*]] = and i64 [[IDX_0_FROZEN]], 15
 ; CHECK-NEXT:    [[IDX_1_CLAMPED:%.*]] = and i64 [[IDX_1:%.*]], 15
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X:%.*]], i32 0, i64 [[IDX_0_CLAMPED]]
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X:%.*]], i64 0, i64 [[IDX_0_CLAMPED]]
 ; CHECK-NEXT:    [[E_0:%.*]] = load i32, ptr [[TMP1]], align 4
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X]], i32 0, i64 [[IDX_1_CLAMPED]]
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <16 x i32>, ptr [[X]], i64 0, i64 [[IDX_1_CLAMPED]]
 ; CHECK-NEXT:    [[E_1:%.*]] = load i32, ptr [[TMP2]], align 4
 ; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
 ; CHECK-NEXT:    ret i32 [[RES]]
diff --git a/llvm/test/Transforms/VectorCombine/X86/load-extractelement-scalarization.ll b/llvm/test/Transforms/VectorCombine/X86/load-extractelement-scalarization.ll
index 9b7676b0c9a9a..3d892d4286dff 100644
--- a/llvm/test/Transforms/VectorCombine/X86/load-extractelement-scalarization.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/load-extractelement-scalarization.ll
@@ -7,7 +7,7 @@ define void @multiple_extract(ptr %p) {
 ; CHECK-LABEL: @multiple_extract(
 ; CHECK-NEXT:    [[VP:%.*]] = load ptr, ptr [[P:%.*]], align 8
 ; CHECK-NEXT:    [[E0:%.*]] = load i32, ptr [[VP]], align 16
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <2 x i32>, ptr [[VP]], i32 0, i64 1
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <2 x i32>, ptr [[VP]], i64 0, i64 1
 ; CHECK-NEXT:    [[E1:%.*]] = load i32, ptr [[TMP2]], align 4
 ; CHECK-NEXT:    store i32 [[E0]], ptr [[P]], align 4
 ; CHECK-NEXT:    [[P1:%.*]] = getelementptr inbounds nuw i8, ptr [[P]], i64 4
@@ -63,7 +63,7 @@ define i64 @dont_scalarize_atomic_bitcast(ptr %p) {
 
 define i8 @load_extract_narrow_unsigned_constant(ptr %p) {
 ; CHECK-LABEL: @load_extract_narrow_unsigned_constant(
-; CHECK-NEXT:    [[P8:%.*]] = getelementptr inbounds <16 x i8>, ptr [[P:%.*]], i32 0, i4 -8
+; CHECK-NEXT:    [[P8:%.*]] = getelementptr inbounds <16 x i8>, ptr [[P:%.*]], i64 0, i64 8
 ; CHECK-NEXT:    [[X:%.*]] = load i8, ptr [[P8]], align 1
 ; CHECK-NEXT:    ret i8 [[X]]
 ;
@@ -75,7 +75,8 @@ define i8 @load_extract_narrow_unsigned_constant(ptr %p) {
 define i8 @load_extract_narrow_unsigned_dynamic(ptr %p, i4 noundef %idx) {
 ; CHECK-LABEL: @load_extract_narrow_unsigned_dynamic(
 ; CHECK-NEXT:    [[BOUNDED:%.*]] = urem i4 [[IDX:%.*]], -1
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds <15 x i8>, ptr [[P:%.*]], i32 0, i4 [[BOUNDED]]
+; CHECK-NEXT:    [[GEPIDX:%.*]] = zext i4 [[BOUNDED]] to i64
+; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds <15 x i8>, ptr [[P:%.*]], i64 0, i64 [[GEPIDX]]
 ; CHECK-NEXT:    [[X:%.*]] = load i8, ptr [[GEP]], align 1
 ; CHECK-NEXT:    ret i8 [[X]]
 ;
@@ -85,15 +86,15 @@ define i8 @load_extract_narrow_unsigned_dynamic(ptr %p, i4 noundef %idx) {
   ret i8 %x
 }
 
-; Record the current profitability result before accounting for the dynamic
-; zext needed to preserve the unsigned lane number.
+; The dynamic zext makes scalarization no cheaper for code size. Keep the
+; vector load and extracts, and do not leave an orphan cast behind.
 define float @load_extract_narrow_unsigned_dynamic_unprofitable(
     ptr %p, i2 noundef %idx) optsize {
 ; CHECK-LABEL: @load_extract_narrow_unsigned_dynamic_unprofitable(
 ; CHECK-NEXT:    [[BOUNDED:%.*]] = urem i2 [[IDX:%.*]], -1
-; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds <3 x float>, ptr [[P:%.*]], i32 0, i2 [[BOUNDED]]
-; CHECK-NEXT:    [[X:%.*]] = load float, ptr [[GEP]], align 1
-; CHECK-NEXT:    [[Y:%.*]] = load float, ptr [[P]], align 1
+; CHECK-NEXT:    [[V:%.*]] = load <3 x float>, ptr [[P:%.*]], align 1
+; CHECK-NEXT:    [[X:%.*]] = extractelement <3 x float> [[V]], i2 [[BOUNDED]]
+; CHECK-NEXT:    [[Y:%.*]] = extractelement <3 x float> [[V]], i2 0
 ; CHECK-NEXT:    [[SUM:%.*]] = fadd float [[X]], [[Y]]
 ; CHECK-NEXT:    ret float [[SUM]]
 ;
diff --git a/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll b/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll
index 19a184afcb724..f78e6edea0aad 100644
--- a/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll
@@ -12,12 +12,10 @@ target datalayout = "e-p:64:64:64:8"
 ; fit in the signed GEP index type. The transform must reject the candidate
 ; without leaving a freeze behind or asserting on the pending freeze state.
 define i16 @load_extract_unrepresentable_offset(ptr %p, i8 %idx) {
-; LOAD-LABEL: define i16 @load_extract_unrepresentable_offset(
-; LOAD-SAME: ptr [[P:%.*]], i8 [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
-; LOAD-NEXT:    [[IDX_FROZEN:%.*]] = freeze i8 [[IDX]]
-; LOAD-NEXT:    [[BOUNDED:%.*]] = and i8 [[IDX_FROZEN]], 127
-; LOAD-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <128 x i16>, ptr [[P]], i32 0, i8 [[BOUNDED]]
-; LOAD-NEXT:    [[X:%.*]] = load i16, ptr [[TMP1]], align 2
+; LOAD-LABEL: @load_extract_unrepresentable_offset(
+; LOAD-NEXT:    [[BOUNDED:%.*]] = and i8 [[IDX:%.*]], 127
+; LOAD-NEXT:    [[V:%.*]] = load <128 x i16>, ptr [[P:%.*]], align 2
+; LOAD-NEXT:    [[X:%.*]] = extractelement <128 x i16> [[V]], i8 [[BOUNDED]]
 ; LOAD-NEXT:    ret i16 [[X]]
 ;
   %bounded = and i8 %idx, 127
@@ -30,12 +28,11 @@ define i16 @load_extract_unrepresentable_offset(ptr %p, i8 %idx) {
 target datalayout = "e-p:64:64:64:8"
 
 define void @insert_store_unrepresentable_offset(ptr %p, i16 %x, i8 %idx) {
-; STORE-LABEL: define void @insert_store_unrepresentable_offset(
-; STORE-SAME: ptr [[P:%.*]], i16 [[X:%.*]], i8 [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
-; STORE-NEXT:    [[IDX_FROZEN:%.*]] = freeze i8 [[IDX]]
-; STORE-NEXT:    [[BOUNDED:%.*]] = and i8 [[IDX_FROZEN]], 127
-; STORE-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <128 x i16>, ptr [[P]], i8 0, i8 [[BOUNDED]]
-; STORE-NEXT:    store i16 [[X]], ptr [[TMP1]], align 2
+; STORE-LABEL: @insert_store_unrepresentable_offset(
+; STORE-NEXT:    [[BOUNDED:%.*]] = and i8 [[IDX:%.*]], 127
+; STORE-NEXT:    [[V:%.*]] = load <128 x i16>, ptr [[P:%.*]], align 2
+; STORE-NEXT:    [[V1:%.*]] = insertelement <128 x i16> [[V]], i16 [[X:%.*]], i8 [[BOUNDED]]
+; STORE-NEXT:    store <128 x i16> [[V1]], ptr [[P]], align 2
 ; STORE-NEXT:    ret void
 ;
   %bounded = and i8 %idx, 127
@@ -56,7 +53,8 @@ define void @insert_store_packed_i24_stride(ptr %p, i24 %x, i6 %idx) {
 ; PACKED-SAME: ptr [[P:%.*]], i24 [[X:%.*]], i6 [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
 ; PACKED-NEXT:    [[IDX_FROZEN:%.*]] = freeze i6 [[IDX]]
 ; PACKED-NEXT:    [[BOUNDED:%.*]] = urem i6 [[IDX_FROZEN]], -21
-; PACKED-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <43 x i24>, ptr [[P]], i6 0, i6 [[BOUNDED]]
+; PACKED-NEXT:    [[BOUNDED_GEPIDX:%.*]] = zext i6 [[BOUNDED]] to i8
+; PACKED-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <43 x i24>, ptr [[P]], i8 0, i8 [[BOUNDED_GEPIDX]]
 ; PACKED-NEXT:    store i24 [[X]], ptr [[TMP1]], align 1
 ; PACKED-NEXT:    ret void
 ;
@@ -77,7 +75,8 @@ define void @insert_store_dynamic_p32_index(ptr %p, i8 %x, i4 %idx) {
 ; P32-SAME: ptr [[P:%.*]], i8 [[X:%.*]], i4 [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
 ; P32-NEXT:    [[IDX_FROZEN:%.*]] = freeze i4 [[IDX]]
 ; P32-NEXT:    [[BOUNDED:%.*]] = urem i4 [[IDX_FROZEN]], -1
-; P32-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <15 x i8>, ptr [[P]], i4 0, i4 [[BOUNDED]]
+; P32-NEXT:    [[BOUNDED_GEPIDX:%.*]] = zext i4 [[BOUNDED]] to i32
+; P32-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <15 x i8>, ptr [[P]], i32 0, i32 [[BOUNDED_GEPIDX]]
 ; P32-NEXT:    store i8 [[X]], ptr [[TMP1]], align 1
 ; P32-NEXT:    ret void
 ;
@@ -94,7 +93,7 @@ define void @insert_store_dynamic_p32_index(ptr %p, i8 %x, i4 %idx) {
 define void @insert_store_constant_high_bit_p32_index(ptr %p, i8 %x) {
 ; P32-LABEL: define void @insert_store_constant_high_bit_p32_index(
 ; P32-SAME: ptr [[P:%.*]], i8 [[X:%.*]]) #[[ATTR0]] {
-; P32-NEXT:    [[GEP:%.*]] = getelementptr inbounds <15 x i8>, ptr [[P]], i4 0, i4 -2
+; P32-NEXT:    [[GEP:%.*]] = getelementptr inbounds <15 x i8>, ptr [[P]], i32 0, i32 14
 ; P32-NEXT:    store i8 [[X]], ptr [[GEP]], align 1
 ; P32-NEXT:    ret void
 ;
@@ -114,7 +113,8 @@ define i8 @load_extract_dynamic_p32_index(ptr %p, i4 %idx) {
 ; P32LOAD-SAME: ptr [[P:%.*]], i4 [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
 ; P32LOAD-NEXT:    [[IDX_FROZEN:%.*]] = freeze i4 [[IDX]]
 ; P32LOAD-NEXT:    [[BOUNDED:%.*]] = urem i4 [[IDX_FROZEN]], -1
-; P32LOAD-NEXT:    [[GEP:%.*]] = getelementptr inbounds <15 x i8>, ptr [[P]], i32 0, i4 [[BOUNDED]]
+; P32LOAD-NEXT:    [[BOUNDED_GEPIDX:%.*]] = zext i4 [[BOUNDED]] to i32
+; P32LOAD-NEXT:    [[GEP:%.*]] = getelementptr inbounds <15 x i8>, ptr [[P]], i32 0, i32 [[BOUNDED_GEPIDX]]
 ; P32LOAD-NEXT:    [[X:%.*]] = load i8, ptr [[GEP]], align 1
 ; P32LOAD-NEXT:    ret i8 [[X]]
 ;
diff --git a/llvm/test/Transforms/VectorCombine/alias.ll b/llvm/test/Transforms/VectorCombine/alias.ll
index 6430041acd644..0fb09d1b35103 100644
--- a/llvm/test/Transforms/VectorCombine/alias.ll
+++ b/llvm/test/Transforms/VectorCombine/alias.ll
@@ -6,11 +6,11 @@ define <4 x i32> @quux(ptr addrspace(3) %arg) {
 ; CHECK-SAME: ptr addrspace(3) [[ARG:%.*]]) {
 ; CHECK-NEXT:  [[BB:.*:]]
 ; CHECK-NEXT:    [[EXTRACTELEMENT:%.*]] = load i8, ptr addrspace(3) [[ARG]], align 4, !tbaa [[TBAA0:![0-9]+]], !alias.scope [[META0:![0-9]+]], !noalias [[META0]]
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i8>, ptr addrspace(3) [[ARG]], i32 0, i64 1
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i8>, ptr addrspace(3) [[ARG]], i64 0, i64 1
 ; CHECK-NEXT:    [[EXTRACTELEMENT1:%.*]] = load i8, ptr addrspace(3) [[TMP0]], align 1, !tbaa [[TBAA0]], !alias.scope [[META0]], !noalias [[META0]]
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i8>, ptr addrspace(3) [[ARG]], i32 0, i64 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i8>, ptr addrspace(3) [[ARG]], i64 0, i64 2
 ; CHECK-NEXT:    [[EXTRACTELEMENT2:%.*]] = load i8, ptr addrspace(3) [[TMP1]], align 2, !tbaa [[TBAA0]], !alias.scope [[META0]], !noalias [[META0]]
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <4 x i8>, ptr addrspace(3) [[ARG]], i32 0, i64 3
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <4 x i8>, ptr addrspace(3) [[ARG]], i64 0, i64 3
 ; CHECK-NEXT:    [[EXTRACTELEMENT3:%.*]] = load i8, ptr addrspace(3) [[TMP2]], align 1, !tbaa [[TBAA0]], !alias.scope [[META0]], !noalias [[META0]]
 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext i8 [[EXTRACTELEMENT]] to i32
 ; CHECK-NEXT:    [[ZEXT4:%.*]] = zext i8 [[EXTRACTELEMENT1]] to i32
@@ -53,4 +53,4 @@ bb:
 ; CHECK: [[META0]] = !{[[META1:![0-9]+]]}
 ; CHECK: [[META1]] = distinct !{[[META1]], [[META2:![0-9]+]]}
 ; CHECK: [[META2]] = distinct !{[[META2]]}
-;.
\ No newline at end of file
+;.

>From b4578dd576ee040e757dbd1bc9569e7a3a30c859 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Tue, 28 Jul 2026 20:58:02 +0900
Subject: [PATCH 3/7] formatting

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

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 2a1dda6b9de9e..2dbfc3b7d33c3 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -2107,8 +2107,7 @@ bool VectorCombine::foldSingleElementStore(Instruction &I) {
 
     if (ScalarizableIdx.isSafeWithFreeze())
       ScalarizableIdx.freeze(Builder, *cast<Instruction>(Idx));
-    Value *GEPIdx =
-        materializeScalarizedGEPIndex(Idx, GEPIndexInfo, Builder);
+    Value *GEPIdx = materializeScalarizedGEPIndex(Idx, GEPIndexInfo, Builder);
     Value *GEP = Builder.CreateInBoundsGEP(
         SI->getValueOperand()->getType(), SI->getPointerOperand(),
         {ConstantInt::get(GEPIdx->getType(), 0), GEPIdx});

>From 33dabd1f96d2265b93979c0fc4cdcc814aee883b Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Sat, 1 Aug 2026 12:26:26 +0900
Subject: [PATCH 4/7] Add pointer-vector scalarization coverage

Cover the load/extract and insert/store scalarization paths when the vector element type is a pointer.
---
 .../scalarized-gep-index-representability.ll  | 37 +++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll b/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll
index f78e6edea0aad..7f330866631b0 100644
--- a/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll
@@ -87,6 +87,25 @@ define void @insert_store_dynamic_p32_index(ptr %p, i8 %x, i4 %idx) {
   ret void
 }
 
+; A vector of pointers reaches getScalarizedGEPIndexInfo as VecTy through the
+; insert/store path. PtrTy remains scalar, as required by load and store.
+define void @insert_store_pointer_vector_dynamic_p32_index(ptr %p, ptr %x, i4 %idx) {
+; P32-LABEL: define void @insert_store_pointer_vector_dynamic_p32_index(
+; P32-SAME: ptr [[P:%.*]], ptr [[X:%.*]], i4 [[IDX:%.*]]) #[[ATTR0]] {
+; P32-NEXT:    [[IDX_FROZEN:%.*]] = freeze i4 [[IDX]]
+; P32-NEXT:    [[BOUNDED:%.*]] = urem i4 [[IDX_FROZEN]], -1
+; P32-NEXT:    [[BOUNDED_GEPIDX:%.*]] = zext i4 [[BOUNDED]] to i32
+; P32-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <15 x ptr>, ptr [[P]], i32 0, i32 [[BOUNDED_GEPIDX]]
+; P32-NEXT:    store ptr [[X]], ptr [[TMP1]], align 8
+; P32-NEXT:    ret void
+;
+  %bounded = urem i4 %idx, 15
+  %v = load <15 x ptr>, ptr %p, align 8
+  %v1 = insertelement <15 x ptr> %v, ptr %x, i4 %bounded
+  store <15 x ptr> %v1, ptr %p, align 8
+  ret void
+}
+
 ; The i4 bit pattern -2 denotes unsigned lane 14. Materializing it for an i32
 ; GEP index must not create an instruction or reinterpret it as a negative
 ; signed index.
@@ -123,3 +142,21 @@ define i8 @load_extract_dynamic_p32_index(ptr %p, i4 %idx) {
   %x = extractelement <15 x i8> %v, i4 %bounded
   ret i8 %x
 }
+
+; A vector of pointers reaches getScalarizedGEPIndexInfo as VecTy through the
+; load/extract path. PtrTy remains scalar, as required by load instructions.
+define ptr @load_extract_pointer_vector_dynamic_p32_index(ptr %p, i4 %idx) {
+; P32LOAD-LABEL: define ptr @load_extract_pointer_vector_dynamic_p32_index(
+; P32LOAD-SAME: ptr [[P:%.*]], i4 [[IDX:%.*]]) #[[ATTR0]] {
+; P32LOAD-NEXT:    [[IDX_FROZEN:%.*]] = freeze i4 [[IDX]]
+; P32LOAD-NEXT:    [[BOUNDED:%.*]] = urem i4 [[IDX_FROZEN]], -1
+; P32LOAD-NEXT:    [[BOUNDED_GEPIDX:%.*]] = zext i4 [[BOUNDED]] to i32
+; P32LOAD-NEXT:    [[GEP:%.*]] = getelementptr inbounds <15 x ptr>, ptr [[P]], i32 0, i32 [[BOUNDED_GEPIDX]]
+; P32LOAD-NEXT:    [[X:%.*]] = load ptr, ptr [[GEP]], align 8
+; P32LOAD-NEXT:    ret ptr [[X]]
+;
+  %bounded = urem i4 %idx, 15
+  %v = load <15 x ptr>, ptr %p, align 8
+  %x = extractelement <15 x ptr> %v, i4 %bounded
+  ret ptr %x
+}

>From bf53f57ad959a919feabe21073060df64e1980bc Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Fri, 14 Aug 2026 23:42:42 +0900
Subject: [PATCH 5/7] reduced testcase for #215293 merged

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

diff --git a/llvm/test/Transforms/VectorCombine/load-insert-store.ll b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
index 897b113c197cf..c4085a3ac65a5 100644
--- a/llvm/test/Transforms/VectorCombine/load-insert-store.ll
+++ b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
@@ -845,5 +845,17 @@ bb:
   ret i32 %i35
 }
 
+define void @PR214650(ptr %q, i32 %s) {
+; CHECK-LABEL: @PR214650(
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i32>, ptr [[Q:%.*]], i64 0, i64 1
+; CHECK-NEXT:    store i32 [[S:%.*]], ptr [[TMP1]], align 4
+; CHECK-NEXT:    ret void
+;
+  %ld = load <8 x i32>, ptr %q, align 32
+  %v1 = insertelement <8 x i32> %ld, i32 %s, i1 true
+  store <8 x i32> %v1, ptr %q, align 32
+  ret void
+}
+
 declare i32 @bar(i32, i1) readonly
 declare double @llvm.log2.f64(double)

>From f892ba54003db31019e3f7fbc8faf88209949a13 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Mon, 17 Aug 2026 02:57:14 +0900
Subject: [PATCH 6/7] remove mcpu because all results are same for each
 x86-64-vX mcpu

---
 .../scalarized-gep-index-representability.ll  | 22 +++++++++----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll b/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll
index 7f330866631b0..a1e6bb0a67035 100644
--- a/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/scalarized-gep-index-representability.ll
@@ -1,9 +1,9 @@
 ; RUN: split-file %s %t
-; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %t/load.ll  | FileCheck %s --check-prefix=LOAD
-; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %t/store.ll | FileCheck %s --check-prefix=STORE
-; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %t/packed-stride.ll | FileCheck %s --check-prefix=PACKED
-; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %t/p32-index.ll | FileCheck %s --check-prefix=P32
-; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu -mcpu=x86-64-v4 < %t/p32-load-index.ll | FileCheck %s --check-prefix=P32LOAD
+; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu < %t/load.ll  | FileCheck %s --check-prefix=LOAD
+; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu < %t/store.ll | FileCheck %s --check-prefix=STORE
+; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu < %t/packed-stride.ll | FileCheck %s --check-prefix=PACKED
+; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu < %t/p32-index.ll | FileCheck %s --check-prefix=P32
+; RUN: opt -S -passes=vector-combine -verify-each -mtriple=x86_64-unknown-linux-gnu < %t/p32-load-index.ll | FileCheck %s --check-prefix=P32LOAD
 
 ;--- load.ll
 target datalayout = "e-p:64:64:64:8"
@@ -50,7 +50,7 @@ target datalayout = "e-p:64:64:64:8-i24:32:32"
 ; the 4-byte ABI allocation size does not.
 define void @insert_store_packed_i24_stride(ptr %p, i24 %x, i6 %idx) {
 ; PACKED-LABEL: define void @insert_store_packed_i24_stride(
-; PACKED-SAME: ptr [[P:%.*]], i24 [[X:%.*]], i6 [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
+; PACKED-SAME: ptr [[P:%.*]], i24 [[X:%.*]], i6 [[IDX:%.*]]) {
 ; PACKED-NEXT:    [[IDX_FROZEN:%.*]] = freeze i6 [[IDX]]
 ; PACKED-NEXT:    [[BOUNDED:%.*]] = urem i6 [[IDX_FROZEN]], -21
 ; PACKED-NEXT:    [[BOUNDED_GEPIDX:%.*]] = zext i6 [[BOUNDED]] to i8
@@ -72,7 +72,7 @@ target datalayout = "e-p:64:64:64:32"
 ; zero-extension destination type.
 define void @insert_store_dynamic_p32_index(ptr %p, i8 %x, i4 %idx) {
 ; P32-LABEL: define void @insert_store_dynamic_p32_index(
-; P32-SAME: ptr [[P:%.*]], i8 [[X:%.*]], i4 [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
+; P32-SAME: ptr [[P:%.*]], i8 [[X:%.*]], i4 [[IDX:%.*]]) {
 ; P32-NEXT:    [[IDX_FROZEN:%.*]] = freeze i4 [[IDX]]
 ; P32-NEXT:    [[BOUNDED:%.*]] = urem i4 [[IDX_FROZEN]], -1
 ; P32-NEXT:    [[BOUNDED_GEPIDX:%.*]] = zext i4 [[BOUNDED]] to i32
@@ -91,7 +91,7 @@ define void @insert_store_dynamic_p32_index(ptr %p, i8 %x, i4 %idx) {
 ; insert/store path. PtrTy remains scalar, as required by load and store.
 define void @insert_store_pointer_vector_dynamic_p32_index(ptr %p, ptr %x, i4 %idx) {
 ; P32-LABEL: define void @insert_store_pointer_vector_dynamic_p32_index(
-; P32-SAME: ptr [[P:%.*]], ptr [[X:%.*]], i4 [[IDX:%.*]]) #[[ATTR0]] {
+; P32-SAME: ptr [[P:%.*]], ptr [[X:%.*]], i4 [[IDX:%.*]]) {
 ; P32-NEXT:    [[IDX_FROZEN:%.*]] = freeze i4 [[IDX]]
 ; P32-NEXT:    [[BOUNDED:%.*]] = urem i4 [[IDX_FROZEN]], -1
 ; P32-NEXT:    [[BOUNDED_GEPIDX:%.*]] = zext i4 [[BOUNDED]] to i32
@@ -111,7 +111,7 @@ define void @insert_store_pointer_vector_dynamic_p32_index(ptr %p, ptr %x, i4 %i
 ; signed index.
 define void @insert_store_constant_high_bit_p32_index(ptr %p, i8 %x) {
 ; P32-LABEL: define void @insert_store_constant_high_bit_p32_index(
-; P32-SAME: ptr [[P:%.*]], i8 [[X:%.*]]) #[[ATTR0]] {
+; P32-SAME: ptr [[P:%.*]], i8 [[X:%.*]]) {
 ; P32-NEXT:    [[GEP:%.*]] = getelementptr inbounds <15 x i8>, ptr [[P]], i32 0, i32 14
 ; P32-NEXT:    store i8 [[X]], ptr [[GEP]], align 1
 ; P32-NEXT:    ret void
@@ -129,7 +129,7 @@ target datalayout = "e-p:64:64:64:32"
 ; extract. The lookup must recover the 32-bit GEP index type for this extract.
 define i8 @load_extract_dynamic_p32_index(ptr %p, i4 %idx) {
 ; P32LOAD-LABEL: define i8 @load_extract_dynamic_p32_index(
-; P32LOAD-SAME: ptr [[P:%.*]], i4 [[IDX:%.*]]) #[[ATTR0:[0-9]+]] {
+; P32LOAD-SAME: ptr [[P:%.*]], i4 [[IDX:%.*]]) {
 ; P32LOAD-NEXT:    [[IDX_FROZEN:%.*]] = freeze i4 [[IDX]]
 ; P32LOAD-NEXT:    [[BOUNDED:%.*]] = urem i4 [[IDX_FROZEN]], -1
 ; P32LOAD-NEXT:    [[BOUNDED_GEPIDX:%.*]] = zext i4 [[BOUNDED]] to i32
@@ -147,7 +147,7 @@ define i8 @load_extract_dynamic_p32_index(ptr %p, i4 %idx) {
 ; load/extract path. PtrTy remains scalar, as required by load instructions.
 define ptr @load_extract_pointer_vector_dynamic_p32_index(ptr %p, i4 %idx) {
 ; P32LOAD-LABEL: define ptr @load_extract_pointer_vector_dynamic_p32_index(
-; P32LOAD-SAME: ptr [[P:%.*]], i4 [[IDX:%.*]]) #[[ATTR0]] {
+; P32LOAD-SAME: ptr [[P:%.*]], i4 [[IDX:%.*]]) {
 ; P32LOAD-NEXT:    [[IDX_FROZEN:%.*]] = freeze i4 [[IDX]]
 ; P32LOAD-NEXT:    [[BOUNDED:%.*]] = urem i4 [[IDX_FROZEN]], -1
 ; P32LOAD-NEXT:    [[BOUNDED_GEPIDX:%.*]] = zext i4 [[BOUNDED]] to i32

>From 25420b17c530224a2f09b25bf5b3051ecd60cd52 Mon Sep 17 00:00:00 2001
From: hanbeom <kese111 at gmail.com>
Date: Mon, 17 Aug 2026 02:57:44 +0900
Subject: [PATCH 7/7] use zext as default for GEP

---
 .../Transforms/Vectorize/VectorCombine.cpp    | 83 ++++++++-----------
 .../load-extractelement-scalarization.ll      | 24 +++---
 .../VectorCombine/X86/load-inseltpoison.ll    |  2 +-
 .../test/Transforms/VectorCombine/X86/load.ll |  2 +-
 .../VectorCombine/load-insert-store.ll        | 54 +++++++-----
 5 files changed, 81 insertions(+), 84 deletions(-)

diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
index 2dbfc3b7d33c3..fe177cea34d71 100644
--- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
+++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp
@@ -1942,15 +1942,9 @@ static ScalarizationResult canScalarizeAccess(VectorType *VecTy, Value *Idx,
   return ScalarizationResult::unsafe();
 }
 
-struct ScalarizedGEPIndexInfo {
-  IntegerType *GEPIndexTy;
-  bool NeedsZExt;
-};
-
-/// Return true and populate \p Info if the unsigned vector index \p Idx can be
-/// represented by an inbounds GEP. Record whether an explicit zero-extension
-/// is required to preserve its value when GEP converts the index to the pointer
-/// index type.
+/// Return the GEP index type if the unsigned vector index \p Idx can be
+/// represented by an inbounds GEP. A null result means that the maximum byte
+/// offset cannot be represented by the pointer's signed GEP index type.
 ///
 ///   unsigned lane range
 ///                |
@@ -1960,32 +1954,28 @@ struct ScalarizedGEPIndexInfo {
 ///                +-- unavailable or outside signed GEP range --> reject
 ///                |
 ///                v
-///   narrow Idx may set its sign bit?
-///          | yes                 | no
-///          v                     v
-///   NeedsZExt = true      NeedsZExt = false
-static bool getScalarizedGEPIndexInfo(VectorType *VecTy, Value *Idx,
-                                      Type *PtrTy, const DataLayout &DL,
-                                      ScalarizedGEPIndexInfo &Info) {
+///   valid range --> use the pointer's GEP index type
+static IntegerType *getScalarizedGEPIndexInfo(VectorType *VecTy, Value *Idx,
+                                              Type *PtrTy,
+                                              const DataLayout &DL) {
   auto *GEPIndexTy = cast<IntegerType>(DL.getIndexType(PtrTy));
-  unsigned SrcBits = Idx->getType()->getIntegerBitWidth();
   unsigned GEPBits = GEPIndexTy->getBitWidth();
   uint64_t NumElements = VecTy->getElementCount().getKnownMinValue();
 
   uint64_t MaxLane = NumElements - 1;
   if (auto *C = dyn_cast<ConstantInt>(Idx)) {
     if (C->getValue().uge(NumElements))
-      return false;
+      return nullptr;
     MaxLane = C->getZExtValue();
   }
 
   Type *ElemTy = VecTy->getElementType();
   if (!DL.typeSizeEqualsStoreSize(ElemTy))
-    return false;
+    return nullptr;
 
   TypeSize ElemStride = DL.getTypeStoreSize(ElemTy);
   if (ElemStride.isScalable())
-    return false;
+    return nullptr;
 
   // Compare both values in a common width:
   //
@@ -2008,34 +1998,26 @@ static bool getScalarizedGEPIndexInfo(VectorType *VecTy, Value *Idx,
   // Reject offsets outside the GEP's positive signed range. Compare as
   // unsigned because the full 128-bit product may set its sign bit.
   if (ByteOffset.ugt(MaxGEPOffset))
-    return false;
+    return nullptr;
 
-  // GEP sign-extends narrow indices, so request a zext if a valid unsigned
-  // lane may set the source sign bit.
-  bool NeedsZExt = false;
-  if (SrcBits < GEPBits) {
-    APInt SignedMax = APInt::getSignedMaxValue(SrcBits).zext(WideBits);
-    NeedsZExt = MaxLaneValue.ugt(SignedMax);
-  }
-  Info = {GEPIndexTy, NeedsZExt};
-  return true;
+  return GEPIndexTy;
 }
 
 /// Materialize an index for a scalarized GEP after profitability is known.
+/// Vector element indices are unsigned, but GEP sign-extends narrow integer
+/// indices. Widen a narrow index explicitly so its unsigned value is retained.
 static Value *materializeScalarizedGEPIndex(Value *Idx,
-                                            const ScalarizedGEPIndexInfo &Info,
+                                            IntegerType *GEPIndexTy,
                                             IRBuilderBase &Builder) {
-  if (!Info.NeedsZExt)
+  unsigned SrcBits = Idx->getType()->getIntegerBitWidth();
+  unsigned DstBits = GEPIndexTy->getBitWidth();
+  if (SrcBits >= DstBits)
     return Idx;
 
-  unsigned DstBits = Info.GEPIndexTy->getBitWidth();
-  assert(Idx->getType()->getIntegerBitWidth() < DstBits &&
-         "Expected a widening zero-extension");
-
   if (auto *C = dyn_cast<ConstantInt>(Idx))
-    return ConstantInt::get(Info.GEPIndexTy, C->getValue().zext(DstBits));
+    return ConstantInt::get(GEPIndexTy, C->getValue().zext(DstBits));
 
-  return Builder.CreateZExt(Idx, Info.GEPIndexTy, Idx->getName() + ".gepidx");
+  return Builder.CreateZExt(Idx, GEPIndexTy, Idx->getName() + ".gepidx");
 }
 
 /// The memory operation on a vector of \p ScalarType had alignment of
@@ -2094,9 +2076,9 @@ bool VectorCombine::foldSingleElementStore(Instruction &I) {
     if (ScalarizableIdx.isUnsafe())
       return false;
 
-    ScalarizedGEPIndexInfo GEPIndexInfo;
-    if (!getScalarizedGEPIndexInfo(VecTy, Idx, SI->getPointerOperandType(), *DL,
-                                   GEPIndexInfo)) {
+    auto GEPIndex =
+        getScalarizedGEPIndexInfo(VecTy, Idx, SI->getPointerOperandType(), *DL);
+    if (!GEPIndex) {
       ScalarizableIdx.discard();
       return false;
     }
@@ -2107,7 +2089,7 @@ bool VectorCombine::foldSingleElementStore(Instruction &I) {
 
     if (ScalarizableIdx.isSafeWithFreeze())
       ScalarizableIdx.freeze(Builder, *cast<Instruction>(Idx));
-    Value *GEPIdx = materializeScalarizedGEPIndex(Idx, GEPIndexInfo, Builder);
+    Value *GEPIdx = materializeScalarizedGEPIndex(Idx, GEPIndex, Builder);
     Value *GEP = Builder.CreateInBoundsGEP(
         SI->getValueOperand()->getType(), SI->getPointerOperand(),
         {ConstantInt::get(GEPIdx->getType(), 0), GEPIdx});
@@ -2191,7 +2173,7 @@ bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
     return false;
 
   DenseMap<ExtractElementInst *, ScalarizationResult> NeedFreeze;
-  DenseMap<ExtractElementInst *, ScalarizedGEPIndexInfo> GEPIndexInfos;
+  DenseMap<ExtractElementInst *, IntegerType *> GEPIndexInfos;
   llvm::scope_exit FailureGuard([&]() {
     // If the transform is aborted, discard the ScalarizationResults.
     for (auto &Pair : NeedFreeze)
@@ -2211,15 +2193,14 @@ bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
     if (ScalarIdx.isUnsafe())
       return false;
 
-    ScalarizedGEPIndexInfo GEPIndexInfo;
-    if (!getScalarizedGEPIndexInfo(VecTy, UI->getIndexOperand(),
-                                   LI->getPointerOperandType(), *DL,
-                                   GEPIndexInfo)) {
+    auto GEPIndex = getScalarizedGEPIndexInfo(VecTy, UI->getIndexOperand(),
+                                              LI->getPointerOperandType(), *DL);
+    if (!GEPIndex) {
       ScalarIdx.discard();
       return false;
     }
 
-    GEPIndexInfos.try_emplace(UI, GEPIndexInfo);
+    GEPIndexInfos.try_emplace(UI, GEPIndex);
 
     if (ScalarIdx.isSafeWithFreeze()) {
       NeedFreeze.try_emplace(UI, ScalarIdx);
@@ -2235,9 +2216,11 @@ bool VectorCombine::scalarizeLoadExtract(LoadInst *LI, VectorType *VecTy,
                             Align(1), LI->getPointerAddressSpace(), CostKind);
     ScalarizedCost += TTI.getAddressComputationCost(LI->getPointerOperandType(),
                                                     nullptr, nullptr, CostKind);
-    if (!Index && GEPIndexInfo.NeedsZExt)
+    if (!Index &&
+        UI->getIndexOperand()->getType()->getIntegerBitWidth() <
+            GEPIndex->getBitWidth())
       ScalarizedCost +=
-          TTI.getCastInstrCost(Instruction::ZExt, GEPIndexInfo.GEPIndexTy,
+          TTI.getCastInstrCost(Instruction::ZExt, GEPIndex,
                                UI->getIndexOperand()->getType(),
                                TTI::CastContextHint::None, CostKind);
   }
diff --git a/llvm/test/Transforms/VectorCombine/AArch64/load-extractelement-scalarization.ll b/llvm/test/Transforms/VectorCombine/AArch64/load-extractelement-scalarization.ll
index 50ca00536856c..b12ba1c7777e2 100644
--- a/llvm/test/Transforms/VectorCombine/AArch64/load-extractelement-scalarization.ll
+++ b/llvm/test/Transforms/VectorCombine/AArch64/load-extractelement-scalarization.ll
@@ -4,7 +4,7 @@
 
 define i32 @load_extract_idx_0(ptr %x) {
 ; CHECK-LABEL: @load_extract_idx_0(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i32 3
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 3
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP1]], align 4
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -27,7 +27,7 @@ define i32 @vscale_load_extract_idx_0(ptr %x) {
 ; smaller alignment should be used.
 define i32 @load_extract_idx_0_small_alignment(ptr %x) {
 ; CHECK-LABEL: @load_extract_idx_0_small_alignment(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i32 3
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 3
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP1]], align 2
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -38,7 +38,7 @@ define i32 @load_extract_idx_0_small_alignment(ptr %x) {
 
 define i32 @load_extract_idx_1(ptr %x) {
 ; CHECK-LABEL: @load_extract_idx_1(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i32 1
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 1
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP1]], align 4
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -49,7 +49,7 @@ define i32 @load_extract_idx_1(ptr %x) {
 
 define i32 @load_extract_idx_2(ptr %x) {
 ; CHECK-LABEL: @load_extract_idx_2(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i32 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 2
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP1]], align 8
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -60,7 +60,7 @@ define i32 @load_extract_idx_2(ptr %x) {
 
 define i32 @vscale_load_extract_idx_2(ptr %x) {
 ; CHECK-LABEL: @vscale_load_extract_idx_2(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <vscale x 4 x i32>, ptr [[X:%.*]], i32 0, i32 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <vscale x 4 x i32>, ptr [[X:%.*]], i64 0, i64 2
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP1]], align 8
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -71,7 +71,7 @@ define i32 @vscale_load_extract_idx_2(ptr %x) {
 
 define i32 @load_extract_idx_3(ptr %x) {
 ; CHECK-LABEL: @load_extract_idx_3(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i32 3
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 3
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP1]], align 4
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -475,7 +475,7 @@ declare void @clobber()
 define i32 @load_extract_clobber_call_before(ptr %x) {
 ; CHECK-LABEL: @load_extract_clobber_call_before(
 ; CHECK-NEXT:    call void @clobber()
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i32 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 2
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP1]], align 8
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -500,7 +500,7 @@ define i32 @load_extract_clobber_call_between(ptr %x) {
 
 define i32 @load_extract_clobber_call_after(ptr %x) {
 ; CHECK-LABEL: @load_extract_clobber_call_after(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i32 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 2
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP1]], align 8
 ; CHECK-NEXT:    call void @clobber()
 ; CHECK-NEXT:    ret i32 [[R]]
@@ -514,7 +514,7 @@ define i32 @load_extract_clobber_call_after(ptr %x) {
 define i32 @load_extract_clobber_store_before(ptr %x, ptr %y) {
 ; CHECK-LABEL: @load_extract_clobber_store_before(
 ; CHECK-NEXT:    store i8 0, ptr [[Y:%.*]], align 1
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i32 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 2
 ; CHECK-NEXT:    [[R:%.*]] = load i32, ptr [[TMP1]], align 8
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
@@ -567,7 +567,7 @@ define i32 @load_extract_clobber_store_after_limit(ptr %x, ptr %y, <8 x i32> %z)
 ; LIMIT-DEFAULT-LABEL: @load_extract_clobber_store_after_limit(
 ; LIMIT-DEFAULT-NEXT:    [[TMP2:%.*]] = shufflevector <8 x i32> [[Z:%.*]], <8 x i32> poison, <5 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4>
 ; LIMIT-DEFAULT-NEXT:    [[Z_0:%.*]] = call i32 @llvm.vector.reduce.add.v5i32(<5 x i32> [[TMP2]])
-; LIMIT-DEFAULT-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i32 0, i32 2
+; LIMIT-DEFAULT-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <4 x i32>, ptr [[X:%.*]], i64 0, i64 2
 ; LIMIT-DEFAULT-NEXT:    [[R:%.*]] = load i32, ptr [[TMP1]], align 8
 ; LIMIT-DEFAULT-NEXT:    store i8 0, ptr [[Y:%.*]], align 1
 ; LIMIT-DEFAULT-NEXT:    [[ADD_4:%.*]] = add i32 [[Z_0]], [[R]]
@@ -649,7 +649,7 @@ define i1 @load_with_non_power_of_2_element_type_2(ptr %x) {
 define i32 @load_multiple_extracts_with_constant_idx(ptr %x) {
 ; CHECK-LABEL: @load_multiple_extracts_with_constant_idx(
 ; CHECK-NEXT:    [[E_0:%.*]] = load i32, ptr [[TMP1:%.*]], align 16
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <4 x i32>, ptr [[TMP1]], i32 0, i32 1
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <4 x i32>, ptr [[TMP1]], i64 0, i64 1
 ; CHECK-NEXT:    [[E_1:%.*]] = load i32, ptr [[TMP2]], align 4
 ; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
 ; CHECK-NEXT:    ret i32 [[RES]]
@@ -666,7 +666,7 @@ define i32 @load_multiple_extracts_with_constant_idx(ptr %x) {
 define i32 @load_multiple_extracts_with_constant_idx_profitable(ptr %x) {
 ; CHECK-LABEL: @load_multiple_extracts_with_constant_idx_profitable(
 ; CHECK-NEXT:    [[E_0:%.*]] = load i32, ptr [[TMP1:%.*]], align 16
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i32>, ptr [[TMP1]], i32 0, i32 6
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds <8 x i32>, ptr [[TMP1]], i64 0, i64 6
 ; CHECK-NEXT:    [[E_1:%.*]] = load i32, ptr [[TMP2]], align 8
 ; CHECK-NEXT:    [[RES:%.*]] = add i32 [[E_0]], [[E_1]]
 ; CHECK-NEXT:    ret i32 [[RES]]
diff --git a/llvm/test/Transforms/VectorCombine/X86/load-inseltpoison.ll b/llvm/test/Transforms/VectorCombine/X86/load-inseltpoison.ll
index 8cd99bbf31a8c..f35b2ea319d23 100644
--- a/llvm/test/Transforms/VectorCombine/X86/load-inseltpoison.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/load-inseltpoison.ll
@@ -676,7 +676,7 @@ define <2 x i64> @PR30986(ptr %0) {
 ; CHECK-NEXT:    [[TMP3:%.*]] = load i64, ptr [[TMP2:%.*]], align 16
 ; CHECK-NEXT:    [[TMP4:%.*]] = tail call i64 @llvm.ctpop.i64(i64 [[TMP3]])
 ; CHECK-NEXT:    [[TMP5:%.*]] = insertelement <2 x i64> poison, i64 [[TMP4]], i32 0
-; CHECK-NEXT:    [[TMP6:%.*]] = getelementptr inbounds <2 x i64>, ptr [[TMP2]], i32 0, i32 1
+; CHECK-NEXT:    [[TMP6:%.*]] = getelementptr inbounds <2 x i64>, ptr [[TMP2]], i64 0, i64 1
 ; CHECK-NEXT:    [[TMP7:%.*]] = load i64, ptr [[TMP6]], align 8
 ; CHECK-NEXT:    [[TMP8:%.*]] = tail call i64 @llvm.ctpop.i64(i64 [[TMP7]])
 ; CHECK-NEXT:    [[TMP9:%.*]] = insertelement <2 x i64> [[TMP5]], i64 [[TMP8]], i32 1
diff --git a/llvm/test/Transforms/VectorCombine/X86/load.ll b/llvm/test/Transforms/VectorCombine/X86/load.ll
index 388b655641b7d..39038cab48aba 100644
--- a/llvm/test/Transforms/VectorCombine/X86/load.ll
+++ b/llvm/test/Transforms/VectorCombine/X86/load.ll
@@ -606,7 +606,7 @@ define <2 x i64> @PR30986(ptr %0) {
 ; CHECK-NEXT:    [[TMP3:%.*]] = load i64, ptr [[TMP2:%.*]], align 16
 ; CHECK-NEXT:    [[TMP4:%.*]] = tail call i64 @llvm.ctpop.i64(i64 [[TMP3]])
 ; CHECK-NEXT:    [[TMP5:%.*]] = insertelement <2 x i64> undef, i64 [[TMP4]], i32 0
-; CHECK-NEXT:    [[TMP6:%.*]] = getelementptr inbounds <2 x i64>, ptr [[TMP2]], i32 0, i32 1
+; CHECK-NEXT:    [[TMP6:%.*]] = getelementptr inbounds <2 x i64>, ptr [[TMP2]], i64 0, i64 1
 ; CHECK-NEXT:    [[TMP7:%.*]] = load i64, ptr [[TMP6]], align 8
 ; CHECK-NEXT:    [[TMP8:%.*]] = tail call i64 @llvm.ctpop.i64(i64 [[TMP7]])
 ; CHECK-NEXT:    [[TMP9:%.*]] = insertelement <2 x i64> [[TMP5]], i64 [[TMP8]], i32 1
diff --git a/llvm/test/Transforms/VectorCombine/load-insert-store.ll b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
index c4085a3ac65a5..12b4e26bf649c 100644
--- a/llvm/test/Transforms/VectorCombine/load-insert-store.ll
+++ b/llvm/test/Transforms/VectorCombine/load-insert-store.ll
@@ -5,7 +5,7 @@
 define void @insert_store(ptr %q, i8 zeroext %s) {
 ; CHECK-LABEL: @insert_store(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 3
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i64 0, i64 3
 ; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
 ; CHECK-NEXT:    ret void
 ;
@@ -19,7 +19,7 @@ entry:
 define void @insert_store_i16_align1(ptr %q, i16 zeroext %s) {
 ; CHECK-LABEL: @insert_store_i16_align1(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i32 0, i32 3
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <8 x i16>, ptr [[Q:%.*]], i64 0, i64 3
 ; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
 ; CHECK-NEXT:    ret void
 ;
@@ -49,7 +49,7 @@ entry:
 define void @insert_store_vscale(ptr %q, i16 zeroext %s) {
 ; CHECK-LABEL: @insert_store_vscale(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 8 x i16>, ptr [[Q:%.*]], i32 0, i32 3
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 8 x i16>, ptr [[Q:%.*]], i64 0, i64 3
 ; CHECK-NEXT:    store i16 [[S:%.*]], ptr [[TMP0]], align 2
 ; CHECK-NEXT:    ret void
 ;
@@ -177,7 +177,8 @@ define void @insert_store_nonconst_large_alignment(ptr %q, i32 zeroext %s, i32 %
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 4
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q:%.*]], i32 0, i32 [[IDX]]
+; CHECK-NEXT:    [[IDX_GEPIDX:%.*]] = zext i32 [[IDX]] to i64
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <4 x i32>, ptr [[Q:%.*]], i64 0, i64 [[IDX_GEPIDX]]
 ; CHECK-NEXT:    store i32 [[S:%.*]], ptr [[TMP0]], align 4
 ; CHECK-NEXT:    ret void
 ;
@@ -194,7 +195,8 @@ define void @insert_store_nonconst_align_maximum_8(ptr %q, i64 %s, i32 %idx) {
 ; CHECK-LABEL: @insert_store_nonconst_align_maximum_8(
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 2
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX]]
+; CHECK-NEXT:    [[IDX_GEPIDX:%.*]] = zext i32 [[IDX]] to i64
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i64 0, i64 [[IDX_GEPIDX]]
 ; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 8
 ; CHECK-NEXT:    ret void
 ;
@@ -210,7 +212,8 @@ define void @insert_store_nonconst_align_maximum_4(ptr %q, i64 %s, i32 %idx) {
 ; CHECK-LABEL: @insert_store_nonconst_align_maximum_4(
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 2
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX]]
+; CHECK-NEXT:    [[IDX_GEPIDX:%.*]] = zext i32 [[IDX]] to i64
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i64 0, i64 [[IDX_GEPIDX]]
 ; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 4
 ; CHECK-NEXT:    ret void
 ;
@@ -226,7 +229,8 @@ define void @insert_store_nonconst_align_larger(ptr %q, i64 %s, i32 %idx) {
 ; CHECK-LABEL: @insert_store_nonconst_align_larger(
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 2
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i32 0, i32 [[IDX]]
+; CHECK-NEXT:    [[IDX_GEPIDX:%.*]] = zext i32 [[IDX]] to i64
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds <8 x i64>, ptr [[Q:%.*]], i64 0, i64 [[IDX_GEPIDX]]
 ; CHECK-NEXT:    store i64 [[S:%.*]], ptr [[TMP1]], align 4
 ; CHECK-NEXT:    ret void
 ;
@@ -243,7 +247,8 @@ define void @insert_store_nonconst_index_known_valid_by_assume(ptr %q, i8 zeroex
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 4
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX]]
+; CHECK-NEXT:    [[IDX_GEPIDX:%.*]] = zext i32 [[IDX]] to i64
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i64 0, i64 [[IDX_GEPIDX]]
 ; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
 ; CHECK-NEXT:    ret void
 ;
@@ -263,7 +268,8 @@ define void @insert_store_vscale_nonconst_index_known_valid_by_assume(ptr %q, i8
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[IDX:%.*]], 4
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[CMP]])
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX]]
+; CHECK-NEXT:    [[IDX_GEPIDX:%.*]] = zext i32 [[IDX]] to i64
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 16 x i8>, ptr [[Q:%.*]], i64 0, i64 [[IDX_GEPIDX]]
 ; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
 ; CHECK-NEXT:    ret void
 ;
@@ -345,7 +351,8 @@ define void @insert_store_nonconst_index_known_noundef_and_valid_by_and(ptr %q,
 ; CHECK-LABEL: @insert_store_nonconst_index_known_noundef_and_valid_by_and(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i32 [[IDX:%.*]], 7
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
+; CHECK-NEXT:    [[IDX_CLAMPED_GEPIDX:%.*]] = zext i32 [[IDX_CLAMPED]] to i64
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i64 0, i64 [[IDX_CLAMPED_GEPIDX]]
 ; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
 ; CHECK-NEXT:    ret void
 ;
@@ -363,7 +370,8 @@ define void @insert_store_vscale_nonconst_index_known_noundef_and_valid_by_and(p
 ; CHECK-LABEL: @insert_store_vscale_nonconst_index_known_noundef_and_valid_by_and(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i32 [[IDX:%.*]], 7
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
+; CHECK-NEXT:    [[IDX_CLAMPED_GEPIDX:%.*]] = zext i32 [[IDX_CLAMPED]] to i64
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 16 x i8>, ptr [[Q:%.*]], i64 0, i64 [[IDX_CLAMPED_GEPIDX]]
 ; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
 ; CHECK-NEXT:    ret void
 ;
@@ -380,7 +388,8 @@ define void @insert_store_nonconst_index_base_frozen_and_valid_by_and(ptr %q, i8
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[IDX_FROZEN:%.*]] = freeze i32 [[IDX:%.*]]
 ; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i32 [[IDX_FROZEN]], 7
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
+; CHECK-NEXT:    [[IDX_CLAMPED_GEPIDX:%.*]] = zext i32 [[IDX_CLAMPED]] to i64
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i64 0, i64 [[IDX_CLAMPED_GEPIDX]]
 ; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
 ; CHECK-NEXT:    ret void
 ;
@@ -417,7 +426,8 @@ define void @insert_store_nonconst_index_known_valid_by_and_but_may_be_poison(pt
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[IDX_FROZEN:%.*]] = freeze i32 [[IDX:%.*]]
 ; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = and i32 [[IDX_FROZEN]], 7
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
+; CHECK-NEXT:    [[IDX_CLAMPED_GEPIDX:%.*]] = zext i32 [[IDX_CLAMPED]] to i64
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i64 0, i64 [[IDX_CLAMPED_GEPIDX]]
 ; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
 ; CHECK-NEXT:    ret void
 ;
@@ -486,7 +496,8 @@ define void @insert_store_nonconst_index_known_noundef_and_valid_by_urem(ptr %q,
 ; CHECK-LABEL: @insert_store_nonconst_index_known_noundef_and_valid_by_urem(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i32 [[IDX:%.*]], 16
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
+; CHECK-NEXT:    [[IDX_CLAMPED_GEPIDX:%.*]] = zext i32 [[IDX_CLAMPED]] to i64
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i64 0, i64 [[IDX_CLAMPED_GEPIDX]]
 ; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
 ; CHECK-NEXT:    ret void
 ;
@@ -504,7 +515,8 @@ define void @insert_store_vscale_nonconst_index_known_noundef_and_valid_by_urem(
 ; CHECK-LABEL: @insert_store_vscale_nonconst_index_known_noundef_and_valid_by_urem(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i32 [[IDX:%.*]], 16
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
+; CHECK-NEXT:    [[IDX_CLAMPED_GEPIDX:%.*]] = zext i32 [[IDX_CLAMPED]] to i64
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <vscale x 16 x i8>, ptr [[Q:%.*]], i64 0, i64 [[IDX_CLAMPED_GEPIDX]]
 ; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
 ; CHECK-NEXT:    ret void
 ;
@@ -521,7 +533,8 @@ define void @insert_store_nonconst_index_base_frozen_and_valid_by_urem(ptr %q, i
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[IDX_FROZEN:%.*]] = freeze i32 [[IDX:%.*]]
 ; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i32 [[IDX_FROZEN]], 16
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
+; CHECK-NEXT:    [[IDX_CLAMPED_GEPIDX:%.*]] = zext i32 [[IDX_CLAMPED]] to i64
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i64 0, i64 [[IDX_CLAMPED_GEPIDX]]
 ; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
 ; CHECK-NEXT:    ret void
 ;
@@ -558,7 +571,8 @@ define void @insert_store_nonconst_index_known_valid_by_urem_but_may_be_poison(p
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[IDX_FROZEN:%.*]] = freeze i32 [[IDX:%.*]]
 ; CHECK-NEXT:    [[IDX_CLAMPED:%.*]] = urem i32 [[IDX_FROZEN]], 16
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 [[IDX_CLAMPED]]
+; CHECK-NEXT:    [[IDX_CLAMPED_GEPIDX:%.*]] = zext i32 [[IDX_CLAMPED]] to i64
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i64 0, i64 [[IDX_CLAMPED_GEPIDX]]
 ; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
 ; CHECK-NEXT:    ret void
 ;
@@ -626,7 +640,7 @@ entry:
 define void @insert_store_ptr_strip(ptr %q, i8 zeroext %s) {
 ; CHECK-LABEL: @insert_store_ptr_strip(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i32 0, i32 3
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q:%.*]], i64 0, i64 3
 ; CHECK-NEXT:    store i8 [[S:%.*]], ptr [[TMP0]], align 1
 ; CHECK-NEXT:    ret void
 ;
@@ -683,7 +697,7 @@ define void @insert_store_mem_modify(ptr %p, ptr %q, ptr noalias %r, i8 %s, i32
 ; CHECK-NEXT:    [[INS:%.*]] = insertelement <16 x i8> [[LD]], i8 [[S:%.*]], i32 3
 ; CHECK-NEXT:    store <16 x i8> [[INS]], ptr [[P]], align 16
 ; CHECK-NEXT:    store <16 x i8> zeroinitializer, ptr [[R:%.*]], align 16
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q]], i32 0, i32 7
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[Q]], i64 0, i64 7
 ; CHECK-NEXT:    store i8 [[S]], ptr [[TMP0]], align 1
 ; CHECK-NEXT:    [[LD3:%.*]] = load <4 x i32>, ptr [[P]], align 16
 ; CHECK-NEXT:    store <16 x i8> zeroinitializer, ptr [[P]], align 16
@@ -743,7 +757,7 @@ define void @insert_store_with_call(ptr %p, ptr %q, i8 %s) {
 ; CHECK-NEXT:    store <16 x i8> [[INS]], ptr [[P]], align 16
 ; CHECK-NEXT:    call void @foo()
 ; CHECK-NEXT:    call void @nowrite(ptr [[P]])
-; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[P]], i32 0, i32 7
+; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds <16 x i8>, ptr [[P]], i64 0, i64 7
 ; CHECK-NEXT:    store i8 [[S]], ptr [[TMP0]], align 1
 ; CHECK-NEXT:    ret void
 ;



More information about the llvm-commits mailing list