[llvm] [VectorCombine] Preserve unsigned indices in scalarized GEPs (PR #212470)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 20 22:12:44 PDT 2026
================
@@ -1948,6 +1948,83 @@ static ScalarizationResult canScalarizeAccess(VectorType *VecTy, Value *Idx,
return ScalarizationResult::unsafe();
}
+/// 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
+/// |
+/// v
+/// MaxByteOffset = MaxLane * element store size
+/// |
+/// +-- unavailable or outside signed GEP range --> reject
+/// |
+/// v
+/// 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 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 nullptr;
+ MaxLane = C->getZExtValue();
+ }
+
+ Type *ElemTy = VecTy->getElementType();
+ if (!DL.typeSizeEqualsStoreSize(ElemTy))
+ return nullptr;
+
+ TypeSize ElemStride = DL.getTypeStoreSize(ElemTy);
+ if (ElemStride.isScalable())
+ return nullptr;
+
+ // 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 nullptr;
+
+ 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, IntegerType *GEPIndexTy,
+ IRBuilderBase &Builder) {
+ unsigned SrcBits = Idx->getType()->getIntegerBitWidth();
+ unsigned DstBits = GEPIndexTy->getBitWidth();
+ if (SrcBits >= DstBits)
+ return Idx;
+
+ if (auto *C = dyn_cast<ConstantInt>(Idx))
+ return ConstantInt::get(GEPIndexTy, C->getValue().zext(DstBits));
+
+ return Builder.CreateZExt(Idx, GEPIndexTy, Idx->getName() + ".gepidx");
----------------
ParkHanbum wrote:
right. I overlooked it.
https://github.com/llvm/llvm-project/pull/212470
More information about the llvm-commits
mailing list