Skip to content

Commit dfdc4b1

Browse files
committed
[mlir][LLVM][NFC] Move LLVMStructType to ODS
This PR extracts NFC changes out of llvm#116035 to reap as many of the same benefits without any of the semantic changes. More concretely, moving `LLVMStructType` to ODS has the benefits of being able to generate much of the required boilerplate, such as interface definitions, documentation and more, automatically. Furthermore, `LLVMStructType` is then treated less special and its definition can be found at the same place where all other complex type definitions are found in the LLVM dialect. Future changes could leverage more automatically generated code from TableGen such as `assemblyFormat`. As these are not as trivial, they have been left for future PRs.
1 parent c4d656a commit dfdc4b1

File tree

7 files changed

+142
-145
lines changed

7 files changed

+142
-145
lines changed

mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.h

Lines changed: 0 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -73,145 +73,6 @@ DEFINE_TRIVIAL_LLVM_TYPE(LLVMMetadataType, "llvm.metadata");
7373

7474
#undef DEFINE_TRIVIAL_LLVM_TYPE
7575

76-
//===----------------------------------------------------------------------===//
77-
// LLVMStructType.
78-
//===----------------------------------------------------------------------===//
79-
80-
/// LLVM dialect structure type representing a collection of different-typed
81-
/// elements manipulated together. Structured can optionally be packed, meaning
82-
/// that their elements immediately follow each other in memory without
83-
/// accounting for potential alignment.
84-
///
85-
/// Structure types can be identified (named) or literal. Literal structures
86-
/// are uniquely represented by the list of types they contain and packedness.
87-
/// Literal structure types are immutable after construction.
88-
///
89-
/// Identified structures are uniquely represented by their name, a string. They
90-
/// have a mutable component, consisting of the list of types they contain,
91-
/// the packedness and the opacity bits. Identified structs can be created
92-
/// without providing the lists of element types, making them suitable to
93-
/// represent recursive, i.e. self-referring, structures. Identified structs
94-
/// without body are considered opaque. For such structs, one can set the body.
95-
/// Identified structs can be created as intentionally-opaque, implying that the
96-
/// caller does not intend to ever set the body (e.g. forward-declarations of
97-
/// structs from another module) and wants to disallow further modification of
98-
/// the body. For intentionally-opaque structs or non-opaque structs with the
99-
/// body, one is not allowed to set another body (however, one can set exactly
100-
/// the same body).
101-
///
102-
/// Note that the packedness of the struct takes place in uniquing of literal
103-
/// structs, but does not in uniquing of identified structs.
104-
class LLVMStructType
105-
: public Type::TypeBase<LLVMStructType, Type, detail::LLVMStructTypeStorage,
106-
DataLayoutTypeInterface::Trait,
107-
DestructurableTypeInterface::Trait,
108-
TypeTrait::IsMutable> {
109-
public:
110-
/// Inherit base constructors.
111-
using Base::Base;
112-
113-
static constexpr StringLiteral name = "llvm.struct";
114-
115-
/// Checks if the given type can be contained in a structure type.
116-
static bool isValidElementType(Type type);
117-
118-
/// Gets or creates an identified struct with the given name in the provided
119-
/// context. Note that unlike llvm::StructType::create, this function will
120-
/// _NOT_ rename a struct in case a struct with the same name already exists
121-
/// in the context. Instead, it will just return the existing struct,
122-
/// similarly to the rest of MLIR type ::get methods.
123-
static LLVMStructType getIdentified(MLIRContext *context, StringRef name);
124-
static LLVMStructType
125-
getIdentifiedChecked(function_ref<InFlightDiagnostic()> emitError,
126-
MLIRContext *context, StringRef name);
127-
128-
/// Gets a new identified struct with the given body. The body _cannot_ be
129-
/// changed later. If a struct with the given name already exists, renames
130-
/// the struct by appending a `.` followed by a number to the name. Renaming
131-
/// happens even if the existing struct has the same body.
132-
static LLVMStructType getNewIdentified(MLIRContext *context, StringRef name,
133-
ArrayRef<Type> elements,
134-
bool isPacked = false);
135-
136-
/// Gets or creates a literal struct with the given body in the provided
137-
/// context.
138-
static LLVMStructType getLiteral(MLIRContext *context, ArrayRef<Type> types,
139-
bool isPacked = false);
140-
static LLVMStructType
141-
getLiteralChecked(function_ref<InFlightDiagnostic()> emitError,
142-
MLIRContext *context, ArrayRef<Type> types,
143-
bool isPacked = false);
144-
145-
/// Gets or creates an intentionally-opaque identified struct. Such a struct
146-
/// cannot have its body set. To create an opaque struct with a mutable body,
147-
/// use `getIdentified`. Note that unlike llvm::StructType::create, this
148-
/// function will _NOT_ rename a struct in case a struct with the same name
149-
/// already exists in the context. Instead, it will just return the existing
150-
/// struct, similarly to the rest of MLIR type ::get methods.
151-
static LLVMStructType getOpaque(StringRef name, MLIRContext *context);
152-
static LLVMStructType
153-
getOpaqueChecked(function_ref<InFlightDiagnostic()> emitError,
154-
MLIRContext *context, StringRef name);
155-
156-
/// Set the body of an identified struct. Returns failure if the body could
157-
/// not be set, e.g. if the struct already has a body or if it was marked as
158-
/// intentionally opaque. This might happen in a multi-threaded context when a
159-
/// different thread modified the struct after it was created. Most callers
160-
/// are likely to assert this always succeeds, but it is possible to implement
161-
/// a local renaming scheme based on the result of this call.
162-
LogicalResult setBody(ArrayRef<Type> types, bool isPacked);
163-
164-
/// Checks if a struct is packed.
165-
bool isPacked() const;
166-
167-
/// Checks if a struct is identified.
168-
bool isIdentified() const;
169-
170-
/// Checks if a struct is opaque.
171-
bool isOpaque();
172-
173-
/// Checks if a struct is initialized.
174-
bool isInitialized();
175-
176-
/// Returns the name of an identified struct.
177-
StringRef getName();
178-
179-
/// Returns the list of element types contained in a non-opaque struct.
180-
ArrayRef<Type> getBody() const;
181-
182-
/// Verifies that the type about to be constructed is well-formed.
183-
static LogicalResult
184-
verifyInvariants(function_ref<InFlightDiagnostic()> emitError, StringRef,
185-
bool);
186-
static LogicalResult
187-
verifyInvariants(function_ref<InFlightDiagnostic()> emitError,
188-
ArrayRef<Type> types, bool);
189-
using Base::verifyInvariants;
190-
191-
/// Hooks for DataLayoutTypeInterface. Should not be called directly. Obtain a
192-
/// DataLayout instance and query it instead.
193-
llvm::TypeSize getTypeSizeInBits(const DataLayout &dataLayout,
194-
DataLayoutEntryListRef params) const;
195-
196-
uint64_t getABIAlignment(const DataLayout &dataLayout,
197-
DataLayoutEntryListRef params) const;
198-
199-
uint64_t getPreferredAlignment(const DataLayout &dataLayout,
200-
DataLayoutEntryListRef params) const;
201-
202-
bool areCompatible(DataLayoutEntryListRef oldLayout,
203-
DataLayoutEntryListRef newLayout) const;
204-
205-
LogicalResult verifyEntries(DataLayoutEntryListRef entries,
206-
Location loc) const;
207-
208-
/// Destructs the struct into its indexed field types.
209-
std::optional<DenseMap<Attribute, Type>> getSubelementIndexMap();
210-
211-
/// Returns which type is stored at a given integer index within the struct.
212-
Type getTypeAtIndex(Attribute index);
213-
};
214-
21576
//===----------------------------------------------------------------------===//
21677
// Printing and parsing.
21778
//===----------------------------------------------------------------------===//

mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,140 @@ def LLVMFunctionType : LLVMType<"LLVMFunction", "func"> {
117117
}];
118118
}
119119

120+
//===----------------------------------------------------------------------===//
121+
// LLVMStructType
122+
//===----------------------------------------------------------------------===//
123+
124+
def LLVMStructType : LLVMType<"LLVMStruct", "struct", [
125+
MutableType,
126+
DeclareTypeInterfaceMethods<DataLayoutTypeInterface,
127+
["areCompatible", "verifyEntries"]>,
128+
DeclareTypeInterfaceMethods<DestructurableTypeInterface,
129+
["getSubelementIndexMap", "getTypeAtIndex"]>
130+
]> {
131+
let summary = "LLVM struct type";
132+
133+
let description = [{
134+
LLVM dialect structure type representing a collection of different-typed
135+
elements manipulated together. Structured can optionally be packed, meaning
136+
that their elements immediately follow each other in memory without
137+
accounting for potential alignment.
138+
139+
Structure types can be identified (named) or literal. Literal structures
140+
are uniquely represented by the list of types they contain and packedness.
141+
Literal structure types are immutable after construction.
142+
143+
Identified structures are uniquely represented by their name, a string. They
144+
have a mutable component, consisting of the list of types they contain,
145+
the packedness and the opacity bits. Identified structs can be created
146+
without providing the lists of element types, making them suitable to
147+
represent recursive, i.e. self-referring, structures. Identified structs
148+
without body are considered opaque. For such structs, one can set the body.
149+
Identified structs can be created as intentionally-opaque, implying that the
150+
caller does not intend to ever set the body (e.g. forward-declarations of
151+
structs from another module) and wants to disallow further modification of
152+
the body. For intentionally-opaque structs or non-opaque structs with the
153+
body, one is not allowed to set another body (however, one can set exactly
154+
the same body).
155+
156+
Note that the packedness of the struct takes place in uniquing of literal
157+
structs, but does not in uniquing of identified structs.
158+
}];
159+
160+
// Specify parameters for which TableGen can generate convenient getters for
161+
// us.
162+
// TODO: Other parameters such as 'packed' or 'opaque' could be added in the
163+
// future iff they generate getters prefixed with 'is', instead of
164+
// 'get'. Until then there are no advantages in doing so.
165+
let parameters = (ins
166+
StringRefParameter<"struct name", [{""}]>:$name,
167+
OptionalArrayRefParameter<"mlir::Type">:$body
168+
);
169+
170+
// A custom storage class defined in C++ is required to implement mutability.
171+
let storageClass = "LLVMStructTypeStorage";
172+
let genStorageClass = 0;
173+
174+
// We want users to use the more aptly named custom builders below.
175+
let skipDefaultBuilders = 1;
176+
177+
let extraClassDeclaration = [{
178+
/// Checks if the given type can be contained in a structure type.
179+
static bool isValidElementType(Type type);
180+
181+
/// Gets or creates an identified struct with the given name in the provided
182+
/// context. Note that unlike llvm::StructType::create, this function will
183+
/// _NOT_ rename a struct in case a struct with the same name already exists
184+
/// in the context. Instead, it will just return the existing struct,
185+
/// similarly to the rest of MLIR type ::get methods.
186+
static LLVMStructType getIdentified(MLIRContext *context, StringRef name);
187+
static LLVMStructType
188+
getIdentifiedChecked(function_ref<InFlightDiagnostic()> emitError,
189+
MLIRContext *context, StringRef name);
190+
191+
/// Gets a new identified struct with the given body. The body _cannot_ be
192+
/// changed later. If a struct with the given name already exists, renames
193+
/// the struct by appending a `.` followed by a number to the name. Renaming
194+
/// happens even if the existing struct has the same body.
195+
static LLVMStructType getNewIdentified(MLIRContext *context, StringRef name,
196+
ArrayRef<Type> elements,
197+
bool isPacked = false);
198+
199+
/// Gets or creates a literal struct with the given body in the provided
200+
/// context.
201+
static LLVMStructType getLiteral(MLIRContext *context, ArrayRef<Type> types,
202+
bool isPacked = false);
203+
204+
static LLVMStructType
205+
getLiteralChecked(function_ref<InFlightDiagnostic()> emitError,
206+
MLIRContext *context, ArrayRef<Type> types,
207+
bool isPacked = false);
208+
209+
/// Gets or creates an intentionally-opaque identified struct. Such a struct
210+
/// cannot have its body set.
211+
/// Note that unlike llvm::StructType::create, this function will _NOT_
212+
/// rename a struct in case a struct with the same name
213+
/// already exists in the context. Instead, it will just return the existing
214+
/// struct, similarly to the rest of MLIR type ::get methods.
215+
static LLVMStructType getOpaque(StringRef name, MLIRContext *context);
216+
217+
static LLVMStructType
218+
getOpaqueChecked(function_ref<InFlightDiagnostic()> emitError,
219+
MLIRContext *context, StringRef name);
220+
221+
/// Set the body of an identified struct. Returns failure if the body could
222+
/// not be set, e.g. if the struct already has a body or if it was marked as
223+
/// intentionally opaque. This might happen in a multi-threaded context when a
224+
/// different thread modified the struct after it was created. Most callers
225+
/// are likely to assert this always succeeds, but it is possible to implement
226+
/// a local renaming scheme based on the result of this call.
227+
LogicalResult setBody(ArrayRef<Type> types, bool isPacked);
228+
229+
/// Checks if a struct is packed.
230+
bool isPacked() const;
231+
232+
/// Checks if a struct is identified.
233+
bool isIdentified() const;
234+
235+
/// Checks if a struct is opaque.
236+
bool isOpaque();
237+
238+
/// Checks if a struct is initialized.
239+
bool isInitialized();
240+
241+
/// Verifies that the type about to be constructed is well-formed.
242+
static LogicalResult
243+
verifyInvariants(function_ref<InFlightDiagnostic()> emitError, StringRef,
244+
bool);
245+
static LogicalResult
246+
verifyInvariants(function_ref<InFlightDiagnostic()> emitError,
247+
ArrayRef<Type> types, bool);
248+
using Base::verifyInvariants;
249+
}];
250+
251+
let hasCustomAssemblyFormat = 1;
252+
}
253+
120254
//===----------------------------------------------------------------------===//
121255
// LLVMPointerType
122256
//===----------------------------------------------------------------------===//

