[llvm] [LoadStoreVectorizer] Support vectorization of mixed-type contiguous accesses (PR #177908)

Anshil Gandhi via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 10:53:30 PDT 2026


================
@@ -160,7 +155,67 @@ struct ChainElem {
   ChainElem(Instruction *Inst, APInt OffsetFromLeader)
       : Inst(std::move(Inst)), OffsetFromLeader(std::move(OffsetFromLeader)) {}
 };
-using Chain = SmallVector<ChainElem, 1>;
+struct Chain : SmallVector<ChainElem, 1> {
+private:
+  Type *ElemTy = nullptr;
+
+public:
+  using SmallVector::SmallVector;
+
+  /// Return the GCD of the element sizes.
+  unsigned int computeGCDSize(const DataLayout &DL) const {
+    unsigned int GCDSize = 0;
+    for (const ChainElem &E : *this) {
+      Type *Ty = getLoadStoreType(E.Inst)->getScalarType();
+      unsigned Sz = DL.getTypeSizeInBits(Ty);
+      GCDSize = GCDSize == 0 ? Sz : std::gcd(GCDSize, Sz);
+    }
+    return GCDSize;
+  }
+
+  /// Gets the element type of the vector that the chain will load or store.
+  ///
+  /// The element type is determined by taking the GCD of the bitwidths of all
+  /// elements in the chain. Among types with this matching bitwidth, we prefer:
+  /// - A type that appears most frequently in the chain, to minimize casts.
+  /// - An integer type if the chain contains pointers, to avoid direct
+  ///   pointer-to-floating-point conversions.
+  ///
+  /// \param C The chain of instructions to be vectorized.
+  /// \returns The chosen element type for the vectorized load or store.
+  Type *computeAndCacheElemTy(LLVMContext &Ctx, const DataLayout &DL) {
+    assert(!empty());
+    if (ElemTy)
+      return ElemTy;
+
+    unsigned GCDSize = computeGCDSize(DL);
+    bool HasPointers = llvm::any_of(*this, [&](ChainElem &E) {
+      return getLoadStoreType(E.Inst)->getScalarType()->isPointerTy();
+    });
+
+    // Among non-pointer types whose size matches the GCD, prefer the most
+    // common one to minimize bitcasts. If the chain contains pointers, only
+    // consider integer types (there's no direct FP-to-pointer cast).
+    DenseMap<Type *, unsigned> TypeCounts;
+    Type *BestTy = nullptr;
+    unsigned BestCount = 0;
+    for (const ChainElem &E : *this) {
+      Type *Ty = getLoadStoreType(E.Inst)->getScalarType();
+      if (Ty->isPointerTy() || DL.getTypeSizeInBits(Ty) != GCDSize ||
+          (HasPointers && !Ty->isIntegerTy()))
+        continue;
+      unsigned Count = ++TypeCounts[Ty];
+      if (Count > BestCount) {
+        BestCount = Count;
+        BestTy = Ty;
+      }
+    }
+
+    return ElemTy = BestTy ? BestTy : Type::getIntNTy(Ctx, GCDSize);
+  }
+
+  void setElemTy(Type *Ty) { ElemTy = Ty; }
----------------
gandhi56 wrote:

Removed `setElemTy` and made `ElemTy` private. `ElemTy` is now exclusively set using `computeAndCacheElemTy(..)` and is maintained within the `struct Chain`.

https://github.com/llvm/llvm-project/pull/177908


More information about the llvm-commits mailing list