Skip to content

Commit 2b8f887

Browse files
authored
[mlir][Ptr] Add the MemorySpaceAttrInterface interface and dependencies. (#86870)
This patch introduces the `MemorySpaceAttrInterface` interface. This interface is responsible for handling the semantics of `ptr` operations. For example, this interface can be used to create read-only memory spaces, making any other operation other than a load a verification error, see `TestConstMemorySpaceAttr` for a possible implementation of this concept. This patch also introduces Enum dependencies `AtomicOrdering`, and `AtomicBinOp`, both enumerations are clones of the Enums with the same name in the LLVM Dialect. Also, see: - [[RFC] `ptr` dialect & modularizing ptr ops in the LLVM dialect](https://discourse.llvm.org/t/rfc-ptr-dialect-modularizing-ptr-ops-in-the-llvm-dialect/75142) for rationale. - #73057 for a prototype implementation of the full change. **Note: Ignore the first commit, that's being reviewed in #86860 .**
1 parent b3d280b commit 2b8f887

17 files changed

+371
-64
lines changed

mlir/include/mlir/Dialect/Ptr/IR/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,15 @@ set(LLVM_TARGET_DEFINITIONS PtrOps.td)
55
mlir_tablegen(PtrOpsAttrs.h.inc -gen-attrdef-decls -attrdefs-dialect=ptr)
66
mlir_tablegen(PtrOpsAttrs.cpp.inc -gen-attrdef-defs -attrdefs-dialect=ptr)
77
add_public_tablegen_target(MLIRPtrOpsAttributesIncGen)
8+
9+
set(LLVM_TARGET_DEFINITIONS MemorySpaceInterfaces.td)
10+
mlir_tablegen(MemorySpaceInterfaces.h.inc -gen-op-interface-decls)
11+
mlir_tablegen(MemorySpaceInterfaces.cpp.inc -gen-op-interface-defs)
12+
mlir_tablegen(MemorySpaceAttrInterfaces.h.inc -gen-attr-interface-decls)
13+
mlir_tablegen(MemorySpaceAttrInterfaces.cpp.inc -gen-attr-interface-defs)
14+
add_public_tablegen_target(MLIRPtrMemorySpaceInterfacesIncGen)
15+
16+
set(LLVM_TARGET_DEFINITIONS PtrOps.td)
17+
mlir_tablegen(PtrOpsEnums.h.inc -gen-enum-decls)
18+
mlir_tablegen(PtrOpsEnums.cpp.inc -gen-enum-defs)
19+
add_public_tablegen_target(MLIRPtrOpsEnumsGen)
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//===-- MemorySpaceInterfaces.h - ptr memory space interfaces ---*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file defines the ptr dialect memory space interfaces.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef MLIR_DIALECT_PTR_IR_MEMORYSPACEINTERFACES_H
14+
#define MLIR_DIALECT_PTR_IR_MEMORYSPACEINTERFACES_H
15+
16+
#include "mlir/IR/Attributes.h"
17+
#include "mlir/IR/BuiltinAttributes.h"
18+
#include "mlir/IR/OpDefinition.h"
19+
20+
namespace mlir {
21+
class Operation;
22+
namespace ptr {
23+
enum class AtomicBinOp : uint64_t;
24+
enum class AtomicOrdering : uint64_t;
25+
} // namespace ptr
26+
} // namespace mlir
27+
28+
#include "mlir/Dialect/Ptr/IR/MemorySpaceAttrInterfaces.h.inc"
29+
30+
#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h.inc"
31+
32+
#endif // MLIR_DIALECT_PTR_IR_MEMORYSPACEINTERFACES_H
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
//===-- MemorySpaceInterfaces.td - Memory space interfaces ----------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file defines memory space attribute interfaces.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef PTR_MEMORYSPACEINTERFACES
14+
#define PTR_MEMORYSPACEINTERFACES
15+
16+
include "mlir/IR/AttrTypeBase.td"
17+
include "mlir/IR/OpBase.td"
18+
19+
//===----------------------------------------------------------------------===//
20+
// Memory space attribute interface.
21+
//===----------------------------------------------------------------------===//
22+
23+
def MemorySpaceAttrInterface : AttrInterface<"MemorySpaceAttrInterface"> {
24+
let description = [{
25+
This interface defines a common API for interacting with the memory model of
26+
a memory space and the operations in the pointer dialect.
27+
28+
Furthermore, this interface allows concepts such as read-only memory to be
29+
adequately modeled and enforced.
30+
}];
31+
let cppNamespace = "::mlir::ptr";
32+
let methods = [
33+
InterfaceMethod<
34+
/*desc=*/ [{
35+
This method checks if it's valid to load a value from the memory space
36+
with a specific type, alignment, and atomic ordering.
37+
If `emitError` is non-null then the method is allowed to emit errors.
38+
}],
39+
/*returnType=*/ "::mlir::LogicalResult",
40+
/*methodName=*/ "isValidLoad",
41+
/*args=*/ (ins "::mlir::Type":$type,
42+
"::mlir::ptr::AtomicOrdering":$ordering,
43+
"::mlir::IntegerAttr":$alignment,
44+
"::llvm::function_ref<::mlir::InFlightDiagnostic()>":$emitError)
45+
>,
46+
InterfaceMethod<
47+
/*desc=*/ [{
48+
This method checks if it's valid to store a value in the memory space
49+
with a specific type, alignment, and atomic ordering.
50+
If `emitError` is non-null then the method is allowed to emit errors.
51+
}],
52+
/*returnType=*/ "::mlir::LogicalResult",
53+
/*methodName=*/ "isValidStore",
54+
/*args=*/ (ins "::mlir::Type":$type,
55+
"::mlir::ptr::AtomicOrdering":$ordering,
56+
"::mlir::IntegerAttr":$alignment,
57+
"::llvm::function_ref<::mlir::InFlightDiagnostic()>":$emitError)
58+
>,
59+
InterfaceMethod<
60+
/*desc=*/ [{
61+
This method checks if it's valid to perform an atomic operation in the
62+
memory space with a specific type, alignment, and atomic ordering.
63+
If `emitError` is non-null then the method is allowed to emit errors.
64+
}],
65+
/*returnType=*/ "::mlir::LogicalResult",
66+
/*methodName=*/ "isValidAtomicOp",
67+
/*args=*/ (ins "::mlir::ptr::AtomicBinOp":$op,
68+
"::mlir::Type":$type,
69+
"::mlir::ptr::AtomicOrdering":$ordering,
70+
"::mlir::IntegerAttr":$alignment,
71+
"::llvm::function_ref<::mlir::InFlightDiagnostic()>":$emitError)
72+
>,
73+
InterfaceMethod<
74+
/*desc=*/ [{
75+
This method checks if it's valid to perform an atomic exchange operation
76+
in the memory space with a specific type, alignment, and atomic
77+
orderings.
78+
If `emitError` is non-null then the method is allowed to emit errors.
79+
}],
80+
/*returnType=*/ "::mlir::LogicalResult",
81+
/*methodName=*/ "isValidAtomicXchg",
82+
/*args=*/ (ins "::mlir::Type":$type,
83+
"::mlir::ptr::AtomicOrdering":$successOrdering,
84+
"::mlir::ptr::AtomicOrdering":$failureOrdering,
85+
"::mlir::IntegerAttr":$alignment,
86+
"::llvm::function_ref<::mlir::InFlightDiagnostic()>":$emitError)
87+
>,
88+
InterfaceMethod<
89+
/*desc=*/ [{
90+
This method checks if it's valid to perform an `addrspacecast` op
91+
in the memory space.
92+
If `emitError` is non-null then the method is allowed to emit errors.
93+
}],
94+
/*returnType=*/ "::mlir::LogicalResult",
95+
/*methodName=*/ "isValidAddrSpaceCast",
96+
/*args=*/ (ins "::mlir::Type":$tgt,
97+
"::mlir::Type":$src,
98+
"::llvm::function_ref<::mlir::InFlightDiagnostic()>":$emitError)
99+
>,
100+
InterfaceMethod<
101+
/*desc=*/ [{
102+
This method checks if it's valid to perform a `ptrtoint` or `inttoptr`
103+
op in the memory space.
104+
The first type is expected to be integer-like, while the second must be a
105+
ptr-like type.
106+
If `emitError` is non-null then the method is allowed to emit errors.
107+
}],
108+
/*returnType=*/ "::mlir::LogicalResult",
109+
/*methodName=*/ "isValidPtrIntCast",
110+
/*args=*/ (ins "::mlir::Type":$intLikeTy,
111+
"::mlir::Type":$ptrLikeTy,
112+
"::llvm::function_ref<::mlir::InFlightDiagnostic()>":$emitError)
113+
>,
114+
];
115+
}
116+
117+
#endif // PTR_MEMORYSPACEINTERFACES

mlir/include/mlir/Dialect/Ptr/IR/PtrAttrs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,6 @@
1818
#define GET_ATTRDEF_CLASSES
1919
#include "mlir/Dialect/Ptr/IR/PtrOpsAttrs.h.inc"
2020

21+
#include "mlir/Dialect/Ptr/IR/PtrOpsEnums.h.inc"
22+
2123
#endif // MLIR_DIALECT_PTR_IR_PTRATTRS_H

mlir/include/mlir/Dialect/Ptr/IR/PtrDialect.td

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def Ptr_PtrType : Ptr_Type<"Ptr", "ptr", [
4545
let description = [{
4646
The `ptr` type is an opaque pointer type. This type typically represents a
4747
handle to an object in memory or target-dependent values like `nullptr`.
48-
Pointers are optionally parameterized by a memory space.
48+
Pointers are parameterized by a memory space.
4949

5050
Syntax:
5151

@@ -54,14 +54,14 @@ def Ptr_PtrType : Ptr_Type<"Ptr", "ptr", [
5454
memory-space ::= attribute-value
5555
```
5656
}];
57-
let parameters = (ins OptionalParameter<"Attribute">:$memorySpace);
58-
let assemblyFormat = "(`<` $memorySpace^ `>`)?";
57+
let parameters = (ins "MemorySpaceAttrInterface":$memorySpace);
58+
let assemblyFormat = "`<` $memorySpace `>`";
5959
let builders = [
60-
TypeBuilder<(ins CArg<"Attribute", "nullptr">:$memorySpace), [{
61-
return $_get($_ctxt, memorySpace);
60+
TypeBuilderWithInferredContext<(ins
61+
"MemorySpaceAttrInterface":$memorySpace), [{
62+
return $_get(memorySpace.getContext(), memorySpace);
6263
}]>
6364
];
64-
let skipDefaultBuilders = 1;
6565
}
6666

6767
//===----------------------------------------------------------------------===//
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//===-- PtrEnums.td - Ptr dialect enumerations -------------*- tablegen -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef PTR_ENUMS
10+
#define PTR_ENUMS
11+
12+
include "mlir/IR/EnumAttr.td"
13+
14+
//===----------------------------------------------------------------------===//
15+
// Atomic binary op enum attribute.
16+
//===----------------------------------------------------------------------===//
17+
18+
def AtomicBinOpXchg : I64EnumAttrCase<"xchg", 0, "xchg">;
19+
def AtomicBinOpAdd : I64EnumAttrCase<"add", 1, "add">;
20+
def AtomicBinOpSub : I64EnumAttrCase<"sub", 2, "sub">;
21+
def AtomicBinOpAnd : I64EnumAttrCase<"_and", 3, "_and">;
22+
def AtomicBinOpNand : I64EnumAttrCase<"nand", 4, "nand">;
23+
def AtomicBinOpOr : I64EnumAttrCase<"_or", 5, "_or">;
24+
def AtomicBinOpXor : I64EnumAttrCase<"_xor", 6, "_xor">;
25+
def AtomicBinOpMax : I64EnumAttrCase<"max", 7, "max">;
26+
def AtomicBinOpMin : I64EnumAttrCase<"min", 8, "min">;
27+
def AtomicBinOpUMax : I64EnumAttrCase<"umax", 9, "umax">;
28+
def AtomicBinOpUMin : I64EnumAttrCase<"umin", 10, "umin">;
29+
def AtomicBinOpFAdd : I64EnumAttrCase<"fadd", 11, "fadd">;
30+
def AtomicBinOpFSub : I64EnumAttrCase<"fsub", 12, "fsub">;
31+
def AtomicBinOpFMax : I64EnumAttrCase<"fmax", 13, "fmax">;
32+
def AtomicBinOpFMin : I64EnumAttrCase<"fmin", 14, "fmin">;
33+
def AtomicBinOpUIncWrap : I64EnumAttrCase<"uinc_wrap", 15, "uinc_wrap">;
34+
def AtomicBinOpUDecWrap : I64EnumAttrCase<"udec_wrap", 16, "udec_wrap">;
35+
36+
def AtomicBinOp : I64EnumAttr<
37+
"AtomicBinOp",
38+
"ptr.atomicrmw binary operations",
39+
[AtomicBinOpXchg, AtomicBinOpAdd, AtomicBinOpSub, AtomicBinOpAnd,
40+
AtomicBinOpNand, AtomicBinOpOr, AtomicBinOpXor, AtomicBinOpMax,
41+
AtomicBinOpMin, AtomicBinOpUMax, AtomicBinOpUMin, AtomicBinOpFAdd,
42+
AtomicBinOpFSub, AtomicBinOpFMax, AtomicBinOpFMin, AtomicBinOpUIncWrap,
43+
AtomicBinOpUDecWrap]> {
44+
let cppNamespace = "::mlir::ptr";
45+
}
46+
47+
//===----------------------------------------------------------------------===//
48+
// Atomic ordering enum attribute.
49+
//===----------------------------------------------------------------------===//
50+
51+
def AtomicOrderingNotAtomic : I64EnumAttrCase<"not_atomic", 0, "not_atomic">;
52+
def AtomicOrderingUnordered : I64EnumAttrCase<"unordered", 1, "unordered">;
53+
def AtomicOrderingMonotonic : I64EnumAttrCase<"monotonic", 2, "monotonic">;
54+
def AtomicOrderingAcquire : I64EnumAttrCase<"acquire", 3, "acquire">;
55+
def AtomicOrderingRelease : I64EnumAttrCase<"release", 4, "release">;
56+
def AtomicOrderingAcqRel : I64EnumAttrCase<"acq_rel", 5, "acq_rel">;
57+
def AtomicOrderingSeqCst : I64EnumAttrCase<"seq_cst", 6, "seq_cst">;
58+
59+
def AtomicOrdering : I64EnumAttr<
60+
"AtomicOrdering",
61+
"Atomic ordering for LLVM's memory model",
62+
[AtomicOrderingNotAtomic, AtomicOrderingUnordered, AtomicOrderingMonotonic,
63+
AtomicOrderingAcquire, AtomicOrderingRelease, AtomicOrderingAcqRel,
64+
AtomicOrderingSeqCst
65+
]> {
66+
let cppNamespace = "::mlir::ptr";
67+
}
68+
69+
#endif // PTR_ENUMS

mlir/include/mlir/Dialect/Ptr/IR/PtrOps.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
include "mlir/Dialect/Ptr/IR/PtrDialect.td"
1313
include "mlir/Dialect/Ptr/IR/PtrAttrDefs.td"
14+
include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.td"
1415
include "mlir/IR/OpAsmInterface.td"
1516

1617
#endif // PTR_OPS

mlir/include/mlir/Dialect/Ptr/IR/PtrTypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef MLIR_DIALECT_PTR_IR_PTRTYPES_H
1414
#define MLIR_DIALECT_PTR_IR_PTRTYPES_H
1515

16+
#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h"
1617
#include "mlir/IR/Types.h"
1718
#include "mlir/Interfaces/DataLayoutInterfaces.h"
1819

mlir/lib/Dialect/Ptr/IR/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ add_mlir_dialect_library(
77
DEPENDS
88
MLIRPtrOpsAttributesIncGen
99
MLIRPtrOpsIncGen
10-
10+
MLIRPtrOpsEnumsGen
11+
MLIRPtrMemorySpaceInterfacesIncGen
1112
LINK_LIBS
1213
PUBLIC
1314
MLIRIR

mlir/lib/Dialect/Ptr/IR/PtrDialect.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ void PtrDialect::initialize() {
4848
#define GET_ATTRDEF_CLASSES
4949
#include "mlir/Dialect/Ptr/IR/PtrOpsAttrs.cpp.inc"
5050

51+
#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.cpp.inc"
52+
53+
#include "mlir/Dialect/Ptr/IR/MemorySpaceAttrInterfaces.cpp.inc"
54+
55+
#include "mlir/Dialect/Ptr/IR/PtrOpsEnums.cpp.inc"
56+
5157
#define GET_TYPEDEF_CLASSES
5258
#include "mlir/Dialect/Ptr/IR/PtrOpsTypes.cpp.inc"
5359

mlir/lib/Dialect/Ptr/IR/PtrTypes.cpp

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ constexpr const static unsigned kDefaultPointerAlignmentBits = 8;
2828
/// Searches the data layout for the pointer spec, returns nullptr if it is not
2929
/// found.
3030
static SpecAttr getPointerSpec(DataLayoutEntryListRef params, PtrType type,
31-
Attribute defaultMemorySpace) {
31+
MemorySpaceAttrInterface defaultMemorySpace) {
3232
for (DataLayoutEntryInterface entry : params) {
3333
if (!entry.isTypeEntry())
3434
continue;
@@ -38,9 +38,11 @@ static SpecAttr getPointerSpec(DataLayoutEntryListRef params, PtrType type,
3838
return spec;
3939
}
4040
}
41-
// If not found, and this is the pointer to the default memory space, assume
42-
// 64-bit pointers.
43-
if (type.getMemorySpace() == defaultMemorySpace)
41+
// If not found, and this is the pointer to the default memory space or if
42+
// `defaultMemorySpace` is null, assume 64-bit pointers. `defaultMemorySpace`
43+
// might be null if the data layout doesn't define the default memory space.
44+
if (type.getMemorySpace() == defaultMemorySpace ||
45+
defaultMemorySpace == nullptr)
4446
return SpecAttr::get(type.getContext(), kDefaultPointerSizeBits,
4547
kDefaultPointerAlignmentBits,
4648
kDefaultPointerAlignmentBits, kDefaultPointerSizeBits);
@@ -93,44 +95,47 @@ bool PtrType::areCompatible(DataLayoutEntryListRef oldLayout,
9395

9496
uint64_t PtrType::getABIAlignment(const DataLayout &dataLayout,
9597
DataLayoutEntryListRef params) const {
96-
Attribute defaultMemorySpace = dataLayout.getDefaultMemorySpace();
98+
auto defaultMemorySpace = llvm::cast_if_present<MemorySpaceAttrInterface>(
99+
dataLayout.getDefaultMemorySpace());
97100
if (SpecAttr spec = getPointerSpec(params, *this, defaultMemorySpace))
98101
return spec.getAbi() / kBitsInByte;
99102

100-
return dataLayout.getTypeABIAlignment(get(getContext(), defaultMemorySpace));
103+
return dataLayout.getTypeABIAlignment(get(defaultMemorySpace));
101104
}
102105

103106
std::optional<uint64_t>
104107
PtrType::getIndexBitwidth(const DataLayout &dataLayout,
105108
DataLayoutEntryListRef params) const {
106-
Attribute defaultMemorySpace = dataLayout.getDefaultMemorySpace();
109+
auto defaultMemorySpace = llvm::cast_if_present<MemorySpaceAttrInterface>(
110+
dataLayout.getDefaultMemorySpace());
107111
if (SpecAttr spec = getPointerSpec(params, *this, defaultMemorySpace)) {
108112
return spec.getIndex() == SpecAttr::kOptionalSpecValue ? spec.getSize()
109113
: spec.getIndex();
110114
}
111115

112-
return dataLayout.getTypeIndexBitwidth(get(getContext(), defaultMemorySpace));
116+
return dataLayout.getTypeIndexBitwidth(get(defaultMemorySpace));
113117
}
114118

115119
llvm::TypeSize PtrType::getTypeSizeInBits(const DataLayout &dataLayout,
116120
DataLayoutEntryListRef params) const {
117-
Attribute defaultMemorySpace = dataLayout.getDefaultMemorySpace();
121+
auto defaultMemorySpace = llvm::cast_if_present<MemorySpaceAttrInterface>(
122+
dataLayout.getDefaultMemorySpace());
118123
if (SpecAttr spec = getPointerSpec(params, *this, defaultMemorySpace))
119124
return llvm::TypeSize::getFixed(spec.getSize());
120125

121126
// For other memory spaces, use the size of the pointer to the default memory
122127
// space.
123-
return dataLayout.getTypeSizeInBits(get(getContext(), defaultMemorySpace));
128+
return dataLayout.getTypeSizeInBits(get(defaultMemorySpace));
124129
}
125130

126131
uint64_t PtrType::getPreferredAlignment(const DataLayout &dataLayout,
127132
DataLayoutEntryListRef params) const {
128-
Attribute defaultMemorySpace = dataLayout.getDefaultMemorySpace();
133+
auto defaultMemorySpace = llvm::cast_if_present<MemorySpaceAttrInterface>(
134+
dataLayout.getDefaultMemorySpace());
129135
if (SpecAttr spec = getPointerSpec(params, *this, defaultMemorySpace))
130136
return spec.getPreferred() / kBitsInByte;
131137

132-
return dataLayout.getTypePreferredAlignment(
133-
get(getContext(), defaultMemorySpace));
138+
return dataLayout.getTypePreferredAlignment(get(defaultMemorySpace));
134139
}
135140

136141
LogicalResult PtrType::verifyEntries(DataLayoutEntryListRef entries,

0 commit comments

Comments
 (0)