1 | //===- ExtensibleDialect.h - Extensible dialect -----------------*- C++ -*-===// |
2 | // |
3 | // This file is licensed 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 DynamicOpDefinition class, the DynamicTypeDefinition |
10 | // class, and the DynamicAttrDefinition class, which represent respectively |
11 | // operations, types, and attributes that can be defined at runtime. They can |
12 | // be registered at runtime to an extensible dialect, using the |
13 | // ExtensibleDialect class defined in this file. |
14 | // |
15 | // For a more complete documentation, see |
16 | // https://mlir.llvm.org/docs/ExtensibleDialects/ . |
17 | // |
18 | //===----------------------------------------------------------------------===// |
19 | |
20 | #ifndef MLIR_IR_EXTENSIBLEDIALECT_H |
21 | #define MLIR_IR_EXTENSIBLEDIALECT_H |
22 | |
23 | #include "mlir/IR/Dialect.h" |
24 | #include "mlir/IR/DialectInterface.h" |
25 | #include "mlir/IR/MLIRContext.h" |
26 | #include "mlir/IR/OpDefinition.h" |
27 | #include "mlir/IR/OperationSupport.h" |
28 | #include "mlir/Support/TypeID.h" |
29 | #include "llvm/ADT/StringMap.h" |
30 | #include "llvm/Support/ErrorHandling.h" |
31 | #include <optional> |
32 | |
33 | namespace mlir { |
34 | class AsmParser; |
35 | class AsmPrinter; |
36 | class DynamicAttr; |
37 | class DynamicType; |
38 | class ExtensibleDialect; |
39 | class MLIRContext; |
40 | class OptionalParseResult; |
41 | class ParseResult; |
42 | |
43 | namespace detail { |
44 | struct DynamicAttrStorage; |
45 | struct DynamicTypeStorage; |
46 | } // namespace detail |
47 | |
48 | //===----------------------------------------------------------------------===// |
49 | // Dynamic attribute |
50 | //===----------------------------------------------------------------------===// |
51 | |
52 | /// The definition of a dynamic attribute. A dynamic attribute is an attribute |
53 | /// that is defined at runtime, and that can be registered at runtime by an |
54 | /// extensible dialect (a dialect inheriting ExtensibleDialect). This class |
55 | /// stores the parser, the printer, and the verifier of the attribute. Each |
56 | /// dynamic attribute definition refers to one instance of this class. |
57 | class DynamicAttrDefinition : public SelfOwningTypeID { |
58 | public: |
59 | using VerifierFn = llvm::unique_function<LogicalResult( |
60 | function_ref<InFlightDiagnostic()>, ArrayRef<Attribute>) const>; |
61 | using ParserFn = llvm::unique_function<ParseResult( |
62 | AsmParser &parser, llvm::SmallVectorImpl<Attribute> &parsedAttributes) |
63 | const>; |
64 | using PrinterFn = llvm::unique_function<void( |
65 | AsmPrinter &printer, ArrayRef<Attribute> params) const>; |
66 | |
67 | /// Create a new attribute definition at runtime. The attribute is registered |
68 | /// only after passing it to the dialect using registerDynamicAttr. |
69 | static std::unique_ptr<DynamicAttrDefinition> |
70 | get(StringRef name, ExtensibleDialect *dialect, VerifierFn &&verifier); |
71 | static std::unique_ptr<DynamicAttrDefinition> |
72 | get(StringRef name, ExtensibleDialect *dialect, VerifierFn &&verifier, |
73 | ParserFn &&parser, PrinterFn &&printer); |
74 | |
75 | /// Sets the verifier function for this attribute. It should emits an error |
76 | /// message and returns failure if a problem is detected, or returns success |
77 | /// if everything is ok. |
78 | void setVerifyFn(VerifierFn &&verify) { verifier = std::move(verify); } |
79 | |
80 | /// Sets the static hook for parsing this attribute assembly. |
81 | void setParseFn(ParserFn &&parse) { parser = std::move(parse); } |
82 | |
83 | /// Sets the static hook for printing this attribute assembly. |
84 | void setPrintFn(PrinterFn &&print) { printer = std::move(print); } |
85 | |
86 | /// Check that the attribute parameters are valid. |
87 | LogicalResult verify(function_ref<InFlightDiagnostic()> emitError, |
88 | ArrayRef<Attribute> params) const { |
89 | return verifier(emitError, params); |
90 | } |
91 | |
92 | /// Return the MLIRContext in which the dynamic attributes are uniqued. |
93 | MLIRContext &getContext() const { return *ctx; } |
94 | |
95 | /// Return the name of the attribute, in the format 'attrname' and |
96 | /// not 'dialectname.attrname'. |
97 | StringRef getName() const { return name; } |
98 | |
99 | /// Return the dialect defining the attribute. |
100 | ExtensibleDialect *getDialect() const { return dialect; } |
101 | |
102 | private: |
103 | DynamicAttrDefinition(StringRef name, ExtensibleDialect *dialect, |
104 | VerifierFn &&verifier, ParserFn &&parser, |
105 | PrinterFn &&printer); |
106 | |
107 | /// This constructor should only be used when we need a pointer to |
108 | /// the DynamicAttrDefinition in the verifier, the parser, or the printer. |
109 | /// The verifier, parser, and printer need thus to be initialized after the |
110 | /// constructor. |
111 | DynamicAttrDefinition(ExtensibleDialect *dialect, StringRef name); |
112 | |
113 | /// Register the concrete attribute in the attribute Uniquer. |
114 | void registerInAttrUniquer(); |
115 | |
116 | /// The name should be prefixed with the dialect name followed by '.'. |
117 | std::string name; |
118 | |
119 | /// Dialect in which this attribute is defined. |
120 | ExtensibleDialect *dialect; |
121 | |
122 | /// The attribute verifier. It checks that the attribute parameters satisfy |
123 | /// the invariants. |
124 | VerifierFn verifier; |
125 | |
126 | /// The attribute parameters parser. It parses only the parameters, and |
127 | /// expects the attribute name to have already been parsed. |
128 | ParserFn parser; |
129 | |
130 | /// The attribute parameters printer. It prints only the parameters, and |
131 | /// expects the attribute name to have already been printed. |
132 | PrinterFn printer; |
133 | |
134 | /// Context in which the concrete attributes are uniqued. |
135 | MLIRContext *ctx; |
136 | |
137 | friend ExtensibleDialect; |
138 | friend DynamicAttr; |
139 | }; |
140 | |
141 | /// This trait is used to determine if an attribute is a dynamic attribute or |
142 | /// not; it should only be implemented by dynamic attributes. |
143 | /// Note: This is only required because dynamic attributes do not have a |
144 | /// static/single TypeID. |
145 | namespace AttributeTrait { |
146 | template <typename ConcreteType> |
147 | class IsDynamicAttr : public TraitBase<ConcreteType, IsDynamicAttr> {}; |
148 | } // namespace AttributeTrait |
149 | |
150 | /// A dynamic attribute instance. This is an attribute whose definition is |
151 | /// defined at runtime. |
152 | /// It is possible to check if an attribute is a dynamic attribute using |
153 | /// `my_attr.isa<DynamicAttr>()`, and getting the attribute definition of a |
154 | /// dynamic attribute using the `DynamicAttr::getAttrDef` method. |
155 | /// All dynamic attributes have the same storage, which is an array of |
156 | /// attributes. |
157 | |
158 | class DynamicAttr : public Attribute::AttrBase<DynamicAttr, Attribute, |
159 | detail::DynamicAttrStorage, |
160 | AttributeTrait::IsDynamicAttr> { |
161 | public: |
162 | // Inherit Base constructors. |
163 | using Base::Base; |
164 | |
165 | /// Return an instance of a dynamic attribute given a dynamic attribute |
166 | /// definition and attribute parameters. |
167 | /// This asserts that the attribute verifier succeeded. |
168 | static DynamicAttr get(DynamicAttrDefinition *attrDef, |
169 | ArrayRef<Attribute> params = {}); |
170 | |
171 | /// Return an instance of a dynamic attribute given a dynamic attribute |
172 | /// definition and attribute parameters. If the parameters provided are |
173 | /// invalid, errors are emitted using the provided location and a null object |
174 | /// is returned. |
175 | static DynamicAttr getChecked(function_ref<InFlightDiagnostic()> emitError, |
176 | DynamicAttrDefinition *attrDef, |
177 | ArrayRef<Attribute> params = {}); |
178 | |
179 | /// Return the attribute definition of the concrete attribute. |
180 | DynamicAttrDefinition *getAttrDef(); |
181 | |
182 | /// Return the attribute parameters. |
183 | ArrayRef<Attribute> getParams(); |
184 | |
185 | /// Check if an attribute is a specific dynamic attribute. |
186 | static bool isa(Attribute attr, DynamicAttrDefinition *attrDef) { |
187 | return attr.getTypeID() == attrDef->getTypeID(); |
188 | } |
189 | |
190 | /// Check if an attribute is a dynamic attribute. |
191 | static bool classof(Attribute attr); |
192 | |
193 | /// Parse the dynamic attribute parameters and construct the attribute. |
194 | /// The parameters are either empty, and nothing is parsed, |
195 | /// or they are in the format '<>' or '<attr (,attr)*>'. |
196 | static ParseResult parse(AsmParser &parser, DynamicAttrDefinition *attrDef, |
197 | DynamicAttr &parsedAttr); |
198 | |
199 | /// Print the dynamic attribute with the format 'attrname' if there is no |
200 | /// parameters, or 'attrname<attr (,attr)*>'. |
201 | void print(AsmPrinter &printer); |
202 | }; |
203 | |
204 | //===----------------------------------------------------------------------===// |
205 | // Dynamic type |
206 | //===----------------------------------------------------------------------===// |
207 | |
208 | /// The definition of a dynamic type. A dynamic type is a type that is |
209 | /// defined at runtime, and that can be registered at runtime by an |
210 | /// extensible dialect (a dialect inheriting ExtensibleDialect). This class |
211 | /// stores the parser, the printer, and the verifier of the type. Each dynamic |
212 | /// type definition refers to one instance of this class. |
213 | class DynamicTypeDefinition : public SelfOwningTypeID { |
214 | public: |
215 | using VerifierFn = llvm::unique_function<LogicalResult( |
216 | function_ref<InFlightDiagnostic()>, ArrayRef<Attribute>) const>; |
217 | using ParserFn = llvm::unique_function<ParseResult( |
218 | AsmParser &parser, llvm::SmallVectorImpl<Attribute> &parsedAttributes) |
219 | const>; |
220 | using PrinterFn = llvm::unique_function<void( |
221 | AsmPrinter &printer, ArrayRef<Attribute> params) const>; |
222 | |
223 | /// Create a new dynamic type definition. The type is registered only after |
224 | /// passing it to the dialect using registerDynamicType. |
225 | static std::unique_ptr<DynamicTypeDefinition> |
226 | get(StringRef name, ExtensibleDialect *dialect, VerifierFn &&verifier); |
227 | static std::unique_ptr<DynamicTypeDefinition> |
228 | get(StringRef name, ExtensibleDialect *dialect, VerifierFn &&verifier, |
229 | ParserFn &&parser, PrinterFn &&printer); |
230 | |
231 | /// Sets the verifier function for this type. It should emits an error |
232 | /// message and returns failure if a problem is detected, or returns success |
233 | /// if everything is ok. |
234 | void setVerifyFn(VerifierFn &&verify) { verifier = std::move(verify); } |
235 | |
236 | /// Sets the static hook for parsing this type assembly. |
237 | void setParseFn(ParserFn &&parse) { parser = std::move(parse); } |
238 | |
239 | /// Sets the static hook for printing this type assembly. |
240 | void setPrintFn(PrinterFn &&print) { printer = std::move(print); } |
241 | |
242 | /// Check that the type parameters are valid. |
243 | LogicalResult verify(function_ref<InFlightDiagnostic()> emitError, |
244 | ArrayRef<Attribute> params) const { |
245 | return verifier(emitError, params); |
246 | } |
247 | |
248 | /// Return the MLIRContext in which the dynamic types is uniqued. |
249 | MLIRContext &getContext() const { return *ctx; } |
250 | |
251 | /// Return the name of the type, in the format 'typename' and |
252 | /// not 'dialectname.typename'. |
253 | StringRef getName() const { return name; } |
254 | |
255 | /// Return the dialect defining the type. |
256 | ExtensibleDialect *getDialect() const { return dialect; } |
257 | |
258 | private: |
259 | DynamicTypeDefinition(StringRef name, ExtensibleDialect *dialect, |
260 | VerifierFn &&verifier, ParserFn &&parser, |
261 | PrinterFn &&printer); |
262 | |
263 | /// This constructor should only be used when we need a pointer to |
264 | /// the DynamicTypeDefinition in the verifier, the parser, or the printer. |
265 | /// The verifier, parser, and printer need thus to be initialized after the |
266 | /// constructor. |
267 | DynamicTypeDefinition(ExtensibleDialect *dialect, StringRef name); |
268 | |
269 | /// Register the concrete type in the type Uniquer. |
270 | void registerInTypeUniquer(); |
271 | |
272 | /// The name should be prefixed with the dialect name followed by '.'. |
273 | std::string name; |
274 | |
275 | /// Dialect in which this type is defined. |
276 | ExtensibleDialect *dialect; |
277 | |
278 | /// The type verifier. It checks that the type parameters satisfy the |
279 | /// invariants. |
280 | VerifierFn verifier; |
281 | |
282 | /// The type parameters parser. It parses only the parameters, and expects the |
283 | /// type name to have already been parsed. |
284 | ParserFn parser; |
285 | |
286 | /// The type parameters printer. It prints only the parameters, and expects |
287 | /// the type name to have already been printed. |
288 | PrinterFn printer; |
289 | |
290 | /// Context in which the concrete types are uniqued. |
291 | MLIRContext *ctx; |
292 | |
293 | friend ExtensibleDialect; |
294 | friend DynamicType; |
295 | }; |
296 | |
297 | /// This trait is used to determine if a type is a dynamic type or not; |
298 | /// it should only be implemented by dynamic types. |
299 | /// Note: This is only required because dynamic type do not have a |
300 | /// static/single TypeID. |
301 | namespace TypeTrait { |
302 | template <typename ConcreteType> |
303 | class IsDynamicType : public TypeTrait::TraitBase<ConcreteType, IsDynamicType> { |
304 | }; |
305 | } // namespace TypeTrait |
306 | |
307 | /// A dynamic type instance. This is a type whose definition is defined at |
308 | /// runtime. |
309 | /// It is possible to check if a type is a dynamic type using |
310 | /// `my_type.isa<DynamicType>()`, and getting the type definition of a dynamic |
311 | /// type using the `DynamicType::getTypeDef` method. |
312 | /// All dynamic types have the same storage, which is an array of attributes. |
313 | class DynamicType |
314 | : public Type::TypeBase<DynamicType, Type, detail::DynamicTypeStorage, |
315 | TypeTrait::IsDynamicType> { |
316 | public: |
317 | // Inherit Base constructors. |
318 | using Base::Base; |
319 | |
320 | /// Return an instance of a dynamic type given a dynamic type definition and |
321 | /// type parameters. |
322 | /// This asserts that the type verifier succeeded. |
323 | static DynamicType get(DynamicTypeDefinition *typeDef, |
324 | ArrayRef<Attribute> params = {}); |
325 | |
326 | /// Return an instance of a dynamic type given a dynamic type definition and |
327 | /// type parameters. If the parameters provided are invalid, errors are |
328 | /// emitted using the provided location and a null object is returned. |
329 | static DynamicType getChecked(function_ref<InFlightDiagnostic()> emitError, |
330 | DynamicTypeDefinition *typeDef, |
331 | ArrayRef<Attribute> params = {}); |
332 | |
333 | /// Return the type definition of the concrete type. |
334 | DynamicTypeDefinition *getTypeDef(); |
335 | |
336 | /// Return the type parameters. |
337 | ArrayRef<Attribute> getParams(); |
338 | |
339 | /// Check if a type is a specific dynamic type. |
340 | static bool isa(Type type, DynamicTypeDefinition *typeDef) { |
341 | return type.getTypeID() == typeDef->getTypeID(); |
342 | } |
343 | |
344 | /// Check if a type is a dynamic type. |
345 | static bool classof(Type type); |
346 | |
347 | /// Parse the dynamic type parameters and construct the type. |
348 | /// The parameters are either empty, and nothing is parsed, |
349 | /// or they are in the format '<>' or '<attr (,attr)*>'. |
350 | static ParseResult parse(AsmParser &parser, DynamicTypeDefinition *typeDef, |
351 | DynamicType &parsedType); |
352 | |
353 | /// Print the dynamic type with the format |
354 | /// 'type' or 'type<>' if there is no parameters, or 'type<attr (,attr)*>'. |
355 | void print(AsmPrinter &printer); |
356 | }; |
357 | |
358 | //===----------------------------------------------------------------------===// |
359 | // Dynamic operation |
360 | //===----------------------------------------------------------------------===// |
361 | |
362 | /// The definition of a dynamic op. A dynamic op is an op that is defined at |
363 | /// runtime, and that can be registered at runtime by an extensible dialect (a |
364 | /// dialect inheriting ExtensibleDialect). This class implements the method |
365 | /// exposed by the OperationName class, and in addition defines the TypeID of |
366 | /// the op that will be defined. Each dynamic operation definition refers to one |
367 | /// instance of this class. |
368 | class DynamicOpDefinition : public OperationName::Impl { |
369 | public: |
370 | using GetCanonicalizationPatternsFn = |
371 | llvm::unique_function<void(RewritePatternSet &, MLIRContext *) const>; |
372 | |
373 | /// Create a new op at runtime. The op is registered only after passing it to |
374 | /// the dialect using registerDynamicOp. |
375 | static std::unique_ptr<DynamicOpDefinition> |
376 | get(StringRef name, ExtensibleDialect *dialect, |
377 | OperationName::VerifyInvariantsFn &&verifyFn, |
378 | OperationName::VerifyRegionInvariantsFn &&verifyRegionFn); |
379 | static std::unique_ptr<DynamicOpDefinition> |
380 | get(StringRef name, ExtensibleDialect *dialect, |
381 | OperationName::VerifyInvariantsFn &&verifyFn, |
382 | OperationName::VerifyRegionInvariantsFn &&verifyRegionFn, |
383 | OperationName::ParseAssemblyFn &&parseFn, |
384 | OperationName::PrintAssemblyFn &&printFn); |
385 | static std::unique_ptr<DynamicOpDefinition> |
386 | get(StringRef name, ExtensibleDialect *dialect, |
387 | OperationName::VerifyInvariantsFn &&verifyFn, |
388 | OperationName::VerifyRegionInvariantsFn &&verifyRegionFn, |
389 | OperationName::ParseAssemblyFn &&parseFn, |
390 | OperationName::PrintAssemblyFn &&printFn, |
391 | OperationName::FoldHookFn &&foldHookFn, |
392 | GetCanonicalizationPatternsFn &&getCanonicalizationPatternsFn, |
393 | OperationName::PopulateDefaultAttrsFn &&populateDefaultAttrsFn); |
394 | |
395 | /// Returns the op typeID. |
396 | TypeID getTypeID() { return typeID; } |
397 | |
398 | /// Sets the verifier function for this operation. It should emits an error |
399 | /// message and returns failure if a problem is detected, or returns success |
400 | /// if everything is ok. |
401 | void setVerifyFn(OperationName::VerifyInvariantsFn &&verify) { |
402 | verifyFn = std::move(verify); |
403 | } |
404 | |
405 | /// Sets the region verifier function for this operation. It should emits an |
406 | /// error message and returns failure if a problem is detected, or returns |
407 | /// success if everything is ok. |
408 | void setVerifyRegionFn(OperationName::VerifyRegionInvariantsFn &&verify) { |
409 | verifyRegionFn = std::move(verify); |
410 | } |
411 | |
412 | /// Sets the static hook for parsing this op assembly. |
413 | void setParseFn(OperationName::ParseAssemblyFn &&parse) { |
414 | parseFn = std::move(parse); |
415 | } |
416 | |
417 | /// Sets the static hook for printing this op assembly. |
418 | void setPrintFn(OperationName::PrintAssemblyFn &&print) { |
419 | printFn = std::move(print); |
420 | } |
421 | |
422 | /// Sets the hook implementing a generalized folder for the op. See |
423 | /// `RegisteredOperationName::foldHook` for more details |
424 | void setFoldHookFn(OperationName::FoldHookFn &&foldHook) { |
425 | foldHookFn = std::move(foldHook); |
426 | } |
427 | |
428 | /// Set the hook returning any canonicalization pattern rewrites that the op |
429 | /// supports, for use by the canonicalization pass. |
430 | void setGetCanonicalizationPatternsFn( |
431 | GetCanonicalizationPatternsFn &&getCanonicalizationPatterns) { |
432 | getCanonicalizationPatternsFn = std::move(getCanonicalizationPatterns); |
433 | } |
434 | |
435 | /// Set the hook populating default attributes. |
436 | void setPopulateDefaultAttrsFn( |
437 | OperationName::PopulateDefaultAttrsFn &&populateDefaultAttrs) { |
438 | populateDefaultAttrsFn = std::move(populateDefaultAttrs); |
439 | } |
440 | |
441 | LogicalResult foldHook(Operation *op, ArrayRef<Attribute> attrs, |
442 | SmallVectorImpl<OpFoldResult> &results) final { |
443 | return foldHookFn(op, attrs, results); |
444 | } |
445 | void getCanonicalizationPatterns(RewritePatternSet &set, |
446 | MLIRContext *context) final { |
447 | getCanonicalizationPatternsFn(set, context); |
448 | } |
449 | bool hasTrait(TypeID id) final { return false; } |
450 | OperationName::ParseAssemblyFn getParseAssemblyFn() final { |
451 | return [&](OpAsmParser &parser, OperationState &state) { |
452 | return parseFn(parser, state); |
453 | }; |
454 | } |
455 | void populateDefaultAttrs(const OperationName &name, |
456 | NamedAttrList &attrs) final { |
457 | populateDefaultAttrsFn(name, attrs); |
458 | } |
459 | void printAssembly(Operation *op, OpAsmPrinter &printer, |
460 | StringRef name) final { |
461 | printFn(op, printer, name); |
462 | } |
463 | LogicalResult verifyInvariants(Operation *op) final { return verifyFn(op); } |
464 | LogicalResult verifyRegionInvariants(Operation *op) final { |
465 | return verifyRegionFn(op); |
466 | } |
467 | |
468 | /// Implementation for properties (unsupported right now here). |
469 | std::optional<Attribute> getInherentAttr(Operation *op, |
470 | StringRef name) final { |
471 | llvm::report_fatal_error(reason: "Unsupported getInherentAttr on Dynamic dialects" ); |
472 | } |
473 | void setInherentAttr(Operation *op, StringAttr name, Attribute value) final { |
474 | llvm::report_fatal_error(reason: "Unsupported setInherentAttr on Dynamic dialects" ); |
475 | } |
476 | void populateInherentAttrs(Operation *op, NamedAttrList &attrs) final {} |
477 | LogicalResult |
478 | verifyInherentAttrs(OperationName opName, NamedAttrList &attributes, |
479 | function_ref<InFlightDiagnostic()> emitError) final { |
480 | return success(); |
481 | } |
482 | int getOpPropertyByteSize() final { return 0; } |
483 | void initProperties(OperationName opName, OpaqueProperties storage, |
484 | OpaqueProperties init) final {} |
485 | void deleteProperties(OpaqueProperties prop) final {} |
486 | void populateDefaultProperties(OperationName opName, |
487 | OpaqueProperties properties) final {} |
488 | |
489 | LogicalResult |
490 | setPropertiesFromAttr(OperationName opName, OpaqueProperties properties, |
491 | Attribute attr, |
492 | function_ref<InFlightDiagnostic()> emitError) final { |
493 | emitError() << "extensible Dialects don't support properties" ; |
494 | return failure(); |
495 | } |
496 | Attribute getPropertiesAsAttr(Operation *op) final { return {}; } |
497 | void copyProperties(OpaqueProperties lhs, OpaqueProperties rhs) final {} |
498 | bool compareProperties(OpaqueProperties, OpaqueProperties) final { return false; } |
499 | llvm::hash_code hashProperties(OpaqueProperties prop) final { return {}; } |
500 | |
501 | private: |
502 | DynamicOpDefinition( |
503 | StringRef name, ExtensibleDialect *dialect, |
504 | OperationName::VerifyInvariantsFn &&verifyFn, |
505 | OperationName::VerifyRegionInvariantsFn &&verifyRegionFn, |
506 | OperationName::ParseAssemblyFn &&parseFn, |
507 | OperationName::PrintAssemblyFn &&printFn, |
508 | OperationName::FoldHookFn &&foldHookFn, |
509 | GetCanonicalizationPatternsFn &&getCanonicalizationPatternsFn, |
510 | OperationName::PopulateDefaultAttrsFn &&populateDefaultAttrsFn); |
511 | |
512 | /// Dialect defining this operation. |
513 | ExtensibleDialect *getdialect(); |
514 | |
515 | OperationName::VerifyInvariantsFn verifyFn; |
516 | OperationName::VerifyRegionInvariantsFn verifyRegionFn; |
517 | OperationName::ParseAssemblyFn parseFn; |
518 | OperationName::PrintAssemblyFn printFn; |
519 | OperationName::FoldHookFn foldHookFn; |
520 | GetCanonicalizationPatternsFn getCanonicalizationPatternsFn; |
521 | OperationName::PopulateDefaultAttrsFn populateDefaultAttrsFn; |
522 | |
523 | friend ExtensibleDialect; |
524 | }; |
525 | |
526 | //===----------------------------------------------------------------------===// |
527 | // Extensible dialect |
528 | //===----------------------------------------------------------------------===// |
529 | |
530 | /// A dialect that can be extended with new operations/types/attributes at |
531 | /// runtime. |
532 | class ExtensibleDialect : public mlir::Dialect { |
533 | public: |
534 | ExtensibleDialect(StringRef name, MLIRContext *ctx, TypeID typeID); |
535 | |
536 | /// Add a new type defined at runtime to the dialect. |
537 | void registerDynamicType(std::unique_ptr<DynamicTypeDefinition> &&type); |
538 | |
539 | /// Add a new attribute defined at runtime to the dialect. |
540 | void registerDynamicAttr(std::unique_ptr<DynamicAttrDefinition> &&attr); |
541 | |
542 | /// Add a new operation defined at runtime to the dialect. |
543 | void registerDynamicOp(std::unique_ptr<DynamicOpDefinition> &&type); |
544 | |
545 | /// Check if the dialect is an extensible dialect. |
546 | static bool classof(const Dialect *dialect); |
547 | |
548 | /// Returns nullptr if the definition was not found. |
549 | DynamicTypeDefinition *lookupTypeDefinition(StringRef name) const { |
550 | return nameToDynTypes.lookup(Key: name); |
551 | } |
552 | |
553 | /// Returns nullptr if the definition was not found. |
554 | DynamicTypeDefinition *lookupTypeDefinition(TypeID id) const { |
555 | auto it = dynTypes.find(Val: id); |
556 | if (it == dynTypes.end()) |
557 | return nullptr; |
558 | return it->second.get(); |
559 | } |
560 | |
561 | /// Returns nullptr if the definition was not found. |
562 | DynamicAttrDefinition *lookupAttrDefinition(StringRef name) const { |
563 | return nameToDynAttrs.lookup(Key: name); |
564 | } |
565 | |
566 | /// Returns nullptr if the definition was not found. |
567 | DynamicAttrDefinition *lookupAttrDefinition(TypeID id) const { |
568 | auto it = dynAttrs.find(Val: id); |
569 | if (it == dynAttrs.end()) |
570 | return nullptr; |
571 | return it->second.get(); |
572 | } |
573 | |
574 | protected: |
575 | /// Parse the dynamic type 'typeName' in the dialect 'dialect'. |
576 | /// typename should not be prefixed with the dialect name. |
577 | /// If the dynamic type does not exist, return no value. |
578 | /// Otherwise, parse it, and return the parse result. |
579 | /// If the parsing succeed, put the resulting type in 'resultType'. |
580 | OptionalParseResult parseOptionalDynamicType(StringRef typeName, |
581 | AsmParser &parser, |
582 | Type &resultType) const; |
583 | |
584 | /// If 'type' is a dynamic type, print it. |
585 | /// Returns success if the type was printed, and failure if the type was not a |
586 | /// dynamic type. |
587 | static LogicalResult printIfDynamicType(Type type, AsmPrinter &printer); |
588 | |
589 | /// Parse the dynamic attribute 'attrName' in the dialect 'dialect'. |
590 | /// attrname should not be prefixed with the dialect name. |
591 | /// If the dynamic attribute does not exist, return no value. |
592 | /// Otherwise, parse it, and return the parse result. |
593 | /// If the parsing succeed, put the resulting attribute in 'resultAttr'. |
594 | OptionalParseResult parseOptionalDynamicAttr(StringRef attrName, |
595 | AsmParser &parser, |
596 | Attribute &resultAttr) const; |
597 | |
598 | /// If 'attr' is a dynamic attribute, print it. |
599 | /// Returns success if the attribute was printed, and failure if the |
600 | /// attribute was not a dynamic attribute. |
601 | static LogicalResult printIfDynamicAttr(Attribute attr, AsmPrinter &printer); |
602 | |
603 | private: |
604 | /// The set of all dynamic types registered. |
605 | DenseMap<TypeID, std::unique_ptr<DynamicTypeDefinition>> dynTypes; |
606 | |
607 | /// This structure allows to get in O(1) a dynamic type given its name. |
608 | llvm::StringMap<DynamicTypeDefinition *> nameToDynTypes; |
609 | |
610 | /// The set of all dynamic attributes registered. |
611 | DenseMap<TypeID, std::unique_ptr<DynamicAttrDefinition>> dynAttrs; |
612 | |
613 | /// This structure allows to get in O(1) a dynamic attribute given its name. |
614 | llvm::StringMap<DynamicAttrDefinition *> nameToDynAttrs; |
615 | |
616 | /// Give DynamicOpDefinition access to allocateTypeID. |
617 | friend DynamicOpDefinition; |
618 | |
619 | /// Allocates a type ID to uniquify operations. |
620 | TypeID allocateTypeID() { return typeIDAllocator.allocate(); } |
621 | |
622 | /// Owns the TypeID generated at runtime for operations. |
623 | TypeIDAllocator typeIDAllocator; |
624 | }; |
625 | |
626 | //===----------------------------------------------------------------------===// |
627 | // Dynamic dialect |
628 | //===----------------------------------------------------------------------===// |
629 | |
630 | /// A dialect that can be defined at runtime. It can be extended with new |
631 | /// operations, types, and attributes at runtime. |
632 | class DynamicDialect : public SelfOwningTypeID, public ExtensibleDialect { |
633 | public: |
634 | DynamicDialect(StringRef name, MLIRContext *ctx); |
635 | |
636 | TypeID getTypeID() { return SelfOwningTypeID::getTypeID(); } |
637 | |
638 | /// Check if the dialect is an extensible dialect. |
639 | static bool classof(const Dialect *dialect); |
640 | |
641 | virtual Type parseType(DialectAsmParser &parser) const override; |
642 | virtual void printType(Type type, DialectAsmPrinter &printer) const override; |
643 | |
644 | virtual Attribute parseAttribute(DialectAsmParser &parser, |
645 | Type type) const override; |
646 | virtual void printAttribute(Attribute attr, |
647 | DialectAsmPrinter &printer) const override; |
648 | }; |
649 | } // namespace mlir |
650 | |
651 | namespace llvm { |
652 | /// Provide isa functionality for ExtensibleDialect. |
653 | /// This is to override the isa functionality for Dialect. |
654 | template <> |
655 | struct isa_impl<mlir::ExtensibleDialect, mlir::Dialect> { |
656 | static inline bool doit(const ::mlir::Dialect &dialect) { |
657 | return mlir::ExtensibleDialect::classof(dialect: &dialect); |
658 | } |
659 | }; |
660 | |
661 | /// Provide isa functionality for DynamicDialect. |
662 | /// This is to override the isa functionality for Dialect. |
663 | template <> |
664 | struct isa_impl<mlir::DynamicDialect, mlir::Dialect> { |
665 | static inline bool doit(const ::mlir::Dialect &dialect) { |
666 | return mlir::DynamicDialect::classof(dialect: &dialect); |
667 | } |
668 | }; |
669 | } // namespace llvm |
670 | |
671 | #endif // MLIR_IR_EXTENSIBLEDIALECT_H |
672 | |