[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> ®ions) {
+ // 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