Skip to content

Commit 556cd71

Browse files
committed
[mlir] Ptr dialect llvm#73057
This patch introduces the Ptr dialect, a dialect to model pointer operations motivated by the goal of modularizing the LLVM dialect. More specifically, this patch introduces: - The pointer dialect and type. - The `MemorySpaceAttrInterface` interface, an interface to conceptualize memory models, giving proper semantical meaning to the Ptr dialect ops. - The `ptr::LoadOp` operation, an operation to load data from memory, with the semantics defined by `MemorySpaceAttrInterface` and translatable to LLVM IR. - The `SharedDialectTypeInterface` interface, an interface to delegate printing and parsing to a different dialect. - The introduction of `LLVM::AddressSpaceAttr`, an attribute to model LLVM memory semantics. - The replacement of `LLVMPointerType` with `ptr::PtrType`.
1 parent d312788 commit 556cd71

31 files changed

+3104
-1
lines changed

mlir/include/mlir/Dialect/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ add_subdirectory(OpenACCMPCommon)
2828
add_subdirectory(OpenMP)
2929
add_subdirectory(PDL)
3030
add_subdirectory(PDLInterp)
31+
add_subdirectory(Ptr)
3132
add_subdirectory(Quant)
3233
add_subdirectory(SCF)
3334
add_subdirectory(Shape)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
add_subdirectory(IR)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
add_mlir_dialect(PtrOps ptr)
2+
add_mlir_doc(PtrOps PtrOps Dialects/ -gen-op-doc)
3+
4+
set(LLVM_TARGET_DEFINITIONS MemorySpaceInterfaces.td)
5+
mlir_tablegen(MemorySpaceInterfaces.h.inc -gen-op-interface-decls)
6+
mlir_tablegen(MemorySpaceInterfaces.cpp.inc -gen-op-interface-defs)
7+
mlir_tablegen(MemorySpaceAttrInterfaces.h.inc -gen-attr-interface-decls)
8+
mlir_tablegen(MemorySpaceAttrInterfaces.cpp.inc -gen-attr-interface-defs)
9+
add_public_tablegen_target(MLIRPtrMemorySpaceInterfacesIncGen)
10+
11+
set(LLVM_TARGET_DEFINITIONS PtrInterfaces.td)
12+
mlir_tablegen(PtrInterfaces.h.inc -gen-op-interface-decls)
13+
mlir_tablegen(PtrInterfaces.cpp.inc -gen-op-interface-defs)
14+
add_public_tablegen_target(MLIRPtrInterfacesIncGen)
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)
20+
21+
set(LLVM_TARGET_DEFINITIONS PtrOps.td)
22+
mlir_tablegen(PtrOpsAttrs.h.inc -gen-attrdef-decls -attrdefs-dialect=ptr)
23+
mlir_tablegen(PtrOpsAttrs.cpp.inc -gen-attrdef-defs -attrdefs-dialect=ptr)
24+
add_public_tablegen_target(MLIRPtrOpsAttributesIncGen)
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
//===-- MemoryModel.h - ptr dialect memory model ---------------*- 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's dialect memory model class and related
10+
// interfaces.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef MLIR_DIALECT_PTR_IR_MEMORYMODEL_H
15+
#define MLIR_DIALECT_PTR_IR_MEMORYMODEL_H
16+
17+
#include "mlir/IR/Attributes.h"
18+
#include "mlir/IR/BuiltinAttributes.h"
19+
#include "mlir/IR/OpDefinition.h"
20+
21+
namespace mlir {
22+
class Operation;
23+
namespace ptr {
24+
/// Memory operation validity.
25+
enum class MemOpValidity : uint8_t {
26+
Valid = 0, /// The operation is valid.
27+
InvalidType =
28+
1, /// The type is not compatible with the operation and memory space.
29+
InvalidAtomicOrdering = 2, /// The atomic ordering is incompatible with the
30+
/// operation and memory space.
31+
InvalidAlignment = 4, /// The provided alignment is invalid.
32+
};
33+
34+
inline MemOpValidity operator&(MemOpValidity lhs, MemOpValidity rhs) {
35+
return static_cast<MemOpValidity>(static_cast<uint8_t>(lhs) &
36+
static_cast<uint8_t>(rhs));
37+
}
38+
inline MemOpValidity operator|(MemOpValidity lhs, MemOpValidity rhs) {
39+
return static_cast<MemOpValidity>(static_cast<uint8_t>(lhs) |
40+
static_cast<uint8_t>(rhs));
41+
}
42+
43+
/// Checks if a specific cast validity flag is set.
44+
inline bool isMemValidityFlagSet(MemOpValidity value, MemOpValidity flag) {
45+
return (value & flag) == flag;
46+
}
47+
48+
/// Ptr cast operations validity.
49+
enum class CastValidity : uint8_t {
50+
Valid = 0, /// Valid cast operation.
51+
InvalidSourceType = 1, /// Invalid source type.
52+
InvalidTargetType = 2, /// Invalid target type.
53+
InvalidVectorRank = 4, /// One of the operands has an invalid vector rank.
54+
InvalidScalableVector = 8, /// One of the operands is a scalable vector.
55+
IncompatibleShapes = 16, /// The types have incompatible shapes.
56+
};
57+
58+
inline CastValidity operator&(CastValidity lhs, CastValidity rhs) {
59+
return static_cast<CastValidity>(static_cast<uint8_t>(lhs) &
60+
static_cast<uint8_t>(rhs));
61+
}
62+
inline CastValidity operator|(CastValidity lhs, CastValidity rhs) {
63+
return static_cast<CastValidity>(static_cast<uint8_t>(lhs) |
64+
static_cast<uint8_t>(rhs));
65+
}
66+
67+
/// Checks if a specific cast validity flag is set.
68+
inline bool isCastFlagSet(CastValidity value, CastValidity flag) {
69+
return (value & flag) == flag;
70+
}
71+
72+
/// This method checks if it's valid to perform an `addrspacecast` op in the
73+
/// memory space.
74+
/// Compatible types are:
75+
/// Vectors of rank 1, or scalars of `ptr` type.
76+
CastValidity isValidAddrSpaceCastImpl(Type tgt, Type src);
77+
78+
/// This method checks if it's valid to perform a `ptrtoint` or `inttoptr` op in
79+
/// the memory space. `CastValidity::InvalidSourceType` always refers to the
80+
/// 'ptr-like' type and `CastValidity::InvalidTargetType` always refers to the
81+
/// `int-like` type.
82+
/// Compatible types are:
83+
/// IntLikeTy: Vectors of rank 1, or scalars of integer types or `index` type.
84+
/// PtrLikeTy: Vectors of rank 1, or scalars of `ptr` type.
85+
CastValidity isValidPtrIntCastImpl(Type intLikeTy, Type ptrLikeTy);
86+
87+
enum class AtomicBinOp : uint64_t;
88+
enum class AtomicOrdering : uint64_t;
89+
} // namespace ptr
90+
} // namespace mlir
91+
92+
#include "mlir/Dialect/Ptr/IR/MemorySpaceAttrInterfaces.h.inc"
93+
94+
namespace mlir {
95+
namespace ptr {
96+
/// This class wraps the `MemorySpaceAttrInterface` interface, providing a safe
97+
/// mechanism to specify the default behavior assumed by the ptr dialect.
98+
class MemoryModel {
99+
public:
100+
MemoryModel() = default;
101+
MemoryModel(std::nullptr_t) {}
102+
MemoryModel(MemorySpaceAttrInterface memorySpace)
103+
: memorySpaceAttr(memorySpace), memorySpace(memorySpace) {}
104+
MemoryModel(Attribute memorySpace)
105+
: memorySpaceAttr(memorySpace),
106+
memorySpace(dyn_cast_or_null<MemorySpaceAttrInterface>(memorySpace)) {}
107+
108+
operator Attribute() const { return memorySpaceAttr; }
109+
operator MemorySpaceAttrInterface() const { return memorySpace; }
110+
bool operator==(const MemoryModel &memSpace) const {
111+
return memSpace.memorySpaceAttr == memorySpaceAttr;
112+
}
113+
114+
/// Returns the underlying memory space.
115+
Attribute getUnderlyingSpace() const { return memorySpaceAttr; }
116+
117+
/// Returns true if the underlying memory space is null.
118+
bool isDefaultModel() const { return memorySpace == nullptr; }
119+
120+
/// Returns the memory space as an integer, or 0 if using the default model.
121+
unsigned getAddressSpace() const {
122+
if (memorySpace)
123+
return memorySpace.getAddressSpace();
124+
if (auto intAttr = llvm::dyn_cast_or_null<IntegerAttr>(memorySpaceAttr))
125+
return intAttr.getInt();
126+
return 0;
127+
}
128+
129+
/// Returns the default memory space as an attribute, or nullptr if using the
130+
/// default model.
131+
Attribute getDefaultMemorySpace() const {
132+
return memorySpace ? memorySpace.getDefaultMemorySpace() : nullptr;
133+
}
134+
135+
/// This method checks if it's valid to load a value from the memory space
136+
/// with a specific type, alignment, and atomic ordering. The default model
137+
/// assumes all values are loadable.
138+
MemOpValidity isValidLoad(Type type, AtomicOrdering ordering,
139+
IntegerAttr alignment) const {
140+
return memorySpace ? memorySpace.isValidLoad(type, ordering, alignment)
141+
: MemOpValidity::Valid;
142+
}
143+
144+
/// This method checks if it's valid to store a value in the memory space with
145+
/// a specific type, alignment, and atomic ordering. The default model assumes
146+
/// all values are loadable.
147+
MemOpValidity isValidStore(Type type, AtomicOrdering ordering,
148+
IntegerAttr alignment) const {
149+
return memorySpace ? memorySpace.isValidStore(type, ordering, alignment)
150+
: MemOpValidity::Valid;
151+
}
152+
153+
/// This method checks if it's valid to perform an atomic operation in the
154+
/// memory space with a specific type, alignment, and atomic ordering.
155+
MemOpValidity isValidAtomicOp(AtomicBinOp op, Type type,
156+
AtomicOrdering ordering,
157+
IntegerAttr alignment) const {
158+
return memorySpace
159+
? memorySpace.isValidAtomicOp(op, type, ordering, alignment)
160+
: MemOpValidity::Valid;
161+
}
162+
163+
/// This method checks if it's valid to perform an atomic operation in the
164+
/// memory space with a specific type, alignment, and atomic ordering.
165+
MemOpValidity isValidAtomicXchg(Type type, AtomicOrdering successOrdering,
166+
AtomicOrdering failureOrdering,
167+
IntegerAttr alignment) const {
168+
return memorySpace ? memorySpace.isValidAtomicXchg(
169+
type, successOrdering, failureOrdering, alignment)
170+
: MemOpValidity::Valid;
171+
}
172+
173+
/// This method checks if it's valid to perform an `addrspacecast` op in the
174+
/// memory space.
175+
CastValidity isValidAddrSpaceCast(Type tgt, Type src) const {
176+
return memorySpace ? memorySpace.isValidAddrSpaceCast(tgt, src)
177+
: isValidAddrSpaceCastImpl(tgt, src);
178+
}
179+
180+
/// This method checks if it's valid to perform a `ptrtoint` or `inttoptr` op
181+
/// in the memory space. `CastValidity::InvalidSourceType` always refers to
182+
/// the 'ptr-like' type and `CastValidity::InvalidTargetType` always refers to
183+
/// the `int-like` type.
184+
CastValidity isValidPtrIntCast(Type intLikeTy, Type ptrLikeTy) const {
185+
return memorySpace ? memorySpace.isValidPtrIntCast(intLikeTy, ptrLikeTy)
186+
: isValidPtrIntCastImpl(intLikeTy, ptrLikeTy);
187+
}
188+
189+
protected:
190+
/// Underlying memory space.
191+
Attribute memorySpaceAttr{};
192+
/// Memory space.
193+
MemorySpaceAttrInterface memorySpace{};
194+
};
195+
} // namespace ptr
196+
} // namespace mlir
197+
198+
#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h.inc"
199+
200+
#endif // MLIR_DIALECT_PTR_IR_MEMORYMODEL_H
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
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, giving proper
27+
semantical meaning to the ops.
28+
29+
Furthermore, this interface allows concepts such as read-only memory to be
30+
adequately modeled and enforced.
31+
}];
32+
let cppNamespace = "::mlir::ptr";
33+
let methods = [
34+
InterfaceMethod<
35+
/*desc=*/ [{
36+
Returns the default memory space as an attribute.
37+
}],
38+
/*returnType=*/ "Attribute",
39+
/*methodName=*/ "getDefaultMemorySpace",
40+
/*args=*/ (ins),
41+
/*methodBody=*/ [{}],
42+
/*defaultImpl=*/ [{}]
43+
>,
44+
InterfaceMethod<
45+
/*desc=*/ [{
46+
Returns the memory space as an integer, or 0 if using the default model.
47+
}],
48+
/*returnType=*/ "unsigned",
49+
/*methodName=*/ "getAddressSpace",
50+
/*args=*/ (ins),
51+
/*methodBody=*/ [{}],
52+
/*defaultImpl=*/ [{ return 0; }]
53+
>,
54+
InterfaceMethod<
55+
/*desc=*/ [{
56+
This method checks if it's valid to load a value from the memory space
57+
with a specific type, alignment, and atomic ordering.
58+
}],
59+
/*returnType=*/ "MemOpValidity",
60+
/*methodName=*/ "isValidLoad",
61+
/*args=*/ (ins "Type":$type,
62+
"AtomicOrdering":$ordering,
63+
"IntegerAttr":$alignment),
64+
/*methodBody=*/ [{}],
65+
/*defaultImpl=*/ [{ return MemOpValidity::Valid; }]
66+
>,
67+
InterfaceMethod<
68+
/*desc=*/ [{
69+
This method checks if it's valid to store a value in the memory space
70+
with a specific type, alignment, and atomic ordering.
71+
}],
72+
/*returnType=*/ "MemOpValidity",
73+
/*methodName=*/ "isValidStore",
74+
/*args=*/ (ins "Type":$type,
75+
"AtomicOrdering":$ordering,
76+
"IntegerAttr":$alignment),
77+
/*methodBody=*/ [{}],
78+
/*defaultImpl=*/ [{ return MemOpValidity::Valid; }]
79+
>,
80+
InterfaceMethod<
81+
/*desc=*/ [{
82+
This method checks if it's valid to perform an atomic operation in the
83+
memory space with a specific type, alignment, and atomic ordering.
84+
}],
85+
/*returnType=*/ "MemOpValidity",
86+
/*methodName=*/ "isValidAtomicOp",
87+
/*args=*/ (ins "AtomicBinOp":$op,
88+
"Type":$type,
89+
"AtomicOrdering":$ordering,
90+
"IntegerAttr":$alignment),
91+
/*methodBody=*/ [{}],
92+
/*defaultImpl=*/ [{ return MemOpValidity::Valid; }]
93+
>,
94+
InterfaceMethod<
95+
/*desc=*/ [{
96+
This method checks if it's valid to perform an atomic exchange operation
97+
in the memory space with a specific type, alignment, and atomic
98+
orderings.
99+
}],
100+
/*returnType=*/ "MemOpValidity",
101+
/*methodName=*/ "isValidAtomicXchg",
102+
/*args=*/ (ins "Type":$type,
103+
"AtomicOrdering":$successOrdering,
104+
"AtomicOrdering":$failureOrdering,
105+
"IntegerAttr":$alignment),
106+
/*methodBody=*/ [{}],
107+
/*defaultImpl=*/ [{ return MemOpValidity::Valid; }]
108+
>,
109+
InterfaceMethod<
110+
/*desc=*/ [{
111+
This method checks if it's valid to perform an `addrspacecast` op
112+
in the memory space.
113+
Both types are expected to be vectors of rank 1, or scalars of `ptr`
114+
type.
115+
}],
116+
/*returnType=*/ "CastValidity",
117+
/*methodName=*/ "isValidAddrSpaceCast",
118+
/*args=*/ (ins "Type":$tgt, "Type":$src),
119+
/*methodBody=*/ [{}],
120+
/*defaultImpl=*/ [{ return isValidAddrSpaceCastImpl(tgt, src); }]
121+
>,
122+
InterfaceMethod<
123+
/*desc=*/ [{
124+
This method checks if it's valid to perform a `ptrtoint` or `inttoptr`
125+
op in the memory space. `CastValidity::InvalidSourceType` always refers
126+
to the 'ptr-like' type and `CastValidity::InvalidTargetType` always
127+
refers to the `int-like` type.
128+
The first type is expected to be integer-like, while the second must be a
129+
ptr-like type.
130+
}],
131+
/*returnType=*/ "CastValidity",
132+
/*methodName=*/ "isValidPtrIntCast",
133+
/*args=*/ (ins "Type":$intLikeTy, "Type":$ptrLikeTy),
134+
/*methodBody=*/ [{}],
135+
/*defaultImpl=*/ [{ return isValidPtrIntCastImpl(intLikeTy, ptrLikeTy); }]
136+
>,
137+
];
138+
}
139+
140+
def MemoryModelOpInterface : OpInterface<"MemoryModelOpInterface"> {
141+
let description = [{
142+
An interface for operations with a memory model.
143+
}];
144+
145+
let cppNamespace = "::mlir::ptr";
146+
147+
let methods = [
148+
InterfaceMethod<
149+
/*desc=*/ "Returns the memory model of the op.",
150+
/*returnType=*/ "MemoryModel",
151+
/*methodName=*/ "getMemoryModel",
152+
/*args=*/ (ins),
153+
/*methodBody=*/ [{}],
154+
/*defaultImpl=*/ [{}]
155+
>,
156+
];
157+
}
158+
#endif // PTR_MEMORYSPACEINTERFACES

0 commit comments

Comments
 (0)