1 //===- ExtensibleDialect.cpp - 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 #include "mlir/IR/ExtensibleDialect.h"
10 #include "mlir/IR/AttributeSupport.h"
11 #include "mlir/IR/DialectImplementation.h"
12 #include "mlir/IR/OperationSupport.h"
13 #include "mlir/IR/StorageUniquerSupport.h"
14 #include "mlir/Support/LogicalResult.h"
15 
16 using namespace mlir;
17 
18 //===----------------------------------------------------------------------===//
19 // Dynamic types and attributes shared functions
20 //===----------------------------------------------------------------------===//
21 
22 /// Default parser for dynamic attribute or type parameters.
23 /// Parse in the format '(<>)?' or '<attr (,attr)*>'.
24 static LogicalResult
typeOrAttrParser(AsmParser & parser,SmallVectorImpl<Attribute> & parsedParams)25 typeOrAttrParser(AsmParser &parser, SmallVectorImpl<Attribute> &parsedParams) {
26   // No parameters
27   if (parser.parseOptionalLess() || !parser.parseOptionalGreater())
28     return success();
29 
30   Attribute attr;
31   if (parser.parseAttribute(attr))
32     return failure();
33   parsedParams.push_back(attr);
34 
35   while (parser.parseOptionalGreater()) {
36     Attribute attr;
37     if (parser.parseComma() || parser.parseAttribute(attr))
38       return failure();
39     parsedParams.push_back(attr);
40   }
41 
42   return success();
43 }
44 
45 /// Default printer for dynamic attribute or type parameters.
46 /// Print in the format '(<>)?' or '<attr (,attr)*>'.
typeOrAttrPrinter(AsmPrinter & printer,ArrayRef<Attribute> params)47 static void typeOrAttrPrinter(AsmPrinter &printer, ArrayRef<Attribute> params) {
48   if (params.empty())
49     return;
50 
51   printer << "<";
52   interleaveComma(params, printer.getStream());
53   printer << ">";
54 }
55 
56 //===----------------------------------------------------------------------===//
57 // Dynamic type
58 //===----------------------------------------------------------------------===//
59 
60 std::unique_ptr<DynamicTypeDefinition>
get(StringRef name,ExtensibleDialect * dialect,VerifierFn && verifier)61 DynamicTypeDefinition::get(StringRef name, ExtensibleDialect *dialect,
62                            VerifierFn &&verifier) {
63   return DynamicTypeDefinition::get(name, dialect, std::move(verifier),
64                                     typeOrAttrParser, typeOrAttrPrinter);
65 }
66 
67 std::unique_ptr<DynamicTypeDefinition>
get(StringRef name,ExtensibleDialect * dialect,VerifierFn && verifier,ParserFn && parser,PrinterFn && printer)68 DynamicTypeDefinition::get(StringRef name, ExtensibleDialect *dialect,
69                            VerifierFn &&verifier, ParserFn &&parser,
70                            PrinterFn &&printer) {
71   return std::unique_ptr<DynamicTypeDefinition>(
72       new DynamicTypeDefinition(name, dialect, std::move(verifier),
73                                 std::move(parser), std::move(printer)));
74 }
75 
DynamicTypeDefinition(StringRef nameRef,ExtensibleDialect * dialect,VerifierFn && verifier,ParserFn && parser,PrinterFn && printer)76 DynamicTypeDefinition::DynamicTypeDefinition(StringRef nameRef,
77                                              ExtensibleDialect *dialect,
78                                              VerifierFn &&verifier,
79                                              ParserFn &&parser,
80                                              PrinterFn &&printer)
81     : name(nameRef), dialect(dialect), verifier(std::move(verifier)),
82       parser(std::move(parser)), printer(std::move(printer)),
83       ctx(dialect->getContext()) {}
84 
DynamicTypeDefinition(ExtensibleDialect * dialect,StringRef nameRef)85 DynamicTypeDefinition::DynamicTypeDefinition(ExtensibleDialect *dialect,
86                                              StringRef nameRef)
87     : name(nameRef), dialect(dialect), ctx(dialect->getContext()) {}
88 
registerInTypeUniquer()89 void DynamicTypeDefinition::registerInTypeUniquer() {
90   detail::TypeUniquer::registerType<DynamicType>(&getContext(), getTypeID());
91 }
92 
93 namespace mlir {
94 namespace detail {
95 /// Storage of DynamicType.
96 /// Contains a pointer to the type definition and type parameters.
97 struct DynamicTypeStorage : public TypeStorage {
98 
99   using KeyTy = std::pair<DynamicTypeDefinition *, ArrayRef<Attribute>>;
100 
DynamicTypeStoragemlir::detail::DynamicTypeStorage101   explicit DynamicTypeStorage(DynamicTypeDefinition *typeDef,
102                               ArrayRef<Attribute> params)
103       : typeDef(typeDef), params(params) {}
104 
operator ==mlir::detail::DynamicTypeStorage105   bool operator==(const KeyTy &key) const {
106     return typeDef == key.first && params == key.second;
107   }
108 
hashKeymlir::detail::DynamicTypeStorage109   static llvm::hash_code hashKey(const KeyTy &key) {
110     return llvm::hash_value(key);
111   }
112 
constructmlir::detail::DynamicTypeStorage113   static DynamicTypeStorage *construct(TypeStorageAllocator &alloc,
114                                        const KeyTy &key) {
115     return new (alloc.allocate<DynamicTypeStorage>())
116         DynamicTypeStorage(key.first, alloc.copyInto(key.second));
117   }
118 
119   /// Definition of the type.
120   DynamicTypeDefinition *typeDef;
121 
122   /// The type parameters.
123   ArrayRef<Attribute> params;
124 };
125 } // namespace detail
126 } // namespace mlir
127 
get(DynamicTypeDefinition * typeDef,ArrayRef<Attribute> params)128 DynamicType DynamicType::get(DynamicTypeDefinition *typeDef,
129                              ArrayRef<Attribute> params) {
130   auto &ctx = typeDef->getContext();
131   auto emitError = detail::getDefaultDiagnosticEmitFn(&ctx);
132   assert(succeeded(typeDef->verify(emitError, params)));
133   return detail::TypeUniquer::getWithTypeID<DynamicType>(
134       &ctx, typeDef->getTypeID(), typeDef, params);
135 }
136 
137 DynamicType
getChecked(function_ref<InFlightDiagnostic ()> emitError,DynamicTypeDefinition * typeDef,ArrayRef<Attribute> params)138 DynamicType::getChecked(function_ref<InFlightDiagnostic()> emitError,
139                         DynamicTypeDefinition *typeDef,
140                         ArrayRef<Attribute> params) {
141   if (failed(typeDef->verify(emitError, params)))
142     return {};
143   auto &ctx = typeDef->getContext();
144   return detail::TypeUniquer::getWithTypeID<DynamicType>(
145       &ctx, typeDef->getTypeID(), typeDef, params);
146 }
147 
getTypeDef()148 DynamicTypeDefinition *DynamicType::getTypeDef() { return getImpl()->typeDef; }
149 
getParams()150 ArrayRef<Attribute> DynamicType::getParams() { return getImpl()->params; }
151 
classof(Type type)152 bool DynamicType::classof(Type type) {
153   return type.hasTrait<TypeTrait::IsDynamicType>();
154 }
155 
parse(AsmParser & parser,DynamicTypeDefinition * typeDef,DynamicType & parsedType)156 ParseResult DynamicType::parse(AsmParser &parser,
157                                DynamicTypeDefinition *typeDef,
158                                DynamicType &parsedType) {
159   SmallVector<Attribute> params;
160   if (failed(typeDef->parser(parser, params)))
161     return failure();
162   parsedType = parser.getChecked<DynamicType>(typeDef, params);
163   if (!parsedType)
164     return failure();
165   return success();
166 }
167 
print(AsmPrinter & printer)168 void DynamicType::print(AsmPrinter &printer) {
169   printer << getTypeDef()->getName();
170   getTypeDef()->printer(printer, getParams());
171 }
172 
173 //===----------------------------------------------------------------------===//
174 // Dynamic attribute
175 //===----------------------------------------------------------------------===//
176 
177 std::unique_ptr<DynamicAttrDefinition>
get(StringRef name,ExtensibleDialect * dialect,VerifierFn && verifier)178 DynamicAttrDefinition::get(StringRef name, ExtensibleDialect *dialect,
179                            VerifierFn &&verifier) {
180   return DynamicAttrDefinition::get(name, dialect, std::move(verifier),
181                                     typeOrAttrParser, typeOrAttrPrinter);
182 }
183 
184 std::unique_ptr<DynamicAttrDefinition>
get(StringRef name,ExtensibleDialect * dialect,VerifierFn && verifier,ParserFn && parser,PrinterFn && printer)185 DynamicAttrDefinition::get(StringRef name, ExtensibleDialect *dialect,
186                            VerifierFn &&verifier, ParserFn &&parser,
187                            PrinterFn &&printer) {
188   return std::unique_ptr<DynamicAttrDefinition>(
189       new DynamicAttrDefinition(name, dialect, std::move(verifier),
190                                 std::move(parser), std::move(printer)));
191 }
192 
DynamicAttrDefinition(StringRef nameRef,ExtensibleDialect * dialect,VerifierFn && verifier,ParserFn && parser,PrinterFn && printer)193 DynamicAttrDefinition::DynamicAttrDefinition(StringRef nameRef,
194                                              ExtensibleDialect *dialect,
195                                              VerifierFn &&verifier,
196                                              ParserFn &&parser,
197                                              PrinterFn &&printer)
198     : name(nameRef), dialect(dialect), verifier(std::move(verifier)),
199       parser(std::move(parser)), printer(std::move(printer)),
200       ctx(dialect->getContext()) {}
201 
DynamicAttrDefinition(ExtensibleDialect * dialect,StringRef nameRef)202 DynamicAttrDefinition::DynamicAttrDefinition(ExtensibleDialect *dialect,
203                                              StringRef nameRef)
204     : name(nameRef), dialect(dialect), ctx(dialect->getContext()) {}
205 
registerInAttrUniquer()206 void DynamicAttrDefinition::registerInAttrUniquer() {
207   detail::AttributeUniquer::registerAttribute<DynamicAttr>(&getContext(),
208                                                            getTypeID());
209 }
210 
211 namespace mlir {
212 namespace detail {
213 /// Storage of DynamicAttr.
214 /// Contains a pointer to the attribute definition and attribute parameters.
215 struct DynamicAttrStorage : public AttributeStorage {
216   using KeyTy = std::pair<DynamicAttrDefinition *, ArrayRef<Attribute>>;
217 
DynamicAttrStoragemlir::detail::DynamicAttrStorage218   explicit DynamicAttrStorage(DynamicAttrDefinition *attrDef,
219                               ArrayRef<Attribute> params)
220       : attrDef(attrDef), params(params) {}
221 
operator ==mlir::detail::DynamicAttrStorage222   bool operator==(const KeyTy &key) const {
223     return attrDef == key.first && params == key.second;
224   }
225 
hashKeymlir::detail::DynamicAttrStorage226   static llvm::hash_code hashKey(const KeyTy &key) {
227     return llvm::hash_value(key);
228   }
229 
constructmlir::detail::DynamicAttrStorage230   static DynamicAttrStorage *construct(AttributeStorageAllocator &alloc,
231                                        const KeyTy &key) {
232     return new (alloc.allocate<DynamicAttrStorage>())
233         DynamicAttrStorage(key.first, alloc.copyInto(key.second));
234   }
235 
236   /// Definition of the type.
237   DynamicAttrDefinition *attrDef;
238 
239   /// The type parameters.
240   ArrayRef<Attribute> params;
241 };
242 } // namespace detail
243 } // namespace mlir
244 
get(DynamicAttrDefinition * attrDef,ArrayRef<Attribute> params)245 DynamicAttr DynamicAttr::get(DynamicAttrDefinition *attrDef,
246                              ArrayRef<Attribute> params) {
247   auto &ctx = attrDef->getContext();
248   return detail::AttributeUniquer::getWithTypeID<DynamicAttr>(
249       &ctx, attrDef->getTypeID(), attrDef, params);
250 }
251 
252 DynamicAttr
getChecked(function_ref<InFlightDiagnostic ()> emitError,DynamicAttrDefinition * attrDef,ArrayRef<Attribute> params)253 DynamicAttr::getChecked(function_ref<InFlightDiagnostic()> emitError,
254                         DynamicAttrDefinition *attrDef,
255                         ArrayRef<Attribute> params) {
256   if (failed(attrDef->verify(emitError, params)))
257     return {};
258   return get(attrDef, params);
259 }
260 
getAttrDef()261 DynamicAttrDefinition *DynamicAttr::getAttrDef() { return getImpl()->attrDef; }
262 
getParams()263 ArrayRef<Attribute> DynamicAttr::getParams() { return getImpl()->params; }
264 
classof(Attribute attr)265 bool DynamicAttr::classof(Attribute attr) {
266   return attr.hasTrait<AttributeTrait::IsDynamicAttr>();
267 }
268 
parse(AsmParser & parser,DynamicAttrDefinition * attrDef,DynamicAttr & parsedAttr)269 ParseResult DynamicAttr::parse(AsmParser &parser,
270                                DynamicAttrDefinition *attrDef,
271                                DynamicAttr &parsedAttr) {
272   SmallVector<Attribute> params;
273   if (failed(attrDef->parser(parser, params)))
274     return failure();
275   parsedAttr = parser.getChecked<DynamicAttr>(attrDef, params);
276   if (!parsedAttr)
277     return failure();
278   return success();
279 }
280 
print(AsmPrinter & printer)281 void DynamicAttr::print(AsmPrinter &printer) {
282   printer << getAttrDef()->getName();
283   getAttrDef()->printer(printer, getParams());
284 }
285 
286 //===----------------------------------------------------------------------===//
287 // Dynamic operation
288 //===----------------------------------------------------------------------===//
289 
DynamicOpDefinition(StringRef name,ExtensibleDialect * dialect,OperationName::VerifyInvariantsFn && verifyFn,OperationName::VerifyRegionInvariantsFn && verifyRegionFn,OperationName::ParseAssemblyFn && parseFn,OperationName::PrintAssemblyFn && printFn,OperationName::FoldHookFn && foldHookFn,OperationName::GetCanonicalizationPatternsFn && getCanonicalizationPatternsFn,OperationName::PopulateDefaultAttrsFn && populateDefaultAttrsFn)290 DynamicOpDefinition::DynamicOpDefinition(
291     StringRef name, ExtensibleDialect *dialect,
292     OperationName::VerifyInvariantsFn &&verifyFn,
293     OperationName::VerifyRegionInvariantsFn &&verifyRegionFn,
294     OperationName::ParseAssemblyFn &&parseFn,
295     OperationName::PrintAssemblyFn &&printFn,
296     OperationName::FoldHookFn &&foldHookFn,
297     OperationName::GetCanonicalizationPatternsFn
298         &&getCanonicalizationPatternsFn,
299     OperationName::PopulateDefaultAttrsFn &&populateDefaultAttrsFn)
300     : typeID(dialect->allocateTypeID()),
301       name((dialect->getNamespace() + "." + name).str()), dialect(dialect),
302       verifyFn(std::move(verifyFn)), verifyRegionFn(std::move(verifyRegionFn)),
303       parseFn(std::move(parseFn)), printFn(std::move(printFn)),
304       foldHookFn(std::move(foldHookFn)),
305       getCanonicalizationPatternsFn(std::move(getCanonicalizationPatternsFn)),
306       populateDefaultAttrsFn(std::move(populateDefaultAttrsFn)) {}
307 
get(StringRef name,ExtensibleDialect * dialect,OperationName::VerifyInvariantsFn && verifyFn,OperationName::VerifyRegionInvariantsFn && verifyRegionFn)308 std::unique_ptr<DynamicOpDefinition> DynamicOpDefinition::get(
309     StringRef name, ExtensibleDialect *dialect,
310     OperationName::VerifyInvariantsFn &&verifyFn,
311     OperationName::VerifyRegionInvariantsFn &&verifyRegionFn) {
312   auto parseFn = [](OpAsmParser &parser, OperationState &result) {
313     return parser.emitError(
314         parser.getCurrentLocation(),
315         "dynamic operation do not define any parser function");
316   };
317 
318   auto printFn = [](Operation *op, OpAsmPrinter &printer, StringRef) {
319     printer.printGenericOp(op);
320   };
321 
322   return DynamicOpDefinition::get(name, dialect, std::move(verifyFn),
323                                   std::move(verifyRegionFn), std::move(parseFn),
324                                   std::move(printFn));
325 }
326 
get(StringRef name,ExtensibleDialect * dialect,OperationName::VerifyInvariantsFn && verifyFn,OperationName::VerifyRegionInvariantsFn && verifyRegionFn,OperationName::ParseAssemblyFn && parseFn,OperationName::PrintAssemblyFn && printFn)327 std::unique_ptr<DynamicOpDefinition> DynamicOpDefinition::get(
328     StringRef name, ExtensibleDialect *dialect,
329     OperationName::VerifyInvariantsFn &&verifyFn,
330     OperationName::VerifyRegionInvariantsFn &&verifyRegionFn,
331     OperationName::ParseAssemblyFn &&parseFn,
332     OperationName::PrintAssemblyFn &&printFn) {
333   auto foldHookFn = [](Operation *op, ArrayRef<Attribute> operands,
334                        SmallVectorImpl<OpFoldResult> &results) {
335     return failure();
336   };
337 
338   auto getCanonicalizationPatternsFn = [](RewritePatternSet &, MLIRContext *) {
339   };
340 
341   auto populateDefaultAttrsFn = [](const RegisteredOperationName &,
342                                    NamedAttrList &) {};
343 
344   return DynamicOpDefinition::get(name, dialect, std::move(verifyFn),
345                                   std::move(verifyRegionFn), std::move(parseFn),
346                                   std::move(printFn), std::move(foldHookFn),
347                                   std::move(getCanonicalizationPatternsFn),
348                                   std::move(populateDefaultAttrsFn));
349 }
350 
get(StringRef name,ExtensibleDialect * dialect,OperationName::VerifyInvariantsFn && verifyFn,OperationName::VerifyInvariantsFn && verifyRegionFn,OperationName::ParseAssemblyFn && parseFn,OperationName::PrintAssemblyFn && printFn,OperationName::FoldHookFn && foldHookFn,OperationName::GetCanonicalizationPatternsFn && getCanonicalizationPatternsFn,OperationName::PopulateDefaultAttrsFn && populateDefaultAttrsFn)351 std::unique_ptr<DynamicOpDefinition> DynamicOpDefinition::get(
352     StringRef name, ExtensibleDialect *dialect,
353     OperationName::VerifyInvariantsFn &&verifyFn,
354     OperationName::VerifyInvariantsFn &&verifyRegionFn,
355     OperationName::ParseAssemblyFn &&parseFn,
356     OperationName::PrintAssemblyFn &&printFn,
357     OperationName::FoldHookFn &&foldHookFn,
358     OperationName::GetCanonicalizationPatternsFn
359         &&getCanonicalizationPatternsFn,
360     OperationName::PopulateDefaultAttrsFn &&populateDefaultAttrsFn) {
361   return std::unique_ptr<DynamicOpDefinition>(new DynamicOpDefinition(
362       name, dialect, std::move(verifyFn), std::move(verifyRegionFn),
363       std::move(parseFn), std::move(printFn), std::move(foldHookFn),
364       std::move(getCanonicalizationPatternsFn),
365       std::move(populateDefaultAttrsFn)));
366 }
367 
368 //===----------------------------------------------------------------------===//
369 // Extensible dialect
370 //===----------------------------------------------------------------------===//
371 
372 namespace {
373 /// Interface that can only be implemented by extensible dialects.
374 /// The interface is used to check if a dialect is extensible or not.
375 class IsExtensibleDialect : public DialectInterface::Base<IsExtensibleDialect> {
376 public:
IsExtensibleDialect(Dialect * dialect)377   IsExtensibleDialect(Dialect *dialect) : Base(dialect) {}
378 
379   MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(IsExtensibleDialect)
380 };
381 } // namespace
382 
ExtensibleDialect(StringRef name,MLIRContext * ctx,TypeID typeID)383 ExtensibleDialect::ExtensibleDialect(StringRef name, MLIRContext *ctx,
384                                      TypeID typeID)
385     : Dialect(name, ctx, typeID) {
386   addInterfaces<IsExtensibleDialect>();
387 }
388 
registerDynamicType(std::unique_ptr<DynamicTypeDefinition> && type)389 void ExtensibleDialect::registerDynamicType(
390     std::unique_ptr<DynamicTypeDefinition> &&type) {
391   DynamicTypeDefinition *typePtr = type.get();
392   TypeID typeID = type->getTypeID();
393   StringRef name = type->getName();
394   ExtensibleDialect *dialect = type->getDialect();
395 
396   assert(dialect == this &&
397          "trying to register a dynamic type in the wrong dialect");
398 
399   // If a type with the same name is already defined, fail.
400   auto registered = dynTypes.try_emplace(typeID, std::move(type)).second;
401   (void)registered;
402   assert(registered && "type TypeID was not unique");
403 
404   registered = nameToDynTypes.insert({name, typePtr}).second;
405   (void)registered;
406   assert(registered &&
407          "Trying to create a new dynamic type with an existing name");
408 
409   auto abstractType =
410       AbstractType::get(*dialect, DynamicAttr::getInterfaceMap(),
411                         DynamicType::getHasTraitFn(), typeID);
412 
413   /// Add the type to the dialect and the type uniquer.
414   addType(typeID, std::move(abstractType));
415   typePtr->registerInTypeUniquer();
416 }
417 
registerDynamicAttr(std::unique_ptr<DynamicAttrDefinition> && attr)418 void ExtensibleDialect::registerDynamicAttr(
419     std::unique_ptr<DynamicAttrDefinition> &&attr) {
420   auto *attrPtr = attr.get();
421   auto typeID = attr->getTypeID();
422   auto name = attr->getName();
423   auto *dialect = attr->getDialect();
424 
425   assert(dialect == this &&
426          "trying to register a dynamic attribute in the wrong dialect");
427 
428   // If an attribute with the same name is already defined, fail.
429   auto registered = dynAttrs.try_emplace(typeID, std::move(attr)).second;
430   (void)registered;
431   assert(registered && "attribute TypeID was not unique");
432 
433   registered = nameToDynAttrs.insert({name, attrPtr}).second;
434   (void)registered;
435   assert(registered &&
436          "Trying to create a new dynamic attribute with an existing name");
437 
438   auto abstractAttr =
439       AbstractAttribute::get(*dialect, DynamicAttr::getInterfaceMap(),
440                              DynamicAttr::getHasTraitFn(), typeID);
441 
442   /// Add the type to the dialect and the type uniquer.
443   addAttribute(typeID, std::move(abstractAttr));
444   attrPtr->registerInAttrUniquer();
445 }
446 
registerDynamicOp(std::unique_ptr<DynamicOpDefinition> && op)447 void ExtensibleDialect::registerDynamicOp(
448     std::unique_ptr<DynamicOpDefinition> &&op) {
449   assert(op->dialect == this &&
450          "trying to register a dynamic op in the wrong dialect");
451   auto hasTraitFn = [](TypeID traitId) { return false; };
452 
453   RegisteredOperationName::insert(
454       op->name, *op->dialect, op->typeID, std::move(op->parseFn),
455       std::move(op->printFn), std::move(op->verifyFn),
456       std::move(op->verifyRegionFn), std::move(op->foldHookFn),
457       std::move(op->getCanonicalizationPatternsFn),
458       detail::InterfaceMap::get<>(), std::move(hasTraitFn), {},
459       std::move(op->populateDefaultAttrsFn));
460 }
461 
classof(const Dialect * dialect)462 bool ExtensibleDialect::classof(const Dialect *dialect) {
463   return const_cast<Dialect *>(dialect)
464       ->getRegisteredInterface<IsExtensibleDialect>();
465 }
466 
parseOptionalDynamicType(StringRef typeName,AsmParser & parser,Type & resultType) const467 OptionalParseResult ExtensibleDialect::parseOptionalDynamicType(
468     StringRef typeName, AsmParser &parser, Type &resultType) const {
469   DynamicTypeDefinition *typeDef = lookupTypeDefinition(typeName);
470   if (!typeDef)
471     return llvm::None;
472 
473   DynamicType dynType;
474   if (DynamicType::parse(parser, typeDef, dynType))
475     return failure();
476   resultType = dynType;
477   return success();
478 }
479 
printIfDynamicType(Type type,AsmPrinter & printer)480 LogicalResult ExtensibleDialect::printIfDynamicType(Type type,
481                                                     AsmPrinter &printer) {
482   if (auto dynType = type.dyn_cast<DynamicType>()) {
483     dynType.print(printer);
484     return success();
485   }
486   return failure();
487 }
488 
parseOptionalDynamicAttr(StringRef attrName,AsmParser & parser,Attribute & resultAttr) const489 OptionalParseResult ExtensibleDialect::parseOptionalDynamicAttr(
490     StringRef attrName, AsmParser &parser, Attribute &resultAttr) const {
491   DynamicAttrDefinition *attrDef = lookupAttrDefinition(attrName);
492   if (!attrDef)
493     return llvm::None;
494 
495   DynamicAttr dynAttr;
496   if (DynamicAttr::parse(parser, attrDef, dynAttr))
497     return failure();
498   resultAttr = dynAttr;
499   return success();
500 }
501 
printIfDynamicAttr(Attribute attribute,AsmPrinter & printer)502 LogicalResult ExtensibleDialect::printIfDynamicAttr(Attribute attribute,
503                                                     AsmPrinter &printer) {
504   if (auto dynAttr = attribute.dyn_cast<DynamicAttr>()) {
505     dynAttr.print(printer);
506     return success();
507   }
508   return failure();
509 }
510