[Mlir-commits] [mlir] [mlir][SPIRV] Handle vector stores when unifying aliased resources (PR #232185)

Anutosh Bhat llvmlistbot at llvm.org
Tue Nov 3 03:51:50 PST 2026


https://github.com/anutosh491 updated https://github.com/llvm/llvm-project/pull/232185

>From 4fd84f72128169c4d9578875de5d87b3aeebadc7 Mon Sep 17 00:00:00 2001
From: anutosh491 <andersonbhat491 at gmail.com>
Date: Thu, 15 Oct 2026 11:28:47 +0530
Subject: [PATCH 1/4] [mlir][SPIRV] Handle vector stores when unifying aliased
 resources

Signed-off-by: anutosh491 <andersonbhat491 at gmail.com>
---
 .../Transforms/UnifyAliasedResourcePass.cpp   |  67 +++++++++-
 .../Transforms/unify-aliased-resource.mlir    | 120 ++++++++++++++++++
 2 files changed, 181 insertions(+), 6 deletions(-)

diff --git a/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp b/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp
index 99eaa3f0b16654..2cc1f0a4a821a8 100644
--- a/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp
+++ b/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp
@@ -24,6 +24,7 @@
 #include "mlir/Transforms/DialectConversion.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Alignment.h"
 #include <iterator>
 
 namespace mlir {
@@ -550,15 +551,69 @@ struct ConvertStore : public ConvertAliasResource<spirv::StoreOp> {
         cast<spirv::PointerType>(storeOp.getPtr().getType()).getPointeeType();
     auto dstElemType =
         cast<spirv::PointerType>(adaptor.getPtr().getType()).getPointeeType();
-    if (!srcElemType.isIntOrFloat() || !dstElemType.isIntOrFloat())
-      return rewriter.notifyMatchFailure(storeOp, "not scalar type");
-    if (!areSameBitwidthScalarType(srcElemType, dstElemType))
-      return rewriter.notifyMatchFailure(storeOp, "different bitwidth");
-
     Location loc = storeOp.getLoc();
     Value value = adaptor.getValue();
-    if (srcElemType != dstElemType)
+    auto srcVector = dyn_cast<VectorType>(srcElemType);
+    auto dstVector = dyn_cast<VectorType>(dstElemType);
+    if (srcVector && dstVector && srcVector != dstVector) {
+      if (srcVector.getElementTypeBitWidth() !=
+              dstVector.getElementTypeBitWidth() ||
+          srcVector.getNumElements() % dstVector.getNumElements() != 0)
+        return rewriter.notifyMatchFailure(storeOp,
+                                           "incompatible vector types");
+      auto acOp = adaptor.getPtr().getDefiningOp<spirv::AccessChainOp>();
+      if (!acOp)
+        return rewriter.notifyMatchFailure(storeOp,
+                                           "ptr not spirv.AccessChain");
+      if (srcVector.getElementType() != dstVector.getElementType())
+        value = spirv::BitcastOp::create(
+            rewriter, loc,
+            VectorType::get(srcVector.getShape(), dstVector.getElementType()),
+            value);
+      unsigned count = dstVector.getNumElements();
+      unsigned ratio = srcVector.getNumElements() / count;
+      unsigned bytes = count * dstVector.getElementTypeBitWidth() / 8;
+      for (unsigned i = 0; i < ratio; ++i) {
+        Value part = value;
+        if (ratio > 1) {
+          SmallVector<int32_t> components;
+          for (unsigned j = 0; j < count; ++j)
+            components.push_back(i * count + j);
+          part = spirv::VectorShuffleOp::create(
+              rewriter, loc, dstVector, value, value,
+              rewriter.getI32ArrayAttr(components));
+        }
+        Value ptr = adaptor.getPtr();
+        auto alignment = storeOp.getAlignmentAttr();
+        if (i) {
+          auto indices = llvm::to_vector(acOp.getIndices());
+          Type indexType = indices.back().getType();
+          auto offset = spirv::ConstantOp::create(
+              rewriter, loc, indexType, rewriter.getIntegerAttr(indexType, i));
+          indices.back() = spirv::IAddOp::create(rewriter, loc, indexType,
+                                                 indices.back(), offset);
+          ptr = spirv::AccessChainOp::create(rewriter, loc, acOp.getBasePtr(),
+                                             indices);
+          if (alignment)
+            alignment = rewriter.getI32IntegerAttr(
+                llvm::commonAlignment(llvm::Align(alignment.getInt()),
+                                      i * bytes)
+                    .value());
+        }
+        auto store = spirv::StoreOp::create(
+            rewriter, loc, ptr, part, storeOp.getMemoryAccessAttr(), alignment);
+        store->setDiscardableAttrs(storeOp->getDiscardableAttrDictionary());
+      }
+      rewriter.eraseOp(storeOp);
+      return success();
+    }
+    if (srcElemType != dstElemType) {
+      if (!srcElemType.isIntOrFloat() || !dstElemType.isIntOrFloat())
+        return rewriter.notifyMatchFailure(storeOp, "not scalar type");
+      if (!areSameBitwidthScalarType(srcElemType, dstElemType))
+        return rewriter.notifyMatchFailure(storeOp, "different bitwidth");
       value = spirv::BitcastOp::create(rewriter, loc, dstElemType, value);
+    }
     auto newStore = rewriter.replaceOpWithNewOp<spirv::StoreOp>(
         storeOp, adaptor.getPtr(), value, storeOp.getMemoryAccessAttr(),
         storeOp.getAlignmentAttr());
diff --git a/mlir/test/Dialect/SPIRV/Transforms/unify-aliased-resource.mlir b/mlir/test/Dialect/SPIRV/Transforms/unify-aliased-resource.mlir
index d7cc1d0cc1f849..e0567272e57de1 100644
--- a/mlir/test/Dialect/SPIRV/Transforms/unify-aliased-resource.mlir
+++ b/mlir/test/Dialect/SPIRV/Transforms/unify-aliased-resource.mlir
@@ -581,3 +581,123 @@ spirv.module Logical GLSL450 {
 // CHECK-LABEL: spirv.func @main
 // CHECK-SAME:  (%{{.+}}: !spirv.ptr<!spirv.struct<(!spirv.rtarray<f32, stride=4> [0])>, StorageBuffer>) "None"
 // CHECK:       spirv.Return
+
+// -----
+
+spirv.module Logical GLSL450 {
+  spirv.GlobalVariable @canonical bind(0, 0) {aliased} : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<2xf32>, stride=8> [0])>, StorageBuffer>
+  spirv.GlobalVariable @wide bind(0, 0) {aliased} : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>
+  spirv.func @store_wide_vector(%value: vector<4xf32>) "None" {
+    %c0 = spirv.Constant 0 : i32
+    %c3 = spirv.Constant 3 : i32
+    %base = spirv.mlir.addressof @wide : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>
+    %ptr = spirv.AccessChain %base[%c0, %c3] : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>, i32, i32 -> !spirv.ptr<vector<4xf32>, StorageBuffer>
+    spirv.Store "StorageBuffer" %ptr, %value : vector<4xf32>
+    spirv.Return
+  }
+}
+// CHECK-LABEL: spirv.module
+// CHECK: spirv.GlobalVariable @canonical bind(0, 0)
+// CHECK-NOT: spirv.GlobalVariable @wide
+// CHECK: spirv.func @store_wide_vector(%[[VALUE:.+]]: vector<4xf32>)
+// CHECK-DAG: %[[ZERO:.+]] = spirv.Constant 0 : i32
+// CHECK-DAG: %[[THREE:.+]] = spirv.Constant 3 : i32
+// CHECK-DAG: %[[BASE:.+]] = spirv.mlir.addressof @canonical
+// CHECK-DAG: %[[TWO:.+]] = spirv.Constant 2 : i32
+// CHECK: %[[INDEX:.+]] = spirv.IMul %[[THREE]], %[[TWO]] : i32
+// CHECK: %[[PTR0:.+]] = spirv.AccessChain %[[BASE]][%[[ZERO]], %[[INDEX]]]
+// CHECK: %[[LOW:.+]] = spirv.VectorShuffle [0 : i32, 1 : i32] %[[VALUE]], %[[VALUE]]
+// CHECK: spirv.Store "StorageBuffer" %[[PTR0]], %[[LOW]] : vector<2xf32>
+// CHECK: %[[HIGH:.+]] = spirv.VectorShuffle [2 : i32, 3 : i32] %[[VALUE]], %[[VALUE]]
+// CHECK: %[[ONE:.+]] = spirv.Constant 1 : i32
+// CHECK: %[[NEXT:.+]] = spirv.IAdd %[[INDEX]], %[[ONE]] : i32
+// CHECK: %[[PTR1:.+]] = spirv.AccessChain %[[BASE]][%[[ZERO]], %[[NEXT]]]
+// CHECK: spirv.Store "StorageBuffer" %[[PTR1]], %[[HIGH]] : vector<2xf32>
+
+// -----
+
+spirv.module Logical GLSL450 {
+  spirv.GlobalVariable @canonical bind(0, 0) {aliased} : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<2xf32>, stride=8> [0])>, StorageBuffer>
+  spirv.GlobalVariable @wide bind(0, 0) {aliased} : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xi32>, stride=16> [0])>, StorageBuffer>
+  spirv.func @store_wide_bitcast(%value: vector<4xi32>) "None" {
+    %c0 = spirv.Constant 0 : i32
+    %c3 = spirv.Constant 3 : i32
+    %base = spirv.mlir.addressof @wide : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xi32>, stride=16> [0])>, StorageBuffer>
+    %ptr = spirv.AccessChain %base[%c0, %c3] : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xi32>, stride=16> [0])>, StorageBuffer>, i32, i32 -> !spirv.ptr<vector<4xi32>, StorageBuffer>
+    spirv.Store "StorageBuffer" %ptr, %value : vector<4xi32>
+    spirv.Return
+  }
+}
+// CHECK-LABEL: spirv.module
+// CHECK: spirv.GlobalVariable @canonical bind(0, 0)
+// CHECK-NOT: spirv.GlobalVariable @wide
+// CHECK: spirv.func @store_wide_bitcast
+// CHECK: spirv.Bitcast
+// CHECK: spirv.VectorShuffle
+// CHECK: spirv.Store "StorageBuffer" {{.+}} : vector<2xf32>
+// CHECK: spirv.VectorShuffle
+// CHECK: spirv.Store "StorageBuffer" {{.+}} : vector<2xf32>
+
+// -----
+
+spirv.module Logical GLSL450 {
+  spirv.GlobalVariable @canonical bind(0, 0) {aliased} : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<2xf32>, stride=8> [0])>, StorageBuffer>
+  spirv.GlobalVariable @wide bind(0, 0) {aliased} : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>
+  spirv.func @store_wide_aligned(%value: vector<4xf32>) "None" {
+    %c0 = spirv.Constant 0 : i32
+    %c3 = spirv.Constant 3 : i32
+    %base = spirv.mlir.addressof @wide : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>
+    %ptr = spirv.AccessChain %base[%c0, %c3] : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>, i32, i32 -> !spirv.ptr<vector<4xf32>, StorageBuffer>
+    spirv.Store "StorageBuffer" %ptr, %value ["Volatile|Aligned", 16] : vector<4xf32>
+    spirv.Return
+  }
+}
+// CHECK-LABEL: spirv.module
+// CHECK: spirv.GlobalVariable @canonical bind(0, 0)
+// CHECK-NOT: spirv.GlobalVariable @wide
+// CHECK: spirv.func @store_wide_aligned
+// CHECK: spirv.VectorShuffle
+// CHECK: spirv.Store "StorageBuffer" {{.+}}["Volatile|Aligned", 16] : vector<2xf32>
+// CHECK: spirv.VectorShuffle
+// CHECK: spirv.Store "StorageBuffer" {{.+}}["Volatile|Aligned", 8] : vector<2xf32>
+
+// -----
+
+spirv.module Logical GLSL450 {
+  spirv.GlobalVariable @canonical bind(0, 0) {aliased} : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>
+  spirv.GlobalVariable @wide bind(0, 0) {aliased} : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xi32>, stride=16> [0])>, StorageBuffer>
+  spirv.func @store_equal_vector_bitcast(%value: vector<4xi32>) "None" {
+    %c0 = spirv.Constant 0 : i32
+    %c3 = spirv.Constant 3 : i32
+    %base = spirv.mlir.addressof @wide : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xi32>, stride=16> [0])>, StorageBuffer>
+    %ptr = spirv.AccessChain %base[%c0, %c3] : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xi32>, stride=16> [0])>, StorageBuffer>, i32, i32 -> !spirv.ptr<vector<4xi32>, StorageBuffer>
+    spirv.Store "StorageBuffer" %ptr, %value : vector<4xi32>
+    spirv.Return
+  }
+}
+// CHECK-LABEL: spirv.module
+// CHECK: spirv.GlobalVariable @canonical bind(0, 0)
+// CHECK-NOT: spirv.GlobalVariable @wide
+// CHECK: spirv.func @store_equal_vector_bitcast
+// CHECK: spirv.Bitcast
+// CHECK: spirv.Store "StorageBuffer" {{.+}} : vector<4xf32>
+
+// -----
+
+spirv.module Logical GLSL450 {
+  spirv.GlobalVariable @canonical bind(0, 0) {aliased} : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>
+  spirv.GlobalVariable @alias bind(0, 0) {aliased} : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>
+  spirv.func @store_equal_vector(%value: vector<4xf32>) "None" {
+    %c0 = spirv.Constant 0 : i32
+    %base = spirv.mlir.addressof @alias : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>
+    %ptr = spirv.AccessChain %base[%c0, %c0] : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>, i32, i32 -> !spirv.ptr<vector<4xf32>, StorageBuffer>
+    spirv.Store "StorageBuffer" %ptr, %value : vector<4xf32>
+    spirv.Return
+  }
+}
+// CHECK-LABEL: spirv.module
+// CHECK: spirv.GlobalVariable @canonical bind(0, 0)
+// CHECK-NOT: spirv.GlobalVariable @alias
+// CHECK: spirv.func @store_equal_vector(%[[VALUE:.+]]: vector<4xf32>)
+// CHECK: %[[PTR:.+]] = spirv.AccessChain
+// CHECK: spirv.Store "StorageBuffer" %[[PTR]], %[[VALUE]] : vector<4xf32>