mlir/include/mlir/IR/AttrTypeBase.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ class ParamNativeTypeTrait<string prop, string params>
5656
class GenInternalTypeTrait<string prop> : GenInternalTrait<prop, "Type">;
5757
class PredTypeTrait<string descr, Pred pred> : PredTrait<descr, pred>;
5858

59+
// Trait required to be added to any type which is mutable.
60+
def MutableType : NativeTypeTrait<"IsMutable">;
61+
5962
//===----------------------------------------------------------------------===//
6063
// Builders
6164
//===----------------------------------------------------------------------===//

mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3510,8 +3510,7 @@ void LLVMDialect::initialize() {
35103510
LLVMPPCFP128Type,
35113511
LLVMTokenType,
35123512
LLVMLabelType,
3513-
LLVMMetadataType,
3514-
LLVMStructType>();
3513+
LLVMMetadataType>();
35153514
// clang-format on
35163515
registerTypes();
35173516

mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,15 +1566,15 @@ DeletionKind LLVM::MemmoveOp::rewire(const DestructurableMemorySlot &slot,
15661566
//===----------------------------------------------------------------------===//
15671567

15681568
std::optional<DenseMap<Attribute, Type>>
1569-
LLVM::LLVMStructType::getSubelementIndexMap() {
1569+
LLVM::LLVMStructType::getSubelementIndexMap() const {
15701570
Type i32 = IntegerType::get(getContext(), 32);
15711571
DenseMap<Attribute, Type> destructured;
15721572
for (const auto &[index, elemType] : llvm::enumerate(getBody()))
15731573
destructured.insert({IntegerAttr::get(i32, index), elemType});
15741574
return destructured;
15751575
}
15761576

1577-
Type LLVM::LLVMStructType::getTypeAtIndex(Attribute index) {
1577+
Type LLVM::LLVMStructType::getTypeAtIndex(Attribute index) const {
15781578
auto indexAttr = llvm::dyn_cast<IntegerAttr>(index);
15791579
if (!indexAttr || !indexAttr.getType().isInteger(32))
15801580
return {};

mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ bool LLVMStructType::isOpaque() {
485485
(getImpl()->isOpaque() || !getImpl()->isInitialized());
486486
}
487487
bool LLVMStructType::isInitialized() { return getImpl()->isInitialized(); }
488-
StringRef LLVMStructType::getName() { return getImpl()->getIdentifier(); }
488+
StringRef LLVMStructType::getName() const { return getImpl()->getIdentifier(); }
489489
ArrayRef<Type> LLVMStructType::getBody() const {
490490
return isIdentified() ? getImpl()->getIdentifiedStructBody()
491491
: getImpl()->getTypeList();

mlir/test/lib/Dialect/Test/TestTypeDefs.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ def TestI32 : Test_Type<"TestI32"> {
375375
}
376376

377377
def TestRecursiveAlias
378-
: Test_Type<"TestRecursiveAlias", [NativeTypeTrait<"IsMutable">]> {
378+
: Test_Type<"TestRecursiveAlias", [MutableType]> {
379379
let mnemonic = "test_rec_alias";
380380
let storageClass = "TestRecursiveTypeStorage";
381381
let storageNamespace = "test";

0 commit comments

Comments
 (0)