[Mlir-commits] [mlir] [MLIR][XeGPU] Promote memref.alloca to SLM in convert-vector-to-xegpu (PR #197978)

Igor Zamyatin llvmlistbot at llvm.org
Fri May 22 10:14:21 PDT 2026


================
@@ -946,9 +947,86 @@ struct ContractionLowering : public OpRewritePattern<vector::ContractionOp> {
   }
 };
 
+// Returns `memrefTy` with its memory space replaced by `newMemSpace`.
+static MemRefType withMemorySpace(MemRefType memrefTy, Attribute newMemSpace) {
+  return MemRefType::get(memrefTy.getShape(), memrefTy.getElementType(),
+                         memrefTy.getLayout(), newMemSpace);
+}
+
+// Rewrite every `memref.alloca` not already in shared local memory (SLM) to
+// be in SLM (address space 3), and propagate the new memory space through
+// memref-producing aliasing users (e.g. memref.cast, memref.subview,
+// memref.expand_shape, ...). Consumers that take a memref operand but
+// produce a non-memref result (e.g. vector.transfer_read, vector.load) are
+// left untouched: their operand type simply reflects the new memory space.
+//
+// This makes `xegpu.load_matrix`/`xegpu.store_matrix` lowering work end-to-end
+// for IR coming from bufferization, which by default assigns memory space 0/1
+// to allocations.
+static void promoteAllocasToSLM(Operation *root) {
+  MLIRContext *ctx = root->getContext();
+  Attribute slmAttr = IntegerAttr::get(IntegerType::get(ctx, 64), 3);
+
+  // A user is treated as a memref-producing alias (e.g. memref.cast,
+  // memref.subview, memref.expand_shape, ...) if it is side-effect free and
+  // produces at least one memref result. This excludes ops like memref.copy
+  // that have memory effects.
+  auto isMemrefResultOp = [](Operation *op) {
+    if (!isMemoryEffectFree(op))
+      return false;
+    return llvm::any_of(op->getResultTypes(),
+                        [](Type t) { return isa<MemRefType>(t); });
+  };
+
+  // Update `v`'s type to have SLM memory space, then walk forward through
+  // memref-producing users and update their result types accordingly.
+  std::function<void(Value)> propagate = [&](Value v) {
+    auto memrefTy = dyn_cast<MemRefType>(v.getType());
+    if (!memrefTy || xegpu::XeGPUDialect::isSharedMemory(memrefTy))
+      return;
+    v.setType(withMemorySpace(memrefTy, slmAttr));
+    for (Operation *user : v.getUsers()) {
+      if (!isMemrefResultOp(user))
+        continue;
+      for (Value result : user->getResults())
+        propagate(result);
+    }
+  };
+
+  SmallVector<memref::AllocaOp> allocas;
+  root->walk([&](memref::AllocaOp op) {
+    auto memrefTy = dyn_cast<MemRefType>(op.getResult().getType());
+    if (!memrefTy || xegpu::XeGPUDialect::isSharedMemory(memrefTy))
+      return;
+    allocas.push_back(op);
+  });
+
+  for (memref::AllocaOp alloca : allocas) {
+    OpBuilder builder(alloca);
+    auto memrefTy = cast<MemRefType>(alloca.getResult().getType());
+    auto newTy = withMemorySpace(memrefTy, slmAttr);
+    auto newOp = memref::AllocaOp::create(
+        builder, alloca.getLoc(), newTy, alloca.getDynamicSizes(),
+        alloca.getSymbolOperands(), alloca.getAlignmentAttr());
+    alloca.getResult().replaceAllUsesWith(newOp.getResult());
+    alloca.erase();
+    // Propagate the new memory space through memref-producing consumers.
+    for (Operation *user : newOp.getResult().getUsers()) {
+      if (!isMemrefResultOp(user))
+        continue;
+      for (Value result : user->getResults())
+        propagate(result);
----------------
Garra1980 wrote:

can you add a test that checks propagation through eg scf.for?

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


More information about the Mlir-commits mailing list