>From a15ec286bd1ef7c449a350d86d093aac7b62097d Mon Sep 17 00:00:00 2001
From: anutosh491 <andersonbhat491 at gmail.com>
Date: Thu, 29 Oct 2026 10:19:45 +0530
Subject: [PATCH 2/4] [mlir][SPIRV] Address vector store review feedback

Signed-off-by: anutosh491 <andersonbhat491 at gmail.com>
---
 .../Transforms/UnifyAliasedResourcePass.cpp   | 56 ++++++++++---------
 .../Transforms/unify-aliased-resource.mlir    | 49 ++++++++++++++++
 2 files changed, 79 insertions(+), 26 deletions(-)

diff --git a/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp b/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp
index 2cc1f0a4a821a8..3ee1e2a6ba641d 100644
--- a/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp
+++ b/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp
@@ -573,33 +573,37 @@ struct ConvertStore : public ConvertAliasResource<spirv::StoreOp> {
       unsigned count = dstVector.getNumElements();
       unsigned ratio = srcVector.getNumElements() / count;
       unsigned bytes = count * dstVector.getElementTypeBitWidth() / 8;
-      for (unsigned i = 0; i < ratio; ++i) {
-        Value part = value;
-        if (ratio > 1) {
-          SmallVector<int32_t> components;
-          for (unsigned j = 0; j < count; ++j)
-            components.push_back(i * count + j);
-          part = spirv::VectorShuffleOp::create(
-              rewriter, loc, dstVector, value, value,
-              rewriter.getI32ArrayAttr(components));
-        }
-        Value ptr = adaptor.getPtr();
+
+      // Split the value into stores of the canonical resource's vector type.
+      auto getPart = [&](unsigned i) -> Value {
+        if (ratio == 1)
+          return value;
+        SmallVector<int32_t> components;
+        for (unsigned j = 0; j < count; ++j)
+          components.push_back(i * count + j);
+        return spirv::VectorShuffleOp::create(
+            rewriter, loc, dstVector, value, value,
+            rewriter.getI32ArrayAttr(components));
+      };
+      auto firstStore = spirv::StoreOp::create(
+          rewriter, loc, adaptor.getPtr(), getPart(0),
+          storeOp.getMemoryAccessAttr(), storeOp.getAlignmentAttr());
+      firstStore->setDiscardableAttrs(storeOp->getDiscardableAttrDictionary());
+      for (unsigned i = 1; i < ratio; ++i) {
+        Value part = getPart(i);
+        auto indices = llvm::to_vector(acOp.getIndices());
+        Type indexType = indices.back().getType();
+        auto offset = spirv::ConstantOp::create(
+            rewriter, loc, indexType, rewriter.getIntegerAttr(indexType, i));
+        indices.back() = spirv::IAddOp::create(rewriter, loc, indexType,
+                                               indices.back(), offset);
+        Value ptr = spirv::AccessChainOp::create(rewriter, loc,
+                                                 acOp.getBasePtr(), indices);
         auto alignment = storeOp.getAlignmentAttr();
-        if (i) {
-          auto indices = llvm::to_vector(acOp.getIndices());
-          Type indexType = indices.back().getType();
-          auto offset = spirv::ConstantOp::create(
-              rewriter, loc, indexType, rewriter.getIntegerAttr(indexType, i));
-          indices.back() = spirv::IAddOp::create(rewriter, loc, indexType,
-                                                 indices.back(), offset);
-          ptr = spirv::AccessChainOp::create(rewriter, loc, acOp.getBasePtr(),
-                                             indices);
-          if (alignment)
-            alignment = rewriter.getI32IntegerAttr(
-                llvm::commonAlignment(llvm::Align(alignment.getInt()),
-                                      i * bytes)
-                    .value());
-        }
+        if (alignment)
+          alignment = rewriter.getI32IntegerAttr(
+              llvm::commonAlignment(llvm::Align(alignment.getInt()), i * bytes)
+                  .value());
         auto store = spirv::StoreOp::create(
             rewriter, loc, ptr, part, storeOp.getMemoryAccessAttr(), alignment);
         store->setDiscardableAttrs(storeOp->getDiscardableAttrDictionary());
diff --git a/mlir/test/Dialect/SPIRV/Transforms/unify-aliased-resource.mlir b/mlir/test/Dialect/SPIRV/Transforms/unify-aliased-resource.mlir
index e0567272e57de1..982a35cebe69df 100644
--- a/mlir/test/Dialect/SPIRV/Transforms/unify-aliased-resource.mlir
+++ b/mlir/test/Dialect/SPIRV/Transforms/unify-aliased-resource.mlir
@@ -701,3 +701,52 @@ spirv.module Logical GLSL450 {
 // CHECK: spirv.func @store_equal_vector(%[[VALUE:.+]]: vector<4xf32>)
 // CHECK: %[[PTR:.+]] = spirv.AccessChain
 // CHECK: spirv.Store "StorageBuffer" %[[PTR]], %[[VALUE]] : vector<4xf32>
+
+// -----
+
+spirv.module Logical GLSL450 {
+  spirv.GlobalVariable @canonical bind(0, 0) {aliased} : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<2xf16>, stride=4> [0])>, StorageBuffer>
+  spirv.GlobalVariable @wide bind(0, 0) {aliased} : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>
+  spirv.func @store_different_element_width(%value: vector<4xf32>) "None" {
+    %c0 = spirv.Constant 0 : i32
+    %base = spirv.mlir.addressof @wide : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>
+    %ptr = spirv.AccessChain %base[%c0, %c0] : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>, i32, i32 -> !spirv.ptr<vector<4xf32>, StorageBuffer>
+    // expected-error at +1 {{failed to legalize operation 'spirv.Store'}}
+    spirv.Store "StorageBuffer" %ptr, %value : vector<4xf32>
+    spirv.Return
+  }
+}
+
+// -----
+
+spirv.module Logical GLSL450 {
+  spirv.GlobalVariable @canonical bind(0, 0) {aliased} : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<3xf32>, stride=16> [0])>, StorageBuffer>
+  spirv.GlobalVariable @wide bind(0, 0) {aliased} : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>
+  spirv.func @store_nondivisible_vectors(%value: vector<4xf32>) "None" {
+    %c0 = spirv.Constant 0 : i32
+    %base = spirv.mlir.addressof @wide : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>
+    %ptr = spirv.AccessChain %base[%c0, %c0] : !spirv.ptr<!spirv.struct<(!spirv.rtarray<vector<4xf32>, stride=16> [0])>, StorageBuffer>, i32, i32 -> !spirv.ptr<vector<4xf32>, StorageBuffer>
+    spirv.Store "StorageBuffer" %ptr, %value : vector<4xf32>
+    spirv.Return
+  }
+}
+
+// CHECK-LABEL: spirv.module
+// CHECK: spirv.GlobalVariable @canonical bind(0, 0) {aliased}
+// CHECK: spirv.GlobalVariable @wide bind(0, 0) {aliased}
+// CHECK-LABEL: spirv.func @store_nondivisible_vectors
+// CHECK-NOT: spirv.VectorShuffle
+// CHECK: spirv.Store "StorageBuffer" {{.+}} : vector<4xf32>
+
+// -----
+
+spirv.module Logical GLSL450 {
+  spirv.func @store_without_access_chain(%ptr: !spirv.ptr<vector<4xf32>, StorageBuffer>, %value: vector<4xf32>) "None" {
+    spirv.Store "StorageBuffer" %ptr, %value : vector<4xf32>
+    spirv.Return
+  }
+}
+// CHECK-LABEL: spirv.func @store_without_access_chain(
+// CHECK-SAME: %[[PTR:.+]]: !spirv.ptr<vector<4xf32>, StorageBuffer>, %[[VALUE:.+]]: vector<4xf32>)
+// CHECK-NOT: spirv.AccessChain
+// CHECK: spirv.Store "StorageBuffer" %[[PTR]], %[[VALUE]] : vector<4xf32>

>From d71c1967feae9c61c66b59319fe37de1b76e71d6 Mon Sep 17 00:00:00 2001
From: anutosh491 <andersonbhat491 at gmail.com>
Date: Thu, 29 Oct 2026 10:22:53 +0530
Subject: [PATCH 3/4] [mlir][SPIRV] Explain aliased vector store lowering

Signed-off-by: anutosh491 <andersonbhat491 at gmail.com>
---
 .../lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp b/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp
index 3ee1e2a6ba641d..b18ffdb857ef7e 100644
--- a/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp
+++ b/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp
@@ -574,7 +574,9 @@ struct ConvertStore : public ConvertAliasResource<spirv::StoreOp> {
       unsigned ratio = srcVector.getNumElements() / count;
       unsigned bytes = count * dstVector.getElementTypeBitWidth() / 8;
 
-      // Split the value into stores of the canonical resource's vector type.
+      // Split the value into vectors matching the canonical resource and store
+      // them at consecutive vector indices. Adjust each store's alignment for
+      // its byte offset from the original pointer.
       auto getPart = [&](unsigned i) -> Value {
         if (ratio == 1)
           return value;

>From 34f8b62a58acaada23c8608a021837be095035f8 Mon Sep 17 00:00:00 2001
From: anutosh491 <andersonbhat491 at gmail.com>
Date: Tue, 3 Nov 2026 17:21:34 +0530
Subject: [PATCH 4/4] [mlir][SPIRV] Spell out vector store conversion types

---
 .../lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp b/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp
index b18ffdb857ef7e..fc2ca73f921b29 100644
--- a/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp
+++ b/mlir/lib/Dialect/SPIRV/Transforms/UnifyAliasedResourcePass.cpp
@@ -593,7 +593,7 @@ struct ConvertStore : public ConvertAliasResource<spirv::StoreOp> {
       firstStore->setDiscardableAttrs(storeOp->getDiscardableAttrDictionary());
       for (unsigned i = 1; i < ratio; ++i) {
         Value part = getPart(i);
-        auto indices = llvm::to_vector(acOp.getIndices());
+        SmallVector<Value> indices = llvm::to_vector(acOp.getIndices());
         Type indexType = indices.back().getType();
         auto offset = spirv::ConstantOp::create(
             rewriter, loc, indexType, rewriter.getIntegerAttr(indexType, i));
@@ -601,7 +601,7 @@ struct ConvertStore : public ConvertAliasResource<spirv::StoreOp> {
                                                indices.back(), offset);
         Value ptr = spirv::AccessChainOp::create(rewriter, loc,
                                                  acOp.getBasePtr(), indices);
-        auto alignment = storeOp.getAlignmentAttr();
+        IntegerAttr alignment = storeOp.getAlignmentAttr();
         if (alignment)
           alignment = rewriter.getI32IntegerAttr(
               llvm::commonAlignment(llvm::Align(alignment.getInt()), i * bytes)



More information about the Mlir-commits mailing list