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