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