1 | //===- LLVMTypes.h - MLIR LLVM dialect types --------------------*- 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 types for the LLVM dialect in MLIR. These MLIR types |
10 | // correspond to the LLVM IR type system. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef MLIR_DIALECT_LLVMIR_LLVMTYPES_H_ |
15 | #define MLIR_DIALECT_LLVMIR_LLVMTYPES_H_ |
16 | |
17 | #include "mlir/IR/Types.h" |
18 | #include "mlir/Interfaces/DataLayoutInterfaces.h" |
19 | #include "mlir/Interfaces/MemorySlotInterfaces.h" |
20 | #include <optional> |
21 | |
22 | namespace llvm { |
23 | class ElementCount; |
24 | class TypeSize; |
25 | } // namespace llvm |
26 | |
27 | namespace mlir { |
28 | |
29 | class AsmParser; |
30 | class AsmPrinter; |
31 | |
32 | namespace LLVM { |
33 | class LLVMDialect; |
34 | |
35 | namespace detail { |
36 | struct LLVMFunctionTypeStorage; |
37 | struct LLVMPointerTypeStorage; |
38 | struct LLVMStructTypeStorage; |
39 | struct LLVMTypeAndSizeStorage; |
40 | } // namespace detail |
41 | } // namespace LLVM |
42 | } // namespace mlir |
43 | |
44 | //===----------------------------------------------------------------------===// |
45 | // ODS-Generated Declarations |
46 | //===----------------------------------------------------------------------===// |
47 | |
48 | #include "mlir/Dialect/LLVMIR/LLVMTypeInterfaces.h.inc" |
49 | |
50 | #define GET_TYPEDEF_CLASSES |
51 | #include "mlir/Dialect/LLVMIR/LLVMTypes.h.inc" |
52 | |
53 | namespace mlir { |
54 | namespace LLVM { |
55 | |
56 | //===----------------------------------------------------------------------===// |
57 | // Trivial types. |
58 | //===----------------------------------------------------------------------===// |
59 | |
60 | // Batch-define trivial types. |
61 | #define DEFINE_TRIVIAL_LLVM_TYPE(ClassName, TypeName) \ |
62 | class ClassName : public Type::TypeBase<ClassName, Type, TypeStorage> { \ |
63 | public: \ |
64 | using Base::Base; \ |
65 | static constexpr StringLiteral name = TypeName; \ |
66 | } |
67 | |
68 | DEFINE_TRIVIAL_LLVM_TYPE(LLVMVoidType, "llvm.void" ); |
69 | DEFINE_TRIVIAL_LLVM_TYPE(LLVMPPCFP128Type, "llvm.ppc_fp128" ); |
70 | DEFINE_TRIVIAL_LLVM_TYPE(LLVMX86MMXType, "llvm.x86_mmx" ); |
71 | DEFINE_TRIVIAL_LLVM_TYPE(LLVMTokenType, "llvm.token" ); |
72 | DEFINE_TRIVIAL_LLVM_TYPE(LLVMLabelType, "llvm.label" ); |
73 | DEFINE_TRIVIAL_LLVM_TYPE(LLVMMetadataType, "llvm.metadata" ); |
74 | |
75 | #undef DEFINE_TRIVIAL_LLVM_TYPE |
76 | |
77 | //===----------------------------------------------------------------------===// |
78 | // LLVMStructType. |
79 | //===----------------------------------------------------------------------===// |
80 | |
81 | /// LLVM dialect structure type representing a collection of different-typed |
82 | /// elements manipulated together. Structured can optionally be packed, meaning |
83 | /// that their elements immediately follow each other in memory without |
84 | /// accounting for potential alignment. |
85 | /// |
86 | /// Structure types can be identified (named) or literal. Literal structures |
87 | /// are uniquely represented by the list of types they contain and packedness. |
88 | /// Literal structure types are immutable after construction. |
89 | /// |
90 | /// Identified structures are uniquely represented by their name, a string. They |
91 | /// have a mutable component, consisting of the list of types they contain, |
92 | /// the packedness and the opacity bits. Identified structs can be created |
93 | /// without providing the lists of element types, making them suitable to |
94 | /// represent recursive, i.e. self-referring, structures. Identified structs |
95 | /// without body are considered opaque. For such structs, one can set the body. |
96 | /// Identified structs can be created as intentionally-opaque, implying that the |
97 | /// caller does not intend to ever set the body (e.g. forward-declarations of |
98 | /// structs from another module) and wants to disallow further modification of |
99 | /// the body. For intentionally-opaque structs or non-opaque structs with the |
100 | /// body, one is not allowed to set another body (however, one can set exactly |
101 | /// the same body). |
102 | /// |
103 | /// Note that the packedness of the struct takes place in uniquing of literal |
104 | /// structs, but does not in uniquing of identified structs. |
105 | class LLVMStructType |
106 | : public Type::TypeBase<LLVMStructType, Type, detail::LLVMStructTypeStorage, |
107 | DataLayoutTypeInterface::Trait, |
108 | DestructurableTypeInterface::Trait, |
109 | TypeTrait::IsMutable> { |
110 | public: |
111 | /// Inherit base constructors. |
112 | using Base::Base; |
113 | |
114 | static constexpr StringLiteral name = "llvm.struct" ; |
115 | |
116 | /// Checks if the given type can be contained in a structure type. |
117 | static bool isValidElementType(Type type); |
118 | |
119 | /// Gets or creates an identified struct with the given name in the provided |
120 | /// context. Note that unlike llvm::StructType::create, this function will |
121 | /// _NOT_ rename a struct in case a struct with the same name already exists |
122 | /// in the context. Instead, it will just return the existing struct, |
123 | /// similarly to the rest of MLIR type ::get methods. |
124 | static LLVMStructType getIdentified(MLIRContext *context, StringRef name); |
125 | static LLVMStructType |
126 | getIdentifiedChecked(function_ref<InFlightDiagnostic()> emitError, |
127 | MLIRContext *context, StringRef name); |
128 | |
129 | /// Gets a new identified struct with the given body. The body _cannot_ be |
130 | /// changed later. If a struct with the given name already exists, renames |
131 | /// the struct by appending a `.` followed by a number to the name. Renaming |
132 | /// happens even if the existing struct has the same body. |
133 | static LLVMStructType getNewIdentified(MLIRContext *context, StringRef name, |
134 | ArrayRef<Type> elements, |
135 | bool isPacked = false); |
136 | |
137 | /// Gets or creates a literal struct with the given body in the provided |
138 | /// context. |
139 | static LLVMStructType getLiteral(MLIRContext *context, ArrayRef<Type> types, |
140 | bool isPacked = false); |
141 | static LLVMStructType |
142 | getLiteralChecked(function_ref<InFlightDiagnostic()> emitError, |
143 | MLIRContext *context, ArrayRef<Type> types, |
144 | bool isPacked = false); |
145 | |
146 | /// Gets or creates an intentionally-opaque identified struct. Such a struct |
147 | /// cannot have its body set. To create an opaque struct with a mutable body, |
148 | /// use `getIdentified`. Note that unlike llvm::StructType::create, this |
149 | /// function will _NOT_ rename a struct in case a struct with the same name |
150 | /// already exists in the context. Instead, it will just return the existing |
151 | /// struct, similarly to the rest of MLIR type ::get methods. |
152 | static LLVMStructType getOpaque(StringRef name, MLIRContext *context); |
153 | static LLVMStructType |
154 | getOpaqueChecked(function_ref<InFlightDiagnostic()> emitError, |
155 | MLIRContext *context, StringRef name); |
156 | |
157 | /// Set the body of an identified struct. Returns failure if the body could |
158 | /// not be set, e.g. if the struct already has a body or if it was marked as |
159 | /// intentionally opaque. This might happen in a multi-threaded context when a |
160 | /// different thread modified the struct after it was created. Most callers |
161 | /// are likely to assert this always succeeds, but it is possible to implement |
162 | /// a local renaming scheme based on the result of this call. |
163 | LogicalResult setBody(ArrayRef<Type> types, bool isPacked); |
164 | |
165 | /// Checks if a struct is packed. |
166 | bool isPacked() const; |
167 | |
168 | /// Checks if a struct is identified. |
169 | bool isIdentified() const; |
170 | |
171 | /// Checks if a struct is opaque. |
172 | bool isOpaque(); |
173 | |
174 | /// Checks if a struct is initialized. |
175 | bool isInitialized(); |
176 | |
177 | /// Returns the name of an identified struct. |
178 | StringRef getName(); |
179 | |
180 | /// Returns the list of element types contained in a non-opaque struct. |
181 | ArrayRef<Type> getBody() const; |
182 | |
183 | /// Verifies that the type about to be constructed is well-formed. |
184 | static LogicalResult verify(function_ref<InFlightDiagnostic()> emitError, |
185 | StringRef, bool); |
186 | static LogicalResult verify(function_ref<InFlightDiagnostic()> emitError, |
187 | ArrayRef<Type> types, bool); |
188 | using Base::verify; |
189 | |
190 | /// Hooks for DataLayoutTypeInterface. Should not be called directly. Obtain a |
191 | /// DataLayout instance and query it instead. |
192 | llvm::TypeSize getTypeSizeInBits(const DataLayout &dataLayout, |
193 | DataLayoutEntryListRef params) const; |
194 | |
195 | uint64_t getABIAlignment(const DataLayout &dataLayout, |
196 | DataLayoutEntryListRef params) const; |
197 | |
198 | uint64_t getPreferredAlignment(const DataLayout &dataLayout, |
199 | DataLayoutEntryListRef params) const; |
200 | |
201 | bool areCompatible(DataLayoutEntryListRef oldLayout, |
202 | DataLayoutEntryListRef newLayout) const; |
203 | |
204 | LogicalResult verifyEntries(DataLayoutEntryListRef entries, |
205 | Location loc) const; |
206 | |
207 | /// Destructs the struct into its indexed field types. |
208 | std::optional<DenseMap<Attribute, Type>> getSubelementIndexMap(); |
209 | |
210 | /// Returns which type is stored at a given integer index within the struct. |
211 | Type getTypeAtIndex(Attribute index); |
212 | }; |
213 | |
214 | //===----------------------------------------------------------------------===// |
215 | // Printing and parsing. |
216 | //===----------------------------------------------------------------------===// |
217 | |
218 | namespace detail { |
219 | /// Parses an LLVM dialect type. |
220 | Type parseType(DialectAsmParser &parser); |
221 | |
222 | /// Prints an LLVM Dialect type. |
223 | void printType(Type type, AsmPrinter &printer); |
224 | } // namespace detail |
225 | |
226 | /// Parse any MLIR type or a concise syntax for LLVM types. |
227 | ParseResult parsePrettyLLVMType(AsmParser &p, Type &type); |
228 | /// Print any MLIR type or a concise syntax for LLVM types. |
229 | void printPrettyLLVMType(AsmPrinter &p, Type type); |
230 | |
231 | //===----------------------------------------------------------------------===// |
232 | // Utility functions. |
233 | //===----------------------------------------------------------------------===// |
234 | |
235 | /// Returns `true` if the given type is compatible with the LLVM dialect. This |
236 | /// is an alias to `LLVMDialect::isCompatibleType`. |
237 | bool isCompatibleType(Type type); |
238 | |
239 | /// Returns `true` if the given outer type is compatible with the LLVM dialect |
240 | /// without checking its potential nested types such as struct elements. |
241 | bool isCompatibleOuterType(Type type); |
242 | |
243 | /// Returns `true` if the given type is a floating-point type compatible with |
244 | /// the LLVM dialect. |
245 | bool isCompatibleFloatingPointType(Type type); |
246 | |
247 | /// Returns `true` if the given type is a vector type compatible with the LLVM |
248 | /// dialect. Compatible types include 1D built-in vector types of built-in |
249 | /// integers and floating-point values, LLVM dialect fixed vector types of LLVM |
250 | /// dialect pointers and LLVM dialect scalable vector types. |
251 | bool isCompatibleVectorType(Type type); |
252 | |
253 | /// Returns the element type of any vector type compatible with the LLVM |
254 | /// dialect. |
255 | Type getVectorElementType(Type type); |
256 | |
257 | /// Returns the element count of any LLVM-compatible vector type. |
258 | llvm::ElementCount getVectorNumElements(Type type); |
259 | |
260 | /// Returns whether a vector type is scalable or not. |
261 | bool isScalableVectorType(Type vectorType); |
262 | |
263 | /// Creates an LLVM dialect-compatible vector type with the given element type |
264 | /// and length. |
265 | Type getVectorType(Type elementType, unsigned numElements, |
266 | bool isScalable = false); |
267 | |
268 | /// Creates an LLVM dialect-compatible vector type with the given element type |
269 | /// and length. |
270 | Type getVectorType(Type elementType, const llvm::ElementCount &numElements); |
271 | |
272 | /// Creates an LLVM dialect-compatible type with the given element type and |
273 | /// length. |
274 | Type getFixedVectorType(Type elementType, unsigned numElements); |
275 | |
276 | /// Creates an LLVM dialect-compatible type with the given element type and |
277 | /// length. |
278 | Type getScalableVectorType(Type elementType, unsigned numElements); |
279 | |
280 | /// Returns the size of the given primitive LLVM dialect-compatible type |
281 | /// (including vectors) in bits, for example, the size of i16 is 16 and |
282 | /// the size of vector<4xi16> is 64. Returns 0 for non-primitive |
283 | /// (aggregates such as struct) or types that don't have a size (such as void). |
284 | llvm::TypeSize getPrimitiveTypeSizeInBits(Type type); |
285 | |
286 | /// The positions of different values in the data layout entry for pointers. |
287 | enum class PtrDLEntryPos { Size = 0, Abi = 1, Preferred = 2, Index = 3 }; |
288 | |
289 | /// Returns the value that corresponds to named position `pos` from the |
290 | /// data layout entry `attr` assuming it's a dense integer elements attribute. |
291 | /// Returns `std::nullopt` if `pos` is not present in the entry. |
292 | /// Currently only `PtrDLEntryPos::Index` is optional, and all other positions |
293 | /// may be assumed to be present. |
294 | std::optional<uint64_t> (Attribute attr, |
295 | PtrDLEntryPos pos); |
296 | |
297 | } // namespace LLVM |
298 | } // namespace mlir |
299 | |
300 | #endif // MLIR_DIALECT_LLVMIR_LLVMTYPES_H_ |
301 | |