[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