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
33namespace mlir {
34class AsmParser;
35class AsmPrinter;
36class DynamicAttr;
37class DynamicType;
38class ExtensibleDialect;
39class MLIRContext;
40class OptionalParseResult;
41class ParseResult;
42
43namespace detail {
44struct DynamicAttrStorage;
45struct 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.
57class DynamicAttrDefinition : public SelfOwningTypeID {
58public:
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
102private:
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.
145namespace AttributeTrait {
146template <typename ConcreteType>
147class 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
158class DynamicAttr : public Attribute::AttrBase<DynamicAttr, Attribute,
159 detail::DynamicAttrStorage,
160 AttributeTrait::IsDynamicAttr> {
161public:
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.
213class DynamicTypeDefinition : public SelfOwningTypeID {
214public:
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
258private:
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.
301namespace TypeTrait {
302template <typename ConcreteType>
303class 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.
313class DynamicType
314 : public Type::TypeBase<DynamicType, Type, detail::DynamicTypeStorage,
315 TypeTrait::IsDynamicType> {
316public:
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.
368class DynamicOpDefinition : public OperationName::Impl {
369public:
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
501private:
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.
532class ExtensibleDialect : public mlir::Dialect {
533public:
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
574protected:
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
603private:
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.
632class DynamicDialect : public SelfOwningTypeID, public ExtensibleDialect {
633public:
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
651namespace llvm {
652/// Provide isa functionality for ExtensibleDialect.
653/// This is to override the isa functionality for Dialect.
654template <>
655struct 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.
663template <>
664struct 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

source code of mlir/include/mlir/IR/ExtensibleDialect.h