[Mlir-commits] [mlir] [mlir][memref] Alias attributes for memref dialect (PR #154991)

Ivan Butygin llvmlistbot at llvm.org
Mon Aug 25 06:24:17 PDT 2025


https://github.com/Hardcode84 updated https://github.com/llvm/llvm-project/pull/154991

>From c7be9f7d9654d16f6c5de032c9945614fb1e8074 Mon Sep 17 00:00:00 2001
From: Ivan Butygin <ivan.butygin at gmail.com>
Date: Thu, 21 Aug 2025 23:58:43 +0200
Subject: [PATCH 01/12] init attrs

---
 .../mlir/Dialect/MemRef/IR/CMakeLists.txt     |   6 +
 mlir/include/mlir/Dialect/MemRef/IR/MemRef.h  |   1 +
 .../mlir/Dialect/MemRef/IR/MemRefAttrs.h      |  21 ++++
 .../mlir/Dialect/MemRef/IR/MemRefAttrs.td     | 114 ++++++++++++++++++
 .../mlir/Dialect/MemRef/IR/MemRefBase.td      |   1 +
 .../mlir/Dialect/MemRef/IR/MemRefOps.td       |  56 ++++++++-
 mlir/lib/Dialect/MemRef/IR/CMakeLists.txt     |   2 +
 mlir/lib/Dialect/MemRef/IR/MemRefAttrs.cpp    |  23 ++++
 mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp  |  11 ++
 mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp      |  21 ++++
 10 files changed, 254 insertions(+), 2 deletions(-)
 create mode 100644 mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.h
 create mode 100644 mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
 create mode 100644 mlir/lib/Dialect/MemRef/IR/MemRefAttrs.cpp

diff --git a/mlir/include/mlir/Dialect/MemRef/IR/CMakeLists.txt b/mlir/include/mlir/Dialect/MemRef/IR/CMakeLists.txt
index b7b12d49f9224..709bebb90760d 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/MemRef/IR/CMakeLists.txt
@@ -1,2 +1,8 @@
 add_mlir_dialect(MemRefOps memref)
 add_mlir_doc(MemRefOps MemRefOps Dialects/ -gen-op-doc)
+
+set(LLVM_TARGET_DEFINITIONS MemRefOps.td)
+mlir_tablegen(MemRefAttrs.h.inc -gen-attrdef-decls -attrdefs-dialect=memref)
+mlir_tablegen(MemRefAttrs.cpp.inc -gen-attrdef-defs -attrdefs-dialect=memref)
+add_public_tablegen_target(MLIRMemRefAttrsIncGen)
+add_dependencies(mlir-headers MLIRMemRefAttrsIncGen)
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRef.h b/mlir/include/mlir/Dialect/MemRef/IR/MemRef.h
index ac383ab46e7a5..ac3d64a57331a 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRef.h
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRef.h
@@ -11,6 +11,7 @@
 
 #include "mlir/Bytecode/BytecodeOpInterface.h"
 #include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/MemRef/IR/MemRefAttrs.h"
 #include "mlir/Dialect/Utils/ReshapeOpsUtils.h"
 #include "mlir/IR/Dialect.h"
 #include "mlir/Interfaces/CallInterfaces.h"
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.h b/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.h
new file mode 100644
index 0000000000000..dea732814f933
--- /dev/null
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.h
@@ -0,0 +1,21 @@
+//===- MemRefAttrs.h - MLIR MemRef IR dialect attributes --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the MemRef dialect attributes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_MEMREF_IR_MEMREFATTRS_H_
+#define MLIR_DIALECT_MEMREF_IR_MEMREFATTRS_H_
+
+#include "mlir/IR/OpImplementation.h"
+
+#define GET_ATTRDEF_CLASSES
+#include "mlir/Dialect/MemRef/IR/MemRefAttrs.h.inc"
+
+#endif // MLIR_DIALECT_MEMREF_IR_MEMREFATTRS_H_
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
new file mode 100644
index 0000000000000..b3d17724ce68c
--- /dev/null
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
@@ -0,0 +1,114 @@
+//===-- MemRefAttrs.td - MemRef Attributes definition file -*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MEMREF_ATTRDEFS
+#define MEMREF_ATTRDEFS
+
+include "mlir/Dialect/MemRef/IR/MemRefBase.td"
+include "mlir/IR/AttrTypeBase.td"
+
+// All of the attributes will extend this class.
+class MemRef_Attr<string name, string attrMnemonic,
+                list<Trait> traits = [],
+                string baseCppClass = "::mlir::Attribute">
+    : AttrDef<MemRef_Dialect, name, traits, baseCppClass> {
+  let mnemonic = attrMnemonic;
+}
+
+
+//===----------------------------------------------------------------------===//
+// AliasScopeDomainAttr
+//===----------------------------------------------------------------------===//
+
+def MemRef_AliasScopeDomainAttr : MemRef_Attr<"AliasScopeDomain",
+                                              "alias_scope_domain"> {
+  let parameters = (ins
+    "Attribute":$id,
+    OptionalParameter<"StringAttr">:$description
+  );
+
+  let builders = [
+    AttrBuilder<(ins CArg<"StringAttr", "{}">:$description), [{
+      return $_get($_ctxt, DistinctAttr::create(UnitAttr::get($_ctxt)), description);
+    }]>
+  ];
+
+  let summary = "TBD";
+
+  let description = [{
+    TBD
+  }];
+
+  let assemblyFormat = "`<` struct(params) `>`";
+
+  // Generate mnemonic alias for the attribute.
+  let genMnemonicAlias = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// AliasScopeAttr
+//===----------------------------------------------------------------------===//
+
+def MemRef_AliasScopeAttr : MemRef_Attr<"AliasScope", "alias_scope"> {
+  let parameters = (ins
+    "Attribute":$id,
+    OptionalParameter<"StringAttr">:$description
+  );
+
+  let builders = [
+    AttrBuilderWithInferredContext<(ins
+      "MLIRContext*":$context,
+      CArg<"StringAttr", "{}">:$description
+    ), [{
+      return $_get(context, DistinctAttr::create(UnitAttr::get(context)), description);
+    }]>
+  ];
+
+  let summary = "TBD";
+
+  let description = [{
+    TBD
+  }];
+
+  let assemblyFormat = "`<` struct(params) `>`";
+
+  let genVerifyDecl = 1;
+
+  // Generate mnemonic alias for the attribute.
+  let genMnemonicAlias = 1;
+}
+
+def MemRef_AliasScopeArrayAttr
+    : TypedArrayAttrBase<MemRef_AliasScopeAttr,
+                         MemRef_AliasScopeAttr.summary # " array"> {
+  let constBuilderCall = ?;
+}
+
+//===----------------------------------------------------------------------===//
+// AliasAttr
+//===----------------------------------------------------------------------===//
+
+def MemRef_AliasingAttr : MemRef_Attr<"Aliasing", "aliasing"> {
+  let parameters = (ins
+    "ArrayAttr":$alias_scopes,
+    "ArrayAttr":$noalias
+  );
+
+  let summary = "TBD";
+
+  let description = [{
+    TBD
+  }];
+
+  let assemblyFormat = "`<` struct(params) `>`";
+
+  // Generate mnemonic alias for the attribute.
+  let genMnemonicAlias = 1;
+}
+
+#endif // MEMREF_ATTRDEFS
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefBase.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefBase.td
index 3be84ae654f6a..f5d42b912b8a9 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefBase.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefBase.td
@@ -21,6 +21,7 @@ def MemRef_Dialect : Dialect {
   }];
   let dependentDialects = ["arith::ArithDialect"];
   let hasConstantMaterializer = 1;
+  let useDefaultAttributePrinterParser = 1;
 }
 
 #endif // MEMREF_BASE
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
index 9321089ab55fa..d7573432338fe 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
@@ -11,6 +11,7 @@
 
 include "mlir/Dialect/Arith/IR/ArithBase.td"
 include "mlir/Dialect/MemRef/IR/MemRefBase.td"
+include "mlir/Dialect/MemRef/IR/MemRefAttrs.td"
 include "mlir/Interfaces/CastInterfaces.td"
 include "mlir/Interfaces/ControlFlowInterfaces.td"
 include "mlir/Interfaces/CopyOpInterface.td"
@@ -154,7 +155,7 @@ def AssumeAlignmentOp : MemRef_Op<"assume_alignment", [
       The `assume_alignment` operation takes a memref and an integer alignment
       value. It returns a new SSA value of the same memref type, but associated
       with the assumption that the underlying buffer is aligned to the given
-      alignment. 
+      alignment.
 
       If the buffer isn't aligned to the given alignment, its result is poison.
       This operation doesn't affect the semantics of a program where the
@@ -169,7 +170,7 @@ def AssumeAlignmentOp : MemRef_Op<"assume_alignment", [
   let assemblyFormat = "$memref `,` $alignment attr-dict `:` type($memref)";
   let extraClassDeclaration = [{
     MemRefType getType() { return ::llvm::cast<MemRefType>(getResult().getType()); }
-    
+
     Value getViewSource() { return getMemref(); }
   }];
 
@@ -450,6 +451,57 @@ def MemRef_AllocaScopeReturnOp : MemRef_Op<"alloca_scope.return",
   let assemblyFormat = "attr-dict ($results^ `:` type($results))?";
 }
 
+//===----------------------------------------------------------------------===//
+// AliasDomainScopeOp
+//===----------------------------------------------------------------------===//
+
+def MemRef_AliasDomainScopeOp : MemRef_Op<"alias_domain_scope", [
+    DeclareOpInterfaceMethods<RegionBranchOpInterface>,
+    SingleBlockImplicitTerminator<"AliasDomainScopeReturnOp">,
+    RecursiveMemoryEffects]> {
+  let summary = "TBD";
+  let description = [{
+    TBD
+  }];
+
+  let arguments = (ins MemRef_AliasScopeDomainAttr:$domain);
+  let results = (outs Variadic<AnyType>:$results);
+
+  let regions = (region SizedRegion<1>:$region);
+
+  let assemblyFormat = "attr-dict $domain (`->` type($results)^)? $region";
+
+//  let extraClassDeclaration = [{
+//    /// Inline op body into parent region and erase the op.
+//    static void inlineIntoParent(::mlir::PatternRewriter &builder, EnvironmentRegionOp op);
+//  }];
+//
+//  let builders = [
+//    OpBuilder<(ins "::mlir::Attribute":$environment,
+//      CArg<"::mlir::ValueRange", "std::nullopt">:$args,
+//      CArg<"::mlir::TypeRange", "std::nullopt">:$results,
+//      CArg<"::llvm::function_ref<void(::mlir::OpBuilder &, ::mlir::Location)>", "nullptr">)>
+//  ];
+//
+//  let hasCanonicalizer = 1;
+}
+
+def MemRef_AliasDomainScopeReturnOp : MemRef_Op<"alias_domain_scope.return", [
+  Pure, ReturnLike, Terminator,
+  HasParent<"AliasDomainScopeOp">
+  ]> {
+
+  let summary = "TBD";
+  let description = [{
+    TBD
+  }];
+
+  let arguments = (ins Variadic<AnyType>:$results);
+  let builders = [OpBuilder<(ins), [{ /* nothing to do */ }]>];
+
+  let assemblyFormat = "attr-dict ($results^ `:` type($results))?";
+}
+
 //===----------------------------------------------------------------------===//
 // CastOp
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/MemRef/IR/CMakeLists.txt b/mlir/lib/Dialect/MemRef/IR/CMakeLists.txt
index 734294bd014c6..e41f6c32b835c 100644
--- a/mlir/lib/Dialect/MemRef/IR/CMakeLists.txt
+++ b/mlir/lib/Dialect/MemRef/IR/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_mlir_dialect_library(MLIRMemRefDialect
+  MemRefAttrs.cpp
   MemRefDialect.cpp
   MemRefMemorySlot.cpp
   MemRefOps.cpp
@@ -9,6 +10,7 @@ add_mlir_dialect_library(MLIRMemRefDialect
 
   DEPENDS
   MLIRMemRefOpsIncGen
+  MLIRMemRefAttrsIncGen
 
   LINK_LIBS PUBLIC
   MLIRArithDialect
diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefAttrs.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefAttrs.cpp
new file mode 100644
index 0000000000000..281e7e80c68f6
--- /dev/null
+++ b/mlir/lib/Dialect/MemRef/IR/MemRefAttrs.cpp
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/MemRef/IR/MemRefAttrs.h"
+#include "mlir/Dialect/MemRef/IR/MemRef.h"
+
+using namespace mlir;
+
+LogicalResult mlir::memref::AliasScopeAttr::verify(
+    function_ref<InFlightDiagnostic()> emitError, Attribute id,
+    StringAttr description) {
+  (void)description;
+  if (!isa<StringAttr, DistinctAttr>(id))
+    return emitError()
+           << "id of an alias scope must be a StringAttr or a DistrinctAttr";
+
+  return success();
+}
diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp
index 6ff63df258c79..22ccad7d3c8ed 100644
--- a/mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp
+++ b/mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp
@@ -10,14 +10,21 @@
 #include "mlir/Conversion/ConvertToLLVM/ToLLVMInterface.h"
 #include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.h"
 #include "mlir/Dialect/MemRef/IR/MemRef.h"
+#include "mlir/Dialect/MemRef/IR/MemRefAttrs.h"
+#include "mlir/IR/Builders.h"
 #include "mlir/IR/BuiltinTypes.h"
+#include "mlir/IR/DialectImplementation.h"
 #include "mlir/Interfaces/MemorySlotInterfaces.h"
 #include "mlir/Interfaces/RuntimeVerifiableOpInterface.h"
 #include "mlir/Interfaces/SideEffectInterfaces.h"
 #include "mlir/Interfaces/ValueBoundsOpInterface.h"
 #include "mlir/Transforms/InliningUtils.h"
+#include "llvm/ADT/TypeSwitch.h"
 #include <optional>
 
+#define GET_ATTRDEF_CLASSES
+#include "mlir/Dialect/MemRef/IR/MemRefAttrs.cpp.inc"
+
 using namespace mlir;
 using namespace mlir::memref;
 
@@ -46,6 +53,10 @@ void mlir::memref::MemRefDialect::initialize() {
 #define GET_OP_LIST
 #include "mlir/Dialect/MemRef/IR/MemRefOps.cpp.inc"
       >();
+  addAttributes<
+#define GET_ATTRDEF_LIST
+#include "mlir/Dialect/MemRef/IR/MemRefAttrs.cpp.inc"
+      >();
   addInterfaces<MemRefInlinerInterface>();
   declarePromisedInterface<ConvertToEmitCPatternInterface, MemRefDialect>();
   declarePromisedInterface<ConvertToLLVMPatternInterface, MemRefDialect>();
diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
index b59d73d1291c8..d0f766e282d1e 100644
--- a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
+++ b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
@@ -518,6 +518,27 @@ void AllocaScopeOp::getCanonicalizationPatterns(RewritePatternSet &results,
   results.add<AllocaScopeInliner, AllocaScopeHoister>(context);
 }
 
+//===----------------------------------------------------------------------===//
+// AliasDomainScopeOp
+//===----------------------------------------------------------------------===//
+
+/// Given the region at `index`, or the parent operation if `index` is None,
+/// return the successor regions. These are the regions that may be selected
+/// during the flow of control. `operands` is a set of optional attributes that
+/// correspond to a constant value for each operand, or null if that operand is
+/// not a constant.
+void AliasDomainScopeOp::getSuccessorRegions(
+    RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {
+  // If the predecessor is the ExecuteRegionOp, branch into the body.
+  if (point.isParent()) {
+    regions.push_back(RegionSuccessor(&getRegion()));
+    return;
+  }
+
+  // Otherwise, the region branches back to the parent operation.
+  regions.push_back(RegionSuccessor(getResults()));
+}
+
 //===----------------------------------------------------------------------===//
 // AssumeAlignmentOp
 //===----------------------------------------------------------------------===//

>From b741a0bf5509116c7744f55eee5b09c6a1c791b2 Mon Sep 17 00:00:00 2001
From: Ivan Butygin <ivan.butygin at gmail.com>
Date: Fri, 22 Aug 2025 15:49:35 +0200
Subject: [PATCH 02/12] memref alias attr

---
 .../mlir/Dialect/MemRef/IR/MemRefAttrs.td     |  3 --
 .../mlir/Dialect/MemRef/IR/MemRefOps.td       | 40 ++++++++-----------
 mlir/test/Dialect/MemRef/ops.mlir             | 20 ++++++++++
 3 files changed, 36 insertions(+), 27 deletions(-)

diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
index b3d17724ce68c..7285b6d8c00b0 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
@@ -106,9 +106,6 @@ def MemRef_AliasingAttr : MemRef_Attr<"Aliasing", "aliasing"> {
   }];
 
   let assemblyFormat = "`<` struct(params) `>`";
-
-  // Generate mnemonic alias for the attribute.
-  let genMnemonicAlias = 1;
 }
 
 #endif // MEMREF_ATTRDEFS
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
index d7573432338fe..b6c3e89bde036 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
@@ -470,20 +470,6 @@ def MemRef_AliasDomainScopeOp : MemRef_Op<"alias_domain_scope", [
   let regions = (region SizedRegion<1>:$region);
 
   let assemblyFormat = "attr-dict $domain (`->` type($results)^)? $region";
-
-//  let extraClassDeclaration = [{
-//    /// Inline op body into parent region and erase the op.
-//    static void inlineIntoParent(::mlir::PatternRewriter &builder, EnvironmentRegionOp op);
-//  }];
-//
-//  let builders = [
-//    OpBuilder<(ins "::mlir::Attribute":$environment,
-//      CArg<"::mlir::ValueRange", "std::nullopt">:$args,
-//      CArg<"::mlir::TypeRange", "std::nullopt">:$results,
-//      CArg<"::llvm::function_ref<void(::mlir::OpBuilder &, ::mlir::Location)>", "nullptr">)>
-//  ];
-//
-//  let hasCanonicalizer = 1;
 }
 
 def MemRef_AliasDomainScopeReturnOp : MemRef_Op<"alias_domain_scope.return", [
@@ -1285,34 +1271,38 @@ def LoadOp : MemRef_Op<"load",
                        Variadic<Index>:$indices,
                        DefaultValuedOptionalAttr<BoolAttr, "false">:$nontemporal,
                        ConfinedAttr<OptionalAttr<I64Attr>,
-                                    [AllAttrOf<[IntPositive, IntPowerOf2]>]>:$alignment);
+                                    [AllAttrOf<[IntPositive, IntPowerOf2]>]>:$alignment,
+                       OptionalAttr<MemRef_AliasingAttr>:$alias);
 
   let builders = [
     OpBuilder<(ins "Value":$memref,
                    "ValueRange":$indices,
                    CArg<"bool", "false">:$nontemporal,
-                   CArg<"uint64_t", "0">:$alignment), [{
+                   CArg<"uint64_t", "0">:$alignment,
+                   CArg<"AliasingAttr", "nullptr">:$alias), [{
       return build($_builder, $_state, memref, indices, nontemporal,
                    alignment != 0 ? $_builder.getI64IntegerAttr(alignment) :
-                                    nullptr);
+                                    nullptr, alias);
     }]>,
     OpBuilder<(ins "Type":$resultType,
                    "Value":$memref,
                    "ValueRange":$indices,
                    CArg<"bool", "false">:$nontemporal,
-                   CArg<"uint64_t", "0">:$alignment), [{
+                   CArg<"uint64_t", "0">:$alignment,
+                   CArg<"AliasingAttr", "nullptr">:$alias), [{
       return build($_builder, $_state, resultType, memref, indices, nontemporal,
                    alignment != 0 ? $_builder.getI64IntegerAttr(alignment) :
-                                    nullptr);
+                                    nullptr, alias);
     }]>,
     OpBuilder<(ins "TypeRange":$resultTypes,
                    "Value":$memref,
                    "ValueRange":$indices,
                    CArg<"bool", "false">:$nontemporal,
-                   CArg<"uint64_t", "0">:$alignment), [{
+                   CArg<"uint64_t", "0">:$alignment,
+                   CArg<"AliasingAttr", "nullptr">:$alias), [{
       return build($_builder, $_state, resultTypes, memref, indices, nontemporal,
                    alignment != 0 ? $_builder.getI64IntegerAttr(alignment) :
-                                    nullptr);
+                                    nullptr, alias);
     }]>
   ];
 
@@ -2019,17 +2009,19 @@ def MemRef_StoreOp : MemRef_Op<"store",
                        Variadic<Index>:$indices,
                        DefaultValuedOptionalAttr<BoolAttr, "false">:$nontemporal,
                        ConfinedAttr<OptionalAttr<I64Attr>,
-                                    [AllAttrOf<[IntPositive, IntPowerOf2]>]>:$alignment);
+                                    [AllAttrOf<[IntPositive, IntPowerOf2]>]>:$alignment,
+                       OptionalAttr<MemRef_AliasingAttr>:$alias);
 
   let builders = [
     OpBuilder<(ins "Value":$valueToStore,
                    "Value":$memref,
                    "ValueRange":$indices,
                    CArg<"bool", "false">:$nontemporal,
-                   CArg<"uint64_t", "0">:$alignment), [{
+                   CArg<"uint64_t", "0">:$alignment,
+                   CArg<"AliasingAttr", "nullptr">:$alias), [{
       return build($_builder, $_state, valueToStore, memref, indices, nontemporal,
                    alignment != 0 ? $_builder.getI64IntegerAttr(alignment) :
-                                    nullptr);
+                                    nullptr, alias);
     }]>,
     OpBuilder<(ins "Value":$valueToStore, "Value":$memref), [{
       $_state.addOperands(valueToStore);
diff --git a/mlir/test/Dialect/MemRef/ops.mlir b/mlir/test/Dialect/MemRef/ops.mlir
index 6c2298a3f8acb..64a1f0f0ef4b5 100644
--- a/mlir/test/Dialect/MemRef/ops.mlir
+++ b/mlir/test/Dialect/MemRef/ops.mlir
@@ -624,3 +624,23 @@ func.func @memref_transpose_map(%src : memref<?x?xf32>) -> memref<?x?xf32, affin
   %dst = memref.transpose %src (i, j) -> (j, i) : memref<?x?xf32> to memref<?x?xf32, affine_map<(d0, d1)[s0] -> (d1 * s0 + d0)>>
   return %dst : memref<?x?xf32, affine_map<(d0, d1)[s0] -> (d1 * s0 + d0)>>
 }
+
+
+#alias_scope_domain = #memref.alias_scope_domain<id = distinct[0]<>, description = "The domain">
+#alias_scope1 = #memref.alias_scope<id = distinct[1]<>, description = "scope">
+#alias_scope2 = #memref.alias_scope<id = distinct[2]<>>
+
+// CHECK-LABEL: func @memref_alias_scope
+func.func @memref_alias_scope(%arg1 : memref<?xf32>, %arg2 : memref<?xf32>, %arg3: index) -> f32 {
+  // CHECK: %[[RES:.*]] = memref.alias_domain_scope #{{.*}} -> f32
+  %0 = memref.alias_domain_scope #alias_scope_domain -> f32 {
+  // CHECK: %[[VAL:.*]] = memref.load %{{.*}}[%{{.*}}] {alias = #memref.aliasing<alias_scopes = [#[[SCOPE1:.*]]], noalias = [#[[SCOPE2:.*]]]>} : memref<?xf32>
+  // CHECK: memref.store %[[VAL]], %{{.*}}[%{{.*}}] {alias = #memref.aliasing<alias_scopes = [#[[SCOPE2]]], noalias = [#[[SCOPE1]]]>} : memref<?xf32>
+  // CHECK: memref.alias_domain_scope.return %[[VAL]] : f32
+    %val = memref.load %arg1[%arg3] { alias = #memref.aliasing<alias_scopes=[#alias_scope1], noalias=[#alias_scope2]> } : memref<?xf32>
+    memref.store %val, %arg2[%arg3] { alias = #memref.aliasing<alias_scopes=[#alias_scope2], noalias=[#alias_scope1]> } : memref<?xf32>
+    memref.alias_domain_scope.return %val: f32
+  }
+  // CHECK: return %[[RES]]
+  return %0 : f32
+}

>From 5ef8b1bc4a5ced8c6c23ef5b7b3d4188d42f58e5 Mon Sep 17 00:00:00 2001
From: Ivan Butygin <ivan.butygin at gmail.com>
Date: Fri, 22 Aug 2025 16:32:28 +0200
Subject: [PATCH 03/12] interfaces

---
 .../mlir/Dialect/MemRef/IR/CMakeLists.txt     |  5 ++
 mlir/include/mlir/Dialect/MemRef/IR/MemRef.h  |  1 +
 .../mlir/Dialect/MemRef/IR/MemRefInterfaces.h | 18 +++++++
 .../Dialect/MemRef/IR/MemRefInterfaces.td     | 49 +++++++++++++++++++
 .../mlir/Dialect/MemRef/IR/MemRefOps.td       | 13 +++--
 mlir/lib/Dialect/MemRef/IR/CMakeLists.txt     |  3 +-
 mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp  |  2 +
 7 files changed, 85 insertions(+), 6 deletions(-)
 create mode 100644 mlir/include/mlir/Dialect/MemRef/IR/MemRefInterfaces.h
 create mode 100644 mlir/include/mlir/Dialect/MemRef/IR/MemRefInterfaces.td

diff --git a/mlir/include/mlir/Dialect/MemRef/IR/CMakeLists.txt b/mlir/include/mlir/Dialect/MemRef/IR/CMakeLists.txt
index 709bebb90760d..ae0d934cfde07 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/MemRef/IR/CMakeLists.txt
@@ -6,3 +6,8 @@ mlir_tablegen(MemRefAttrs.h.inc -gen-attrdef-decls -attrdefs-dialect=memref)
 mlir_tablegen(MemRefAttrs.cpp.inc -gen-attrdef-defs -attrdefs-dialect=memref)
 add_public_tablegen_target(MLIRMemRefAttrsIncGen)
 add_dependencies(mlir-headers MLIRMemRefAttrsIncGen)
+
+set(LLVM_TARGET_DEFINITIONS MemRefInterfaces.td)
+mlir_tablegen(MemRefInterfaces.h.inc -gen-op-interface-decls)
+mlir_tablegen(MemRefInterfaces.cpp.inc -gen-op-interface-defs)
+add_public_tablegen_target(MLIRMemRefInterfacesIncGen)
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRef.h b/mlir/include/mlir/Dialect/MemRef/IR/MemRef.h
index ac3d64a57331a..735237ef86cc5 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRef.h
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRef.h
@@ -12,6 +12,7 @@
 #include "mlir/Bytecode/BytecodeOpInterface.h"
 #include "mlir/Dialect/Arith/IR/Arith.h"
 #include "mlir/Dialect/MemRef/IR/MemRefAttrs.h"
+#include "mlir/Dialect/MemRef/IR/MemRefInterfaces.h"
 #include "mlir/Dialect/Utils/ReshapeOpsUtils.h"
 #include "mlir/IR/Dialect.h"
 #include "mlir/Interfaces/CallInterfaces.h"
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefInterfaces.h b/mlir/include/mlir/Dialect/MemRef/IR/MemRefInterfaces.h
new file mode 100644
index 0000000000000..e5d873412c24f
--- /dev/null
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefInterfaces.h
@@ -0,0 +1,18 @@
+//===- MemRefInterfaces.h - MemRef Interfaces -------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines op interfaces for the MemRef dialect in MLIR.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_MEMREF_MEMREFINTERFACES_H_
+#define MLIR_DIALECT_MEMREF_MEMREFINTERFACES_H_
+
+#include "mlir/Dialect/MemRef/IR/MemRefInterfaces.h.inc"
+
+#endif // MLIR_DIALECT_MEMREF_MEMREFINTERFACES_H_
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefInterfaces.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefInterfaces.td
new file mode 100644
index 0000000000000..632ba2fe1f302
--- /dev/null
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefInterfaces.td
@@ -0,0 +1,49 @@
+//===- MemRefInterfaces.td - Memref dialect interfaces -----*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MEMREF_INTERFACES
+#define MEMREF_INTERFACES
+
+include "mlir/IR/OpBase.td"
+
+def AliasAnalysisOpInterface : OpInterface<"AliasAnalysisOpInterface"> {
+  let description = [{
+    An interface for memory operations that can carry alias analysis metadata.
+    It provides setters and getters for the operation's alias analysis
+    attributes.
+  }];
+
+  let cppNamespace = "::mlir::memref";
+
+  let methods = [
+    InterfaceMethod<
+      /*desc=*/        "Returns the alias attribute or nullptr",
+      /*returnType=*/  "::mlir::memref::AliasingAttr",
+      /*methodName=*/  "getAliasingAttr",
+      /*args=*/        (ins),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{
+        auto op = cast<ConcreteOp>(this->getOperation());
+        return op.getAliasAttr();
+      }]
+      >,
+    InterfaceMethod<
+      /*desc=*/        "Sets the alias attribute",
+      /*returnType=*/  "void",
+      /*methodName=*/  "setAliasingAttr",
+      /*args=*/        (ins "::mlir::memref::AliasingAttr":$attr),
+      /*methodBody=*/  [{}],
+      /*defaultImpl=*/ [{
+        auto op = cast<ConcreteOp>(this->getOperation());
+        op.setAliasAttr(attr);
+      }]
+      >
+  ];
+}
+
+#endif // MEMREF_INTERFACES
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
index b6c3e89bde036..cd5f2c41930d5 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
@@ -10,8 +10,11 @@
 #define MEMREF_OPS
 
 include "mlir/Dialect/Arith/IR/ArithBase.td"
-include "mlir/Dialect/MemRef/IR/MemRefBase.td"
 include "mlir/Dialect/MemRef/IR/MemRefAttrs.td"
+include "mlir/Dialect/MemRef/IR/MemRefBase.td"
+include "mlir/Dialect/MemRef/IR/MemRefInterfaces.td"
+include "mlir/IR/OpAsmInterface.td"
+include "mlir/IR/SymbolInterfaces.td"
 include "mlir/Interfaces/CastInterfaces.td"
 include "mlir/Interfaces/ControlFlowInterfaces.td"
 include "mlir/Interfaces/CopyOpInterface.td"
@@ -21,8 +24,6 @@ include "mlir/Interfaces/MemorySlotInterfaces.td"
 include "mlir/Interfaces/ShapedOpInterfaces.td"
 include "mlir/Interfaces/SideEffectInterfaces.td"
 include "mlir/Interfaces/ViewLikeInterface.td"
-include "mlir/IR/OpAsmInterface.td"
-include "mlir/IR/SymbolInterfaces.td"
 
 /// A TypeAttr for memref types.
 def MemRefTypeAttr
@@ -1234,7 +1235,8 @@ def LoadOp : MemRef_Op<"load",
                      "::llvm::cast<MemRefType>($_self).getElementType()">,
       MemRefsNormalizable,
       DeclareOpInterfaceMethods<PromotableMemOpInterface>,
-      DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>]> {
+      DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
+      DeclareOpInterfaceMethods<AliasAnalysisOpInterface>]> {
   let summary = "load operation";
   let description = [{
     The `load` op reads an element from a memref at the specified indices.
@@ -1974,7 +1976,8 @@ def MemRef_StoreOp : MemRef_Op<"store",
                      "::llvm::cast<MemRefType>($_self).getElementType()">,
       MemRefsNormalizable,
       DeclareOpInterfaceMethods<PromotableMemOpInterface>,
-      DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>]> {
+      DeclareOpInterfaceMethods<DestructurableAccessorOpInterface>,
+      DeclareOpInterfaceMethods<AliasAnalysisOpInterface>]> {
   let summary = "store operation";
   let description = [{
     The `store` op stores an element into a memref at the specified indices.
diff --git a/mlir/lib/Dialect/MemRef/IR/CMakeLists.txt b/mlir/lib/Dialect/MemRef/IR/CMakeLists.txt
index e41f6c32b835c..9c4f8669b21b9 100644
--- a/mlir/lib/Dialect/MemRef/IR/CMakeLists.txt
+++ b/mlir/lib/Dialect/MemRef/IR/CMakeLists.txt
@@ -9,8 +9,9 @@ add_mlir_dialect_library(MLIRMemRefDialect
   ${PROJECT_SOURCE_DIR}/inlude/mlir/Dialect/MemRefDialect
 
   DEPENDS
-  MLIRMemRefOpsIncGen
   MLIRMemRefAttrsIncGen
+  MLIRMemRefInterfacesIncGen
+  MLIRMemRefOpsIncGen
 
   LINK_LIBS PUBLIC
   MLIRArithDialect
diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp
index 22ccad7d3c8ed..cf4d27bfa4cb0 100644
--- a/mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp
+++ b/mlir/lib/Dialect/MemRef/IR/MemRefDialect.cpp
@@ -25,6 +25,8 @@
 #define GET_ATTRDEF_CLASSES
 #include "mlir/Dialect/MemRef/IR/MemRefAttrs.cpp.inc"
 
+#include "mlir/Dialect/MemRef/IR/MemRefInterfaces.cpp.inc"
+
 using namespace mlir;
 using namespace mlir::memref;
 

>From cdba4f04a24f9bd9d16590e8723706276410c4bc Mon Sep 17 00:00:00 2001
From: Ivan Butygin <ivan.butygin at gmail.com>
Date: Fri, 22 Aug 2025 18:40:58 +0200
Subject: [PATCH 04/12] convert-memref-alias-attributes-to-llvm

---
 .../Conversion/MemRefToLLVM/MemRefToLLVM.h    |  3 ++
 mlir/include/mlir/Conversion/Passes.td        |  9 ++++
 .../mlir/Dialect/MemRef/IR/MemRefAttrs.td     | 10 ++++
 .../Conversion/MemRefToLLVM/MemRefToLLVM.cpp  | 48 +++++++++++++++++++
 .../memref-alias-attrs-to-llvm.mlir           | 21 ++++++++
 5 files changed, 91 insertions(+)
 create mode 100644 mlir/test/Conversion/MemRefToLLVM/memref-alias-attrs-to-llvm.mlir

diff --git a/mlir/include/mlir/Conversion/MemRefToLLVM/MemRefToLLVM.h b/mlir/include/mlir/Conversion/MemRefToLLVM/MemRefToLLVM.h
index e93d5bdce7bf2..b228437b3fee5 100644
--- a/mlir/include/mlir/Conversion/MemRefToLLVM/MemRefToLLVM.h
+++ b/mlir/include/mlir/Conversion/MemRefToLLVM/MemRefToLLVM.h
@@ -18,6 +18,9 @@ class LLVMTypeConverter;
 class RewritePatternSet;
 class SymbolTableCollection;
 
+#define GEN_PASS_DECL_CONVERTMEMREFALIASATTRIBUTESTOLLVMPASS
+#include "mlir/Conversion/Passes.h.inc"
+
 #define GEN_PASS_DECL_FINALIZEMEMREFTOLLVMCONVERSIONPASS
 #include "mlir/Conversion/Passes.h.inc"
 
diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td
index 2058aba7f9e37..342985d7c9555 100644
--- a/mlir/include/mlir/Conversion/Passes.td
+++ b/mlir/include/mlir/Conversion/Passes.td
@@ -868,6 +868,15 @@ def ConvertMemRefToEmitC : Pass<"convert-memref-to-emitc", "ModuleOp"> {
 // MemRefToLLVM
 //===----------------------------------------------------------------------===//
 
+def ConvertMemRefAliasAttributesToLLVMPass :
+    Pass<"convert-memref-alias-attributes-to-llvm"> {
+  let summary = "Convert MemRef aliasing attributes to LLVM";
+  let description = [{
+    TBD
+  }];
+  let dependentDialects = ["LLVM::LLVMDialect"];
+}
+
 def FinalizeMemRefToLLVMConversionPass :
     Pass<"finalize-memref-to-llvm", "ModuleOp"> {
   let summary = "Finalize MemRef dialect to LLVM dialect conversion";
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
index 7285b6d8c00b0..564d71c38047a 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
@@ -105,6 +105,16 @@ def MemRef_AliasingAttr : MemRef_Attr<"Aliasing", "aliasing"> {
     TBD
   }];
 
+  let builders = [
+    AttrBuilderWithInferredContext<(ins
+      "MLIRContext*":$context,
+      CArg<"ArrayRef<Attribute>", "{}">:$alias_scopes,
+      CArg<"ArrayRef<Attribute>", "{}">:$noalias
+    ), [{
+      return $_get(context, ArrayAttr::get(context, alias_scopes), ArrayAttr::get(context, noalias));
+    }]>
+  ];
+
   let assemblyFormat = "`<` struct(params) `>`";
 }
 
diff --git a/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp b/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
index 262e0e7a30c63..1ddf9cb4de1b9 100644
--- a/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
+++ b/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
@@ -32,6 +32,9 @@
 #define DEBUG_TYPE "memref-to-llvm"
 
 namespace mlir {
+#define GEN_PASS_DEF_CONVERTMEMREFALIASATTRIBUTESTOLLVMPASS
+#include "mlir/Conversion/Passes.h.inc"
+
 #define GEN_PASS_DEF_FINALIZEMEMREFTOLLVMCONVERSIONPASS
 #include "mlir/Conversion/Passes.h.inc"
 } // namespace mlir
@@ -2062,6 +2065,51 @@ struct FinalizeMemRefToLLVMConversionPass
   }
 };
 
+struct ConvertMemRefAliasAttributesToLLVMPass
+    : public impl::ConvertMemRefAliasAttributesToLLVMPassBase<
+          ConvertMemRefAliasAttributesToLLVMPass> {
+  using ConvertMemRefAliasAttributesToLLVMPassBase::
+      ConvertMemRefAliasAttributesToLLVMPassBase;
+
+  void runOnOperation() override {
+    Operation *op = getOperation();
+    MLIRContext *ctx = &getContext();
+    auto visitor = [&](memref::AliasAnalysisOpInterface aliasOp) -> WalkResult {
+      memref::AliasingAttr aliasingAttr = aliasOp.getAliasingAttr();
+      if (!aliasingAttr)
+        return WalkResult::advance();
+
+      auto scope = aliasOp->getParentOfType<memref::AliasDomainScopeOp>();
+      if (!scope) {
+        aliasOp.emitError("alias scope not found");
+        return WalkResult::interrupt();
+      }
+
+      memref::AliasScopeDomainAttr domain = scope.getDomain();
+      auto llvmDomain = LLVM::AliasScopeDomainAttr::get(
+          ctx, domain.getId(), domain.getDescription());
+      auto convertScope = [&](Attribute scope) -> Attribute {
+        auto memrefScope = dyn_cast_if_present<memref::AliasScopeAttr>(scope);
+        if (!memrefScope)
+          return scope;
+
+        return LLVM::AliasScopeAttr::get(ctx, memrefScope.getId(), llvmDomain,
+                                         memrefScope.getDescription());
+      };
+      SmallVector<Attribute> scopes =
+          llvm::map_to_vector(aliasingAttr.getAliasScopes(), convertScope);
+      SmallVector<Attribute> noaliasScopes =
+          llvm::map_to_vector(aliasingAttr.getNoalias(), convertScope);
+      auto newAliasingAttr =
+          memref::AliasingAttr::get(ctx, scopes, noaliasScopes);
+      aliasOp.setAliasingAttr(newAliasingAttr);
+      return WalkResult::advance();
+    };
+    if (op->walk(visitor).wasInterrupted())
+      return signalPassFailure();
+  }
+};
+
 /// Implement the interface to convert MemRef to LLVM.
 struct MemRefToLLVMDialectInterface : public ConvertToLLVMPatternInterface {
   using ConvertToLLVMPatternInterface::ConvertToLLVMPatternInterface;
diff --git a/mlir/test/Conversion/MemRefToLLVM/memref-alias-attrs-to-llvm.mlir b/mlir/test/Conversion/MemRefToLLVM/memref-alias-attrs-to-llvm.mlir
new file mode 100644
index 0000000000000..2e3bf644d9975
--- /dev/null
+++ b/mlir/test/Conversion/MemRefToLLVM/memref-alias-attrs-to-llvm.mlir
@@ -0,0 +1,21 @@
+// RUN: mlir-opt --convert-memref-alias-attributes-to-llvm %s | FileCheck %s
+
+#alias_scope_domain = #memref.alias_scope_domain<id = distinct[0]<>, description = "The domain">
+#alias_scope1 = #memref.alias_scope<id = distinct[1]<>, description = "scope">
+#alias_scope2 = #memref.alias_scope<id = distinct[2]<>>
+
+// CHECK: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<id = distinct[0]<>, description = "The domain">
+// CHECK-DAG: #[[SCOPE1:.*]] = #llvm.alias_scope<id = distinct[1]<>, domain = #[[DOMAIN]], description = "scope">
+// CHECK-DAG: #[[SCOPE2:.*]] = #llvm.alias_scope<id = distinct[2]<>, domain = #[[DOMAIN]]>
+
+// CHECK: func @memref_alias_attributes
+func.func @memref_alias_attributes(%arg1 : memref<?xf32>, %arg2 : memref<?xf32>, %arg3: index) -> f32 {
+  %0 = memref.alias_domain_scope #alias_scope_domain -> f32 {
+  // CHECK:  %[[VAL:.*]] = memref.load %{{.*}}[%{{.*}}] {alias = #memref.aliasing<alias_scopes = [#[[SCOPE1]]], noalias = [#[[SCOPE2]]]>} : memref<?xf32>
+  // CHECK:  memref.store %[[VAL]], %{{.*}}[%{{.*}}] {alias = #memref.aliasing<alias_scopes = [#[[SCOPE2]]], noalias = [#[[SCOPE1]]]>} : memref<?xf32>
+    %val = memref.load %arg1[%arg3] { alias = #memref.aliasing<alias_scopes=[#alias_scope1], noalias=[#alias_scope2]> } : memref<?xf32>
+    memref.store %val, %arg2[%arg3] { alias = #memref.aliasing<alias_scopes=[#alias_scope2], noalias=[#alias_scope1]> } : memref<?xf32>
+    memref.alias_domain_scope.return %val: f32
+  }
+  return %0 : f32
+}

>From c7dc256af293ff0b559e3579880fd486fb5ccb99 Mon Sep 17 00:00:00 2001
From: Ivan Butygin <ivan.butygin at gmail.com>
Date: Fri, 22 Aug 2025 19:20:59 +0200
Subject: [PATCH 05/12] llvm conversion

---
 .../mlir/Dialect/MemRef/IR/MemRefOps.td       |  5 ++
 .../Conversion/MemRefToLLVM/MemRefToLLVM.cpp  | 68 +++++++++++++++----
 mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp      | 10 +++
 .../MemRefToLLVM/memref-to-llvm.mlir          | 24 +++++++
 4 files changed, 95 insertions(+), 12 deletions(-)

diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
index cd5f2c41930d5..aef81d1543196 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
@@ -471,6 +471,11 @@ def MemRef_AliasDomainScopeOp : MemRef_Op<"alias_domain_scope", [
   let regions = (region SizedRegion<1>:$region);
 
   let assemblyFormat = "attr-dict $domain (`->` type($results)^)? $region";
+
+  let extraClassDeclaration = [{
+    /// Inline op body into parent region and erase the op.
+    static void inlineIntoParent(PatternRewriter &builder, AliasDomainScopeOp op);
+  }];
 }
 
 def MemRef_AliasDomainScopeReturnOp : MemRef_Op<"alias_domain_scope.return", [
diff --git a/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp b/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
index 1ddf9cb4de1b9..e30aee77e956a 100644
--- a/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
+++ b/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
@@ -881,6 +881,22 @@ struct GetGlobalMemrefOpLowering
   }
 };
 
+static FailureOr<std::pair<ArrayAttr, ArrayAttr>>
+getAliasScopes(Attribute attr) {
+  if (!attr)
+    return std::pair(ArrayAttr(), ArrayAttr());
+
+  auto aliasingAttr = cast<memref::AliasingAttr>(attr);
+  auto checkAttr = [](Attribute elem) -> bool {
+    return isa<LLVM::AliasScopeAttr>(elem);
+  };
+  if (!llvm::all_of(aliasingAttr.getAliasScopes(), checkAttr) ||
+      !llvm::all_of(aliasingAttr.getNoalias(), checkAttr))
+    return failure();
+
+  return std::pair(aliasingAttr.getAliasScopes(), aliasingAttr.getNoalias());
+}
+
 // Load operation is lowered to obtaining a pointer to the indexed element
 // and loading it.
 struct LoadOpLowering : public LoadStoreOpLowering<memref::LoadOp> {
@@ -890,6 +906,10 @@ struct LoadOpLowering : public LoadStoreOpLowering<memref::LoadOp> {
   matchAndRewrite(memref::LoadOp loadOp, OpAdaptor adaptor,
                   ConversionPatternRewriter &rewriter) const override {
     auto type = loadOp.getMemRefType();
+    FailureOr<std::pair<ArrayAttr, ArrayAttr>> aliasScopes =
+        getAliasScopes(loadOp.getAliasAttr());
+    if (failed(aliasScopes))
+      return rewriter.notifyMatchFailure(loadOp, "invalid alias attribute");
 
     // Per memref.load spec, the indices must be in-bounds:
     // 0 <= idx < dim_size, and additionally all offsets are non-negative,
@@ -897,9 +917,11 @@ struct LoadOpLowering : public LoadStoreOpLowering<memref::LoadOp> {
     Value dataPtr = getStridedElementPtr(rewriter, loadOp.getLoc(), type,
                                          adaptor.getMemref(),
                                          adaptor.getIndices(), kNoWrapFlags);
-    rewriter.replaceOpWithNewOp<LLVM::LoadOp>(
+    auto op = rewriter.replaceOpWithNewOp<LLVM::LoadOp>(
         loadOp, typeConverter->convertType(type.getElementType()), dataPtr,
         loadOp.getAlignment().value_or(0), false, loadOp.getNontemporal());
+    op.setAliasScopes(aliasScopes->first);
+    op.setNoAliasScopes(aliasScopes->second);
     return success();
   }
 };
@@ -910,19 +932,25 @@ struct StoreOpLowering : public LoadStoreOpLowering<memref::StoreOp> {
   using Base::Base;
 
   LogicalResult
-  matchAndRewrite(memref::StoreOp op, OpAdaptor adaptor,
+  matchAndRewrite(memref::StoreOp storeOp, OpAdaptor adaptor,
                   ConversionPatternRewriter &rewriter) const override {
-    auto type = op.getMemRefType();
+    auto type = storeOp.getMemRefType();
+    FailureOr<std::pair<ArrayAttr, ArrayAttr>> aliasScopes =
+        getAliasScopes(storeOp.getAliasAttr());
+    if (failed(aliasScopes))
+      return rewriter.notifyMatchFailure(storeOp, "invalid alias attribute");
 
     // Per memref.store spec, the indices must be in-bounds:
     // 0 <= idx < dim_size, and additionally all offsets are non-negative,
     // hence inbounds and nuw are used when lowering to llvm.getelementptr.
-    Value dataPtr =
-        getStridedElementPtr(rewriter, op.getLoc(), type, adaptor.getMemref(),
-                             adaptor.getIndices(), kNoWrapFlags);
-    rewriter.replaceOpWithNewOp<LLVM::StoreOp>(op, adaptor.getValue(), dataPtr,
-                                               op.getAlignment().value_or(0),
-                                               false, op.getNontemporal());
+    Value dataPtr = getStridedElementPtr(rewriter, storeOp.getLoc(), type,
+                                         adaptor.getMemref(),
+                                         adaptor.getIndices(), kNoWrapFlags);
+    auto op = rewriter.replaceOpWithNewOp<LLVM::StoreOp>(
+        storeOp, adaptor.getValue(), dataPtr,
+        storeOp.getAlignment().value_or(0), false, storeOp.getNontemporal());
+    op.setAliasScopes(aliasScopes->first);
+    op.setNoAliasScopes(aliasScopes->second);
     return success();
   }
 };
@@ -1991,6 +2019,21 @@ class ExtractStridedMetadataOpLowering
   }
 };
 
+/// Unpack the pointer returned by a memref.alias_domain_scope.
+class ConvertAliasDomainScope
+    : public ConvertOpToLLVMPattern<memref::AliasDomainScopeOp> {
+public:
+  using ConvertOpToLLVMPattern::ConvertOpToLLVMPattern;
+
+  LogicalResult
+  matchAndRewrite(memref::AliasDomainScopeOp op, OpAdaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    // We no longer need AliasDomainScopeOp as this stage so just remove it.
+    memref::AliasDomainScopeOp::inlineIntoParent(rewriter, op);
+    return success();
+  }
+};
+
 } // namespace
 
 void mlir::populateFinalizeMemRefToLLVMConversionPatterns(
@@ -2000,8 +2043,9 @@ void mlir::populateFinalizeMemRefToLLVMConversionPatterns(
   patterns.add<
       AllocaOpLowering,
       AllocaScopeOpLowering,
-      AtomicRMWOpLowering,
       AssumeAlignmentOpLowering,
+      AtomicRMWOpLowering,
+      ConvertAliasDomainScope,
       ConvertExtractAlignedPointerAsIndex,
       DimOpLowering,
       ExtractStridedMetadataOpLowering,
@@ -2009,13 +2053,13 @@ void mlir::populateFinalizeMemRefToLLVMConversionPatterns(
       GetGlobalMemrefOpLowering,
       LoadOpLowering,
       MemRefCastOpLowering,
-      MemorySpaceCastOpLowering,
       MemRefReinterpretCastOpLowering,
       MemRefReshapeOpLowering,
+      MemorySpaceCastOpLowering,
       PrefetchOpLowering,
       RankOpLowering,
-      ReassociatingReshapeOpConversion<memref::ExpandShapeOp>,
       ReassociatingReshapeOpConversion<memref::CollapseShapeOp>,
+      ReassociatingReshapeOpConversion<memref::ExpandShapeOp>,
       StoreOpLowering,
       SubViewOpLowering,
       TransposeOpLowering,
diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
index d0f766e282d1e..28722ba5adc19 100644
--- a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
+++ b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp
@@ -539,6 +539,16 @@ void AliasDomainScopeOp::getSuccessorRegions(
   regions.push_back(RegionSuccessor(getResults()));
 }
 
+void AliasDomainScopeOp::inlineIntoParent(mlir::PatternRewriter &builder,
+                                          AliasDomainScopeOp op) {
+  mlir::Block *block = &op.getRegion().front();
+  Operation *term = block->getTerminator();
+  SmallVector<Value> args = llvm::to_vector(term->getOperands());
+  builder.eraseOp(term);
+  builder.inlineBlockBefore(block, op);
+  builder.replaceOp(op, args);
+}
+
 //===----------------------------------------------------------------------===//
 // AssumeAlignmentOp
 //===----------------------------------------------------------------------===//
diff --git a/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir b/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir
index 45b1a1f1ca40c..3b054746ca253 100644
--- a/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir
+++ b/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir
@@ -800,3 +800,27 @@ func.func @alloca_unconvertable_memory_space() {
   %alloca = memref.alloca() : memref<1x32x33xi32, #spirv.storage_class<StorageBuffer>>
   func.return
 }
+
+// -----
+
+#alias_scope_domain = #memref.alias_scope_domain<id = distinct[0]<>, description = "The domain">
+#llvm_domain = #llvm.alias_scope_domain<id = distinct[0]<>, description = "The domain">
+#scope1 = #llvm.alias_scope<id = distinct[1]<>, domain = #llvm_domain, description = "scope">
+#scope2 = #llvm.alias_scope<id = distinct[2]<>, domain = #llvm_domain>
+
+// CHECK: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<id = distinct[0]<>, description = "The domain">
+// CHECK-DAG: #[[SCOPE1:.*]] = #llvm.alias_scope<id = distinct[1]<>, domain = #[[DOMAIN]], description = "scope">
+// CHECK-DAG: #[[SCOPE2:.*]] = #llvm.alias_scope<id = distinct[2]<>, domain = #[[DOMAIN]]>
+
+// CHECK: func @memref_alias_attributes
+func.func @memref_alias_attributes(%arg1 : memref<?xf32>, %arg2 : memref<?xf32>, %arg3: index) -> f32 {
+  // CHECK-NOT:  memref.alias_domain_scope
+  %0 = memref.alias_domain_scope #alias_scope_domain -> f32 {
+  // CHECK:  llvm.load {{.*}} {alias_scopes = [#[[SCOPE1]]], noalias_scopes = [#[[SCOPE2]]]}
+  // CHECK:  llvm.store {{.*}} {alias_scopes = [#[[SCOPE2]]], noalias_scopes = [#[[SCOPE1]]]}
+    %val = memref.load %arg1[%arg3] { alias = #memref.aliasing<alias_scopes=[#scope1], noalias=[#scope2]> } : memref<?xf32>
+    memref.store %val, %arg2[%arg3] { alias = #memref.aliasing<alias_scopes=[#scope2], noalias=[#scope1]> } : memref<?xf32>
+    memref.alias_domain_scope.return %val: f32
+  }
+  return %0 : f32
+}

>From d2d5c85e05ea06f033d8d2bc7197e57732408347 Mon Sep 17 00:00:00 2001
From: Ivan Butygin <ivan.butygin at gmail.com>
Date: Fri, 22 Aug 2025 20:00:57 +0200
Subject: [PATCH 06/12] update tests

---
 mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir b/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir
index 3b054746ca253..b67c3067ed670 100644
--- a/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir
+++ b/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir
@@ -804,9 +804,9 @@ func.func @alloca_unconvertable_memory_space() {
 // -----
 
 #alias_scope_domain = #memref.alias_scope_domain<id = distinct[0]<>, description = "The domain">
-#llvm_domain = #llvm.alias_scope_domain<id = distinct[0]<>, description = "The domain">
-#scope1 = #llvm.alias_scope<id = distinct[1]<>, domain = #llvm_domain, description = "scope">
-#scope2 = #llvm.alias_scope<id = distinct[2]<>, domain = #llvm_domain>
+#llvm_domain = #llvm.alias_scope_domain<id = distinct[1]<>, description = "The domain">
+#scope1 = #llvm.alias_scope<id = distinct[2]<>, domain = #llvm_domain, description = "scope">
+#scope2 = #llvm.alias_scope<id = distinct[3]<>, domain = #llvm_domain>
 
 // CHECK: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<id = distinct[0]<>, description = "The domain">
 // CHECK-DAG: #[[SCOPE1:.*]] = #llvm.alias_scope<id = distinct[1]<>, domain = #[[DOMAIN]], description = "scope">
@@ -816,11 +816,12 @@ func.func @alloca_unconvertable_memory_space() {
 func.func @memref_alias_attributes(%arg1 : memref<?xf32>, %arg2 : memref<?xf32>, %arg3: index) -> f32 {
   // CHECK-NOT:  memref.alias_domain_scope
   %0 = memref.alias_domain_scope #alias_scope_domain -> f32 {
-  // CHECK:  llvm.load {{.*}} {alias_scopes = [#[[SCOPE1]]], noalias_scopes = [#[[SCOPE2]]]}
-  // CHECK:  llvm.store {{.*}} {alias_scopes = [#[[SCOPE2]]], noalias_scopes = [#[[SCOPE1]]]}
+  // CHECK:  %[[VAL:.*]] = llvm.load {{.*}} {alias_scopes = [#[[SCOPE1]]], noalias_scopes = [#[[SCOPE2]]]}
+  // CHECK:  llvm.store %[[VAL]], {{.*}} {alias_scopes = [#[[SCOPE2]]], noalias_scopes = [#[[SCOPE1]]]}
     %val = memref.load %arg1[%arg3] { alias = #memref.aliasing<alias_scopes=[#scope1], noalias=[#scope2]> } : memref<?xf32>
     memref.store %val, %arg2[%arg3] { alias = #memref.aliasing<alias_scopes=[#scope2], noalias=[#scope1]> } : memref<?xf32>
     memref.alias_domain_scope.return %val: f32
   }
+  // CHECK: return %[[VAL]]
   return %0 : f32
 }

>From ba45a8fda1bc6235346767b875cf94c365b2e7d6 Mon Sep 17 00:00:00 2001
From: Ivan Butygin <ivan.butygin at gmail.com>
Date: Fri, 22 Aug 2025 23:18:51 +0200
Subject: [PATCH 07/12] remove #memref.alias_scope_domain

---
 .../mlir/Dialect/MemRef/IR/MemRefAttrs.td     | 30 -------------
 .../mlir/Dialect/MemRef/IR/MemRefOps.td       |  5 ++-
 .../Conversion/MemRefToLLVM/MemRefToLLVM.cpp  | 42 ++++++++++---------
 .../memref-alias-attrs-to-llvm.mlir           | 27 ++++++++----
 .../MemRefToLLVM/memref-to-llvm.mlir          | 19 ++++-----
 mlir/test/Dialect/MemRef/ops.mlir             | 12 +++---
 6 files changed, 59 insertions(+), 76 deletions(-)

diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
index 564d71c38047a..1e747f3fc1efe 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
@@ -20,36 +20,6 @@ class MemRef_Attr<string name, string attrMnemonic,
   let mnemonic = attrMnemonic;
 }
 
-
-//===----------------------------------------------------------------------===//
-// AliasScopeDomainAttr
-//===----------------------------------------------------------------------===//
-
-def MemRef_AliasScopeDomainAttr : MemRef_Attr<"AliasScopeDomain",
-                                              "alias_scope_domain"> {
-  let parameters = (ins
-    "Attribute":$id,
-    OptionalParameter<"StringAttr">:$description
-  );
-
-  let builders = [
-    AttrBuilder<(ins CArg<"StringAttr", "{}">:$description), [{
-      return $_get($_ctxt, DistinctAttr::create(UnitAttr::get($_ctxt)), description);
-    }]>
-  ];
-
-  let summary = "TBD";
-
-  let description = [{
-    TBD
-  }];
-
-  let assemblyFormat = "`<` struct(params) `>`";
-
-  // Generate mnemonic alias for the attribute.
-  let genMnemonicAlias = 1;
-}
-
 //===----------------------------------------------------------------------===//
 // AliasScopeAttr
 //===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
index aef81d1543196..fd8c4b0930e21 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
@@ -465,12 +465,13 @@ def MemRef_AliasDomainScopeOp : MemRef_Op<"alias_domain_scope", [
     TBD
   }];
 
-  let arguments = (ins MemRef_AliasScopeDomainAttr:$domain);
+  let arguments = (ins OptionalAttr<StrAttr>:$description);
   let results = (outs Variadic<AnyType>:$results);
 
   let regions = (region SizedRegion<1>:$region);
 
-  let assemblyFormat = "attr-dict $domain (`->` type($results)^)? $region";
+  let assemblyFormat =
+      "( $description^ )? (`->` type($results)^)? $region attr-dict";
 
   let extraClassDeclaration = [{
     /// Inline op body into parent region and erase the op.
diff --git a/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp b/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
index e30aee77e956a..dfe58874c9fce 100644
--- a/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
+++ b/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
@@ -2019,21 +2019,6 @@ class ExtractStridedMetadataOpLowering
   }
 };
 
-/// Unpack the pointer returned by a memref.alias_domain_scope.
-class ConvertAliasDomainScope
-    : public ConvertOpToLLVMPattern<memref::AliasDomainScopeOp> {
-public:
-  using ConvertOpToLLVMPattern::ConvertOpToLLVMPattern;
-
-  LogicalResult
-  matchAndRewrite(memref::AliasDomainScopeOp op, OpAdaptor adaptor,
-                  ConversionPatternRewriter &rewriter) const override {
-    // We no longer need AliasDomainScopeOp as this stage so just remove it.
-    memref::AliasDomainScopeOp::inlineIntoParent(rewriter, op);
-    return success();
-  }
-};
-
 } // namespace
 
 void mlir::populateFinalizeMemRefToLLVMConversionPatterns(
@@ -2045,7 +2030,6 @@ void mlir::populateFinalizeMemRefToLLVMConversionPatterns(
       AllocaScopeOpLowering,
       AssumeAlignmentOpLowering,
       AtomicRMWOpLowering,
-      ConvertAliasDomainScope,
       ConvertExtractAlignedPointerAsIndex,
       DimOpLowering,
       ExtractStridedMetadataOpLowering,
@@ -2109,6 +2093,11 @@ struct FinalizeMemRefToLLVMConversionPass
   }
 };
 
+struct TrivialPatternRewriter : public PatternRewriter {
+  explicit TrivialPatternRewriter(MLIRContext *context)
+      : PatternRewriter(context) {}
+};
+
 struct ConvertMemRefAliasAttributesToLLVMPass
     : public impl::ConvertMemRefAliasAttributesToLLVMPassBase<
           ConvertMemRefAliasAttributesToLLVMPass> {
@@ -2118,6 +2107,9 @@ struct ConvertMemRefAliasAttributesToLLVMPass
   void runOnOperation() override {
     Operation *op = getOperation();
     MLIRContext *ctx = &getContext();
+    llvm::SmallDenseMap<memref::AliasDomainScopeOp, LLVM::AliasScopeDomainAttr>
+        aliasScopeMap;
+    SmallVector<memref::AliasDomainScopeOp> aliasScopeOps;
     auto visitor = [&](memref::AliasAnalysisOpInterface aliasOp) -> WalkResult {
       memref::AliasingAttr aliasingAttr = aliasOp.getAliasingAttr();
       if (!aliasingAttr)
@@ -2129,15 +2121,21 @@ struct ConvertMemRefAliasAttributesToLLVMPass
         return WalkResult::interrupt();
       }
 
-      memref::AliasScopeDomainAttr domain = scope.getDomain();
-      auto llvmDomain = LLVM::AliasScopeDomainAttr::get(
-          ctx, domain.getId(), domain.getDescription());
+      LLVM::AliasScopeDomainAttr domain = aliasScopeMap.lookup(scope);
+
+      if (!domain) {
+        domain =
+            LLVM::AliasScopeDomainAttr::get(ctx, scope.getDescriptionAttr());
+        aliasScopeMap[scope] = domain;
+        aliasScopeOps.push_back(scope);
+      }
+
       auto convertScope = [&](Attribute scope) -> Attribute {
         auto memrefScope = dyn_cast_if_present<memref::AliasScopeAttr>(scope);
         if (!memrefScope)
           return scope;
 
-        return LLVM::AliasScopeAttr::get(ctx, memrefScope.getId(), llvmDomain,
+        return LLVM::AliasScopeAttr::get(ctx, memrefScope.getId(), domain,
                                          memrefScope.getDescription());
       };
       SmallVector<Attribute> scopes =
@@ -2151,6 +2149,10 @@ struct ConvertMemRefAliasAttributesToLLVMPass
     };
     if (op->walk(visitor).wasInterrupted())
       return signalPassFailure();
+
+    TrivialPatternRewriter rewriter(ctx);
+    for (memref::AliasDomainScopeOp scope : aliasScopeOps)
+      memref::AliasDomainScopeOp::inlineIntoParent(rewriter, scope);
   }
 };
 
diff --git a/mlir/test/Conversion/MemRefToLLVM/memref-alias-attrs-to-llvm.mlir b/mlir/test/Conversion/MemRefToLLVM/memref-alias-attrs-to-llvm.mlir
index 2e3bf644d9975..88ace5cd4fa05 100644
--- a/mlir/test/Conversion/MemRefToLLVM/memref-alias-attrs-to-llvm.mlir
+++ b/mlir/test/Conversion/MemRefToLLVM/memref-alias-attrs-to-llvm.mlir
@@ -1,21 +1,34 @@
 // RUN: mlir-opt --convert-memref-alias-attributes-to-llvm %s | FileCheck %s
 
-#alias_scope_domain = #memref.alias_scope_domain<id = distinct[0]<>, description = "The domain">
 #alias_scope1 = #memref.alias_scope<id = distinct[1]<>, description = "scope">
 #alias_scope2 = #memref.alias_scope<id = distinct[2]<>>
 
-// CHECK: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<id = distinct[0]<>, description = "The domain">
-// CHECK-DAG: #[[SCOPE1:.*]] = #llvm.alias_scope<id = distinct[1]<>, domain = #[[DOMAIN]], description = "scope">
-// CHECK-DAG: #[[SCOPE2:.*]] = #llvm.alias_scope<id = distinct[2]<>, domain = #[[DOMAIN]]>
+// CHECK-DAG: #[[DOMAIN1:.*]] = #llvm.alias_scope_domain<id = {{.*}}, description = "foo">
+// CHECK-DAG: #[[DOMAIN2:.*]] = #llvm.alias_scope_domain<id = {{.*}}>
+// CHECK-DAG: #[[SCOPE1_1:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN1]], description = "scope">
+// CHECK-DAG: #[[SCOPE1_2:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN1]]>
+// CHECK-DAG: #[[SCOPE2_1:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN2]], description = "scope">
+// CHECK-DAG: #[[SCOPE2_2:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN2]]>
 
 // CHECK: func @memref_alias_attributes
 func.func @memref_alias_attributes(%arg1 : memref<?xf32>, %arg2 : memref<?xf32>, %arg3: index) -> f32 {
-  %0 = memref.alias_domain_scope #alias_scope_domain -> f32 {
-  // CHECK:  %[[VAL:.*]] = memref.load %{{.*}}[%{{.*}}] {alias = #memref.aliasing<alias_scopes = [#[[SCOPE1]]], noalias = [#[[SCOPE2]]]>} : memref<?xf32>
-  // CHECK:  memref.store %[[VAL]], %{{.*}}[%{{.*}}] {alias = #memref.aliasing<alias_scopes = [#[[SCOPE2]]], noalias = [#[[SCOPE1]]]>} : memref<?xf32>
+  // CHECK-NOT: alias_domain_scope
+  memref.alias_domain_scope "foo" {
+  // CHECK:  %[[VAL:.*]] = memref.load %{{.*}}[%{{.*}}] {alias = #memref.aliasing<alias_scopes = [#[[SCOPE1_1]]], noalias = [#[[SCOPE1_2]]]>} : memref<?xf32>
+  // CHECK:  memref.store %[[VAL]], %{{.*}}[%{{.*}}] {alias = #memref.aliasing<alias_scopes = [#[[SCOPE1_2]]], noalias = [#[[SCOPE1_1]]]>} : memref<?xf32>
+    %val = memref.load %arg1[%arg3] { alias = #memref.aliasing<alias_scopes=[#alias_scope1], noalias=[#alias_scope2]> } : memref<?xf32>
+    memref.store %val, %arg2[%arg3] { alias = #memref.aliasing<alias_scopes=[#alias_scope2], noalias=[#alias_scope1]> } : memref<?xf32>
+    memref.alias_domain_scope.return
+  }
+
+  // CHECK-NOT: alias_domain_scope
+  %0 = memref.alias_domain_scope -> f32 {
+  // CHECK:  %[[VAL:.*]] = memref.load %{{.*}}[%{{.*}}] {alias = #memref.aliasing<alias_scopes = [#[[SCOPE2_1]]], noalias = [#[[SCOPE2_2]]]>} : memref<?xf32>
+  // CHECK:  memref.store %[[VAL]], %{{.*}}[%{{.*}}] {alias = #memref.aliasing<alias_scopes = [#[[SCOPE2_2]]], noalias = [#[[SCOPE2_1]]]>} : memref<?xf32>
     %val = memref.load %arg1[%arg3] { alias = #memref.aliasing<alias_scopes=[#alias_scope1], noalias=[#alias_scope2]> } : memref<?xf32>
     memref.store %val, %arg2[%arg3] { alias = #memref.aliasing<alias_scopes=[#alias_scope2], noalias=[#alias_scope1]> } : memref<?xf32>
     memref.alias_domain_scope.return %val: f32
   }
+  // CHECK: return %[[VAL]]
   return %0 : f32
 }
diff --git a/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir b/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir
index b67c3067ed670..1f7f686ba7b8e 100644
--- a/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir
+++ b/mlir/test/Conversion/MemRefToLLVM/memref-to-llvm.mlir
@@ -803,25 +803,20 @@ func.func @alloca_unconvertable_memory_space() {
 
 // -----
 
-#alias_scope_domain = #memref.alias_scope_domain<id = distinct[0]<>, description = "The domain">
 #llvm_domain = #llvm.alias_scope_domain<id = distinct[1]<>, description = "The domain">
 #scope1 = #llvm.alias_scope<id = distinct[2]<>, domain = #llvm_domain, description = "scope">
 #scope2 = #llvm.alias_scope<id = distinct[3]<>, domain = #llvm_domain>
 
-// CHECK: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<id = distinct[0]<>, description = "The domain">
-// CHECK-DAG: #[[SCOPE1:.*]] = #llvm.alias_scope<id = distinct[1]<>, domain = #[[DOMAIN]], description = "scope">
-// CHECK-DAG: #[[SCOPE2:.*]] = #llvm.alias_scope<id = distinct[2]<>, domain = #[[DOMAIN]]>
+// CHECK: #[[DOMAIN:.*]] = #llvm.alias_scope_domain<id = {{.*}}, description = "The domain">
+// CHECK-DAG: #[[SCOPE1:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]], description = "scope">
+// CHECK-DAG: #[[SCOPE2:.*]] = #llvm.alias_scope<id = {{.*}}, domain = #[[DOMAIN]]>
 
 // CHECK: func @memref_alias_attributes
-func.func @memref_alias_attributes(%arg1 : memref<?xf32>, %arg2 : memref<?xf32>, %arg3: index) -> f32 {
+func.func @memref_alias_attributes(%arg1 : memref<?xf32>, %arg2 : memref<?xf32>, %arg3: index) {
   // CHECK-NOT:  memref.alias_domain_scope
-  %0 = memref.alias_domain_scope #alias_scope_domain -> f32 {
   // CHECK:  %[[VAL:.*]] = llvm.load {{.*}} {alias_scopes = [#[[SCOPE1]]], noalias_scopes = [#[[SCOPE2]]]}
   // CHECK:  llvm.store %[[VAL]], {{.*}} {alias_scopes = [#[[SCOPE2]]], noalias_scopes = [#[[SCOPE1]]]}
-    %val = memref.load %arg1[%arg3] { alias = #memref.aliasing<alias_scopes=[#scope1], noalias=[#scope2]> } : memref<?xf32>
-    memref.store %val, %arg2[%arg3] { alias = #memref.aliasing<alias_scopes=[#scope2], noalias=[#scope1]> } : memref<?xf32>
-    memref.alias_domain_scope.return %val: f32
-  }
-  // CHECK: return %[[VAL]]
-  return %0 : f32
+  %val = memref.load %arg1[%arg3] { alias = #memref.aliasing<alias_scopes=[#scope1], noalias=[#scope2]> } : memref<?xf32>
+  memref.store %val, %arg2[%arg3] { alias = #memref.aliasing<alias_scopes=[#scope2], noalias=[#scope1]> } : memref<?xf32>
+  return
 }
diff --git a/mlir/test/Dialect/MemRef/ops.mlir b/mlir/test/Dialect/MemRef/ops.mlir
index 64a1f0f0ef4b5..a5b42ec03b9f4 100644
--- a/mlir/test/Dialect/MemRef/ops.mlir
+++ b/mlir/test/Dialect/MemRef/ops.mlir
@@ -626,14 +626,16 @@ func.func @memref_transpose_map(%src : memref<?x?xf32>) -> memref<?x?xf32, affin
 }
 
 
-#alias_scope_domain = #memref.alias_scope_domain<id = distinct[0]<>, description = "The domain">
-#alias_scope1 = #memref.alias_scope<id = distinct[1]<>, description = "scope">
-#alias_scope2 = #memref.alias_scope<id = distinct[2]<>>
+#alias_scope1 = #memref.alias_scope<id = distinct[0]<>, description = "scope">
+#alias_scope2 = #memref.alias_scope<id = distinct[1]<>>
 
 // CHECK-LABEL: func @memref_alias_scope
 func.func @memref_alias_scope(%arg1 : memref<?xf32>, %arg2 : memref<?xf32>, %arg3: index) -> f32 {
-  // CHECK: %[[RES:.*]] = memref.alias_domain_scope #{{.*}} -> f32
-  %0 = memref.alias_domain_scope #alias_scope_domain -> f32 {
+  // CHECK: memref.alias_domain_scope "The Domain"
+  memref.alias_domain_scope "The Domain" {}
+
+  // CHECK: %[[RES:.*]] = memref.alias_domain_scope -> f32
+  %0 = memref.alias_domain_scope -> f32 {
   // CHECK: %[[VAL:.*]] = memref.load %{{.*}}[%{{.*}}] {alias = #memref.aliasing<alias_scopes = [#[[SCOPE1:.*]]], noalias = [#[[SCOPE2:.*]]]>} : memref<?xf32>
   // CHECK: memref.store %[[VAL]], %{{.*}}[%{{.*}}] {alias = #memref.aliasing<alias_scopes = [#[[SCOPE2]]], noalias = [#[[SCOPE1]]]>} : memref<?xf32>
   // CHECK: memref.alias_domain_scope.return %[[VAL]] : f32

>From 1dd81beff12f2013394e1b463faff3fe84e20453 Mon Sep 17 00:00:00 2001
From: Ivan Butygin <ivan.butygin at gmail.com>
Date: Fri, 22 Aug 2025 23:33:01 +0200
Subject: [PATCH 08/12] docs

---
 .../mlir/Dialect/MemRef/IR/MemRefAttrs.td     | 34 ++++++++++++++--
 .../mlir/Dialect/MemRef/IR/MemRefOps.td       | 39 ++++++++++++++++---
 2 files changed, 64 insertions(+), 9 deletions(-)

diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
index 1e747f3fc1efe..0190adfde0d33 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefAttrs.td
@@ -39,10 +39,35 @@ def MemRef_AliasScopeAttr : MemRef_Attr<"AliasScope", "alias_scope"> {
     }]>
   ];
 
-  let summary = "TBD";
+  let summary = "MemRef dialect alias scope";
 
   let description = [{
-    TBD
+    Defines an alias scope that can be attached to a memory-accessing operation.
+    Such scopes can be used in combination with `noalias` metadata to indicate
+    that sets of memory-affecting operations in one scope do not alias with
+    memory-affecting operations in another scope.
+
+    This attribute must be used in conjunctions with
+    `memref.alias_domain_scope`.
+
+    Example:
+    ```
+    #alias_scope1 = #memref.alias_scope<id = distinct[0]<>, description = "scope">
+    #alias_scope2 = #memref.alias_scope<id = distinct[1]<>>
+
+    func.func @memref_alias_scope(%arg1 : memref<?xf32>, %arg2 : memref<?xf32>, %arg3: index) -> f32 {
+      %0 = memref.alias_domain_scope "The Domain" -> f32 {
+        %val = memref.load %arg1[%arg3] { alias = #memref.aliasing<alias_scopes=[#alias_scope1], noalias=[#alias_scope2]> } : memref<?xf32>
+        memref.store %val, %arg2[%arg3] { alias = #memref.aliasing<alias_scopes=[#alias_scope2], noalias=[#alias_scope1]> } : memref<?xf32>
+        memref.alias_domain_scope.return %val: f32
+      }
+      return %0 : f32
+    }
+    ```
+
+    This attribute is modeled against LLVM alias scopes, see the following link
+    for more details:
+    https://llvm.org/docs/LangRef.html#noalias-and-alias-scope-metadata
   }];
 
   let assemblyFormat = "`<` struct(params) `>`";
@@ -69,10 +94,11 @@ def MemRef_AliasingAttr : MemRef_Attr<"Aliasing", "aliasing"> {
     "ArrayAttr":$noalias
   );
 
-  let summary = "TBD";
+  let summary = "MemRef dialect aliasing attribute";
 
   let description = [{
-    TBD
+    This attribute combines `alias_scopes` and `noalias` arrays into single
+    attribute.
   }];
 
   let builders = [
diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
index fd8c4b0930e21..63cc01bf956fc 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
@@ -459,10 +459,32 @@ def MemRef_AllocaScopeReturnOp : MemRef_Op<"alloca_scope.return",
 def MemRef_AliasDomainScopeOp : MemRef_Op<"alias_domain_scope", [
     DeclareOpInterfaceMethods<RegionBranchOpInterface>,
     SingleBlockImplicitTerminator<"AliasDomainScopeReturnOp">,
-    RecursiveMemoryEffects]> {
-  let summary = "TBD";
+    RecursiveMemoryEffects,
+    NoRegionArguments]> {
+  let summary = "aliasing domain scope for alias_scope annotations";
   let description = [{
-    TBD
+    Defines a domain that will be associated with an alias scope for the ops
+    inside the region. In case of multiple nested `alias_domain_scope` ops the
+    innermost will take the precence.
+
+    Example:
+    ```
+    #alias_scope1 = #memref.alias_scope<id = distinct[0]<>, description = "scope">
+    #alias_scope2 = #memref.alias_scope<id = distinct[1]<>>
+
+    func.func @memref_alias_scope(%arg1 : memref<?xf32>, %arg2 : memref<?xf32>, %arg3: index) -> f32 {
+      %0 = memref.alias_domain_scope "The Domain" -> f32 {
+        %val = memref.load %arg1[%arg3] { alias = #memref.aliasing<alias_scopes=[#alias_scope1], noalias=[#alias_scope2]> } : memref<?xf32>
+        memref.store %val, %arg2[%arg3] { alias = #memref.aliasing<alias_scopes=[#alias_scope2], noalias=[#alias_scope1]> } : memref<?xf32>
+        memref.alias_domain_scope.return %val: f32
+      }
+      return %0 : f32
+    }
+    ```
+
+    The alias scopes are modeled against LLVM alias scopes, see the following
+    link for more details:
+    https://llvm.org/docs/LangRef.html#noalias-and-alias-scope-metadata
   }];
 
   let arguments = (ins OptionalAttr<StrAttr>:$description);
@@ -484,9 +506,16 @@ def MemRef_AliasDomainScopeReturnOp : MemRef_Op<"alias_domain_scope.return", [
   HasParent<"AliasDomainScopeOp">
   ]> {
 
-  let summary = "TBD";
+  let summary = "terminator for alias_domain_scope operation";
   let description = [{
-    TBD
+    `memref.alias_domain_scope.return` operation returns zero or more SSA values
+    from the region within `memref.alias_domain_scope`. If no values are returned,
+    the return operation may be omitted. Otherwise, it has to be present
+    to indicate which values are going to be returned. For example:
+
+    ```mlir
+    memref.alias_domain_scope.return %value
+    ```
   }];
 
   let arguments = (ins Variadic<AnyType>:$results);

>From 349e1cbf09e43043d2700deed591b749f26a6e7a Mon Sep 17 00:00:00 2001
From: Ivan Butygin <ivan.butygin at gmail.com>
Date: Fri, 22 Aug 2025 23:57:32 +0200
Subject: [PATCH 09/12] more docs

---
 mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
index 63cc01bf956fc..b715d68e254d6 100644
--- a/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
+++ b/mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td
@@ -1296,8 +1296,14 @@ def LoadOp : MemRef_Op<"load",
     memory at an address aligned to this boundary. Violations may lead to
     architecture-specific faults or performance penalties.
     A value of 0 indicates no specific alignment requirement.
-    Example:
 
+    An optional `alias` attribute allows to specify the aliasing metadata for
+    the op and works in conjunction with `alias_domain_scope` op. If attribute
+    is missing op is assumed to potentially alias with any other load or store
+    op. Dropping this attribute during the transformations is safe and can only
+    result in missing optimizations.
+
+    Example:
     ```mlir
     %0 = memref.load %A[%a, %b] : memref<8x?xi32, #layout, memspace0>
     ```
@@ -2034,8 +2040,14 @@ def MemRef_StoreOp : MemRef_Op<"store",
     memory at an address aligned to this boundary. Violations may lead to
     architecture-specific faults or performance penalties.
     A value of 0 indicates no specific alignment requirement.
-    Example:
 
+    An optional `alias` attribute allows to specify the aliasing metadata for
+    the op and works in conjunction with `alias_domain_scope` op. If attribute
+    is missing op is assumed to potentially alias with any other load or store
+    op. Dropping this attribute during the transformations is safe and can only
+    result in missing optimizations.
+
+    Example:
     ```mlir
     memref.store %val, %A[%a, %b] : memref<8x?xi32, #layout, memspace0>
     ```

>From 86f69289d9a792d75e82a6cd2a25465ce8ae1281 Mon Sep 17 00:00:00 2001
From: Ivan Butygin <ivan.butygin at gmail.com>
Date: Sat, 23 Aug 2025 00:13:32 +0200
Subject: [PATCH 10/12] pass doc

---
 mlir/include/mlir/Conversion/Passes.td | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td
index 342985d7c9555..af42123254d03 100644
--- a/mlir/include/mlir/Conversion/Passes.td
+++ b/mlir/include/mlir/Conversion/Passes.td
@@ -872,7 +872,9 @@ def ConvertMemRefAliasAttributesToLLVMPass :
     Pass<"convert-memref-alias-attributes-to-llvm"> {
   let summary = "Convert MemRef aliasing attributes to LLVM";
   let description = [{
-    TBD
+    Convert MemRef dialect alising attibutes to LLVM dialect ones and erase
+    alias domain ops. This pass must be called before
+    `--finalize-memref-to-llvm`.
   }];
   let dependentDialects = ["LLVM::LLVMDialect"];
 }

>From 9ca5a7407dab7db7adfff3ab9d74f6a2970e4f99 Mon Sep 17 00:00:00 2001
From: Ivan Butygin <ivan.butygin at gmail.com>
Date: Sat, 23 Aug 2025 02:23:02 +0200
Subject: [PATCH 11/12] fix region removal

---
 mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp b/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
index dfe58874c9fce..2e1fb2f282861 100644
--- a/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
+++ b/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
@@ -2109,7 +2109,6 @@ struct ConvertMemRefAliasAttributesToLLVMPass
     MLIRContext *ctx = &getContext();
     llvm::SmallDenseMap<memref::AliasDomainScopeOp, LLVM::AliasScopeDomainAttr>
         aliasScopeMap;
-    SmallVector<memref::AliasDomainScopeOp> aliasScopeOps;
     auto visitor = [&](memref::AliasAnalysisOpInterface aliasOp) -> WalkResult {
       memref::AliasingAttr aliasingAttr = aliasOp.getAliasingAttr();
       if (!aliasingAttr)
@@ -2127,7 +2126,6 @@ struct ConvertMemRefAliasAttributesToLLVMPass
         domain =
             LLVM::AliasScopeDomainAttr::get(ctx, scope.getDescriptionAttr());
         aliasScopeMap[scope] = domain;
-        aliasScopeOps.push_back(scope);
       }
 
       auto convertScope = [&](Attribute scope) -> Attribute {
@@ -2151,8 +2149,9 @@ struct ConvertMemRefAliasAttributesToLLVMPass
       return signalPassFailure();
 
     TrivialPatternRewriter rewriter(ctx);
-    for (memref::AliasDomainScopeOp scope : aliasScopeOps)
+    op->walk([&](memref::AliasDomainScopeOp scope) {
       memref::AliasDomainScopeOp::inlineIntoParent(rewriter, scope);
+    });
   }
 };
 

>From 41706f93bcf0c2c978b0eca94962d5f36d774336 Mon Sep 17 00:00:00 2001
From: Ivan Butygin <ivan.butygin at gmail.com>
Date: Mon, 25 Aug 2025 15:23:50 +0200
Subject: [PATCH 12/12] Use PatternRewriter

---
 mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp b/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
index 2e1fb2f282861..e046147f50e1d 100644
--- a/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
+++ b/mlir/lib/Conversion/MemRefToLLVM/MemRefToLLVM.cpp
@@ -2093,11 +2093,6 @@ struct FinalizeMemRefToLLVMConversionPass
   }
 };
 
-struct TrivialPatternRewriter : public PatternRewriter {
-  explicit TrivialPatternRewriter(MLIRContext *context)
-      : PatternRewriter(context) {}
-};
-
 struct ConvertMemRefAliasAttributesToLLVMPass
     : public impl::ConvertMemRefAliasAttributesToLLVMPassBase<
           ConvertMemRefAliasAttributesToLLVMPass> {
@@ -2148,7 +2143,7 @@ struct ConvertMemRefAliasAttributesToLLVMPass
     if (op->walk(visitor).wasInterrupted())
       return signalPassFailure();
 
-    TrivialPatternRewriter rewriter(ctx);
+    PatternRewriter rewriter(ctx);
     op->walk([&](memref::AliasDomainScopeOp scope) {
       memref::AliasDomainScopeOp::inlineIntoParent(rewriter, scope);
     });



More information about the Mlir-commits mailing list