1//===- IRDLOps.td - IR Definition Language Dialect ---------*- tablegen -*-===// 2// 3// Part of the LLVM Project, 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 declares the IRDL dialect ops. 10// 11//===----------------------------------------------------------------------===// 12 13#ifndef MLIR_DIALECT_IRDL_IR_IRDLOPS 14#define MLIR_DIALECT_IRDL_IR_IRDLOPS 15 16include "IRDL.td" 17include "IRDLAttributes.td" 18include "IRDLTypes.td" 19include "IRDLInterfaces.td" 20include "mlir/Interfaces/SideEffectInterfaces.td" 21include "mlir/Interfaces/InferTypeOpInterface.td" 22include "mlir/IR/SymbolInterfaces.td" 23include "mlir/IR/BuiltinAttributes.td" 24 25class IRDL_Op<string mnemonic, list<Trait> traits = []> 26 : Op<IRDL_Dialect, mnemonic, traits>; 27 28class AtMostOneChildOf<string op> : ParamNativeOpTrait<"AtMostOneChildOf", op>; 29 30//===----------------------------------------------------------------------===// 31// Dialect definition 32//===----------------------------------------------------------------------===// 33 34def IRDL_DialectOp : IRDL_Op<"dialect", 35 [IsolatedFromAbove, NoTerminator, Symbol, SymbolTable]> { 36 let summary = "Define a new dialect"; 37 let description = [{ 38 The `irdl.dialect` operation defines a dialect. All operations, attributes, 39 and types defined inside its region will be part of the dialect. 40 41 Example: 42 43 ```mlir 44 irdl.dialect @cmath { 45 ... 46 } 47 ``` 48 49 The above program defines a `cmath` dialect. 50 }]; 51 52 let arguments = (ins SymbolNameAttr:$sym_name); 53 let regions = (region SizedRegion<1>:$body); 54 let assemblyFormat = 55 "$sym_name attr-dict-with-keyword custom<SingleBlockRegion>($body)"; 56 let hasVerifier = 1; 57} 58 59//===----------------------------------------------------------------------===// 60// Type and Attribute definition 61//===----------------------------------------------------------------------===// 62 63def IRDL_TypeOp : IRDL_Op<"type", 64 [HasParent<"DialectOp">, NoTerminator, NoRegionArguments, 65 AtMostOneChildOf<"ParametersOp">, Symbol]> { 66 let summary = "Define a new type"; 67 let description = [{ 68 `irdl.type` defines a new type belonging to the `irdl.dialect` parent. 69 70 The type parameters can be defined with an `irdl.parameters` operation in 71 the optional region. 72 73 Example: 74 75 ```mlir 76 irdl.dialect @cmath { 77 irdl.type @complex { 78 %0 = irdl.is i32 79 %1 = irdl.is i64 80 %2 = irdl.any_of(%0, %1) 81 irdl.parameters(%2) 82 } 83 } 84 ``` 85 86 The above program defines a type `complex` inside the dialect `cmath`. The 87 type has a single parameter that should be either `i32` or `i64`. 88 }]; 89 90 let arguments = (ins SymbolNameAttr:$sym_name); 91 let regions = (region SizedRegion<1>:$body); 92 let assemblyFormat = 93 "$sym_name attr-dict-with-keyword custom<SingleBlockRegion>($body)"; 94} 95 96def IRDL_AttributeOp : IRDL_Op<"attribute", 97 [HasParent<"DialectOp">, NoTerminator, NoRegionArguments, 98 AtMostOneChildOf<"ParametersOp">, Symbol]> { 99 let summary = "Define a new attribute"; 100 let description = [{ 101 `irdl.attribute` defines a new attribute belonging to the `irdl.dialect` 102 parent. 103 104 The attribute parameters can be defined with an `irdl.parameters` operation 105 in the optional region. 106 107 Example: 108 109 ```mlir 110 irdl.dialect @testd { 111 irdl.attribute @enum_attr { 112 %0 = irdl.is "foo" 113 %1 = irdl.is "bar" 114 %2 = irdl.any_of(%0, %1) 115 irdl.parameters(%2) 116 } 117 } 118 ``` 119 120 The above program defines an `enum_attr` attribute inside the `testd` 121 dialect. The attribute has one `StringAttr` parameter that should be 122 either a `"foo"` or a `"bar"`. 123 }]; 124 125 let arguments = (ins SymbolNameAttr:$sym_name); 126 let regions = (region SizedRegion<1>:$body); 127 let assemblyFormat = 128 "$sym_name attr-dict-with-keyword custom<SingleBlockRegion>($body)"; 129} 130 131def IRDL_ParametersOp : IRDL_Op<"parameters", 132 [ParentOneOf<["AttributeOp", "TypeOp"]>]> { 133 let summary = 134 "Define the constraints on parameters of a type/attribute definition"; 135 let description = [{ 136 `irdl.parameters` defines the constraints on parameters of a type or 137 attribute definition. Each parameter is named after an identifier. 138 139 Example: 140 141 ```mlir 142 irdl.dialect @cmath { 143 irdl.type @complex { 144 %0 = irdl.is i32 145 %1 = irdl.is i64 146 %2 = irdl.any_of(%0, %1) 147 irdl.parameters(elem: %2) 148 } 149 } 150 ``` 151 152 The above program defines a type `complex` inside the dialect `cmath`. The 153 type has a single parameter `elem` that should be either `i32` or `i64`. 154 }]; 155 156 let arguments = (ins Variadic<IRDL_AttributeType>:$args, 157 StrArrayAttr:$names); 158 let assemblyFormat = " `` custom<NamedValueList>($args, $names) attr-dict "; 159 let hasVerifier = true; 160} 161 162//===----------------------------------------------------------------------===// 163// IRDL Operation definition 164//===----------------------------------------------------------------------===// 165 166def IRDL_OperationOp : IRDL_Op<"operation", 167 [HasParent<"DialectOp">, NoTerminator, NoRegionArguments, 168 AtMostOneChildOf<"OperandsOp, ResultsOp, AttributesOp, RegionsOp">, 169 Symbol]> { 170 let summary = "Define a new operation"; 171 let description = [{ 172 `irdl.operation` defines a new operation belonging to the `irdl.dialect` 173 parent. 174 175 Operations can define constraints on their operands and results with the 176 `irdl.results` and `irdl.operands` operations. If these operations are not 177 present in the region, the results or operands are expected to be empty. 178 179 Example: 180 181 ```mlir 182 irdl.dialect @cmath { 183 184 irdl.type @complex { /* ... */ } 185 186 irdl.operation @norm { 187 %0 = irdl.any 188 %1 = irdl.parametric @cmath::@complex<%0> 189 irdl.results(%0) 190 irdl.operands(%1) 191 } 192 } 193 ``` 194 195 The above program defines an operation `norm` inside the dialect `cmath`. 196 The operation expects a single operand of base type `cmath.complex`, and 197 returns a single result of the element type of the operand. 198 }]; 199 200 let arguments = (ins SymbolNameAttr:$sym_name); 201 let regions = (region SizedRegion<1>:$body); 202 let assemblyFormat = 203 "$sym_name attr-dict-with-keyword custom<SingleBlockRegion>($body)"; 204 let hasRegionVerifier = true; 205} 206 207def IRDL_OperandsOp : IRDL_Op<"operands", [HasParent<"OperationOp">]> { 208 let summary = "Define the operands of an operation"; 209 let description = [{ 210 `irdl.operands` define the operands of the `irdl.operation` parent operation 211 definition. Each operand is named after an identifier. 212 213 In the following example, `irdl.operands` defines the operands of the 214 `mul` operation: 215 216 ```mlir 217 irdl.dialect @cmath { 218 219 irdl.type @complex { /* ... */ } 220 221 irdl.operation @mul { 222 %0 = irdl.any 223 %1 = irdl.parametric @cmath::@complex<%0> 224 irdl.results(res: %1) 225 irdl.operands(lhs: %1, rhs: %1) 226 } 227 } 228 ``` 229 230 The `mul` operation will expect two operands of type `cmath.complex`, that 231 have the same type, and return a result of the same type. 232 233 The operands can also be marked as variadic or optional: 234 ```mlir 235 irdl.operands(foo: %0, bar: single %1, baz: optional %2, qux: variadic %3) 236 ``` 237 238 Here, foo and bar are required single operands, baz is an optional operand, 239 and qux is a variadic operand. 240 241 When more than one operand is marked as optional or variadic, the operation 242 will expect a 'operandSegmentSizes' attribute that defines the number of 243 operands in each segment. 244 }]; 245 246 let arguments = (ins Variadic<IRDL_AttributeType>:$args, 247 StrArrayAttr:$names, 248 VariadicityArrayAttr:$variadicity); 249 let assemblyFormat = 250 " `` custom<NamedValueListWithVariadicity>($args, $names, $variadicity) attr-dict"; 251 let hasVerifier = true; 252} 253 254def IRDL_ResultsOp : IRDL_Op<"results", [HasParent<"OperationOp">]> { 255 let summary = "Define the results of an operation"; 256 let description = [{ 257 `irdl.results` define the results of the `irdl.operation` parent operation 258 definition. Each result is named after an identifier. 259 260 In the following example, `irdl.results` defines the results of the 261 `get_values` operation: 262 263 ```mlir 264 irdl.dialect @cmath { 265 266 irdl.type @complex { /* ... */ } 267 268 /// Returns the real and imaginary parts of a complex number. 269 irdl.operation @get_values { 270 %0 = irdl.any 271 %1 = irdl.parametric @cmath::@complex<%0> 272 irdl.results(re: %0, im: %0) 273 irdl.operands(complex: %1) 274 } 275 } 276 ``` 277 278 The operation will expect one operand of the `cmath.complex` type, and two 279 results that have the underlying type of the `cmath.complex`. 280 281 The results can also be marked as variadic or optional: 282 ```mlir 283 irdl.results(foo: %0, bar: single %1, baz: optional %2, qux: variadic %3) 284 ``` 285 286 Here, foo and bar are required single results, baz is an optional result, 287 and qux is a variadic result. 288 289 When more than one result is marked as optional or variadic, the operation 290 will expect a 'resultSegmentSizes' attribute that defines the number of 291 results in each segment. 292 }]; 293 294 let arguments = (ins Variadic<IRDL_AttributeType>:$args, 295 StrArrayAttr:$names, 296 VariadicityArrayAttr:$variadicity); 297 let assemblyFormat = 298 " `` custom<NamedValueListWithVariadicity>($args, $names, $variadicity) attr-dict"; 299 let hasVerifier = true; 300} 301 302def IRDL_AttributesOp : IRDL_Op<"attributes", [HasParent<"OperationOp">]> { 303 let summary = "Define the attributes of an operation"; 304 305 let description = [{ 306 `irdl.attributes` defines the attributes of the `irdl.operation` parent 307 operation definition. 308 309 In the following example, `irdl.attributes` defines the attributes of the 310 `attr_op` operation: 311 312 ```mlir 313 irdl.dialect @example { 314 315 irdl.operation @attr_op { 316 %0 = irdl.any 317 %1 = irdl.is i64 318 irdl.attibutes { 319 "attr1" = %0, 320 "attr2" = %1 321 } 322 } 323 } 324 ``` 325 326 The operation will expect an arbitrary attribute "attr1" and an 327 attribute "attr2" with value `i64`. 328 }]; 329 330 let arguments = (ins Variadic<IRDL_AttributeType>:$attributeValues, 331 StrArrayAttr:$attributeValueNames); 332 let assemblyFormat = [{ 333 custom<AttributesOp>($attributeValues, $attributeValueNames) attr-dict 334 }]; 335 336 let hasVerifier = true; 337} 338 339def IRDL_RegionOp : IRDL_Op<"region", 340 [HasParent<"OperationOp">, VerifyRegionInterface, 341 DeclareOpInterfaceMethods<VerifyRegionInterface>]> { 342 let summary = "Define a region of an operation"; 343 let description = [{ 344 The irdl.region construct defines a set of characteristics 345 that a region of an operation should satify. Each region is named after 346 an identifier. 347 348 These characteristics include constraints for the entry block arguments 349 of the region and the total number of blocks it contains. 350 The number of blocks must be a non-zero and non-negative integer, 351 and it is optional by default. 352 The set of constraints for the entry block arguments may be optional or 353 empty. If no parentheses are provided, the set is assumed to be optional, 354 and the arguments are not constrained in any way. If parentheses are 355 provided with no arguments, it means that the region must have 356 no entry block arguments 357 358 359 Example: 360 361 ```mlir 362 irdl.dialect @example { 363 irdl.operation @op_with_regions { 364 %r0 = irdl.region 365 %r1 = irdl.region() 366 %v0 = irdl.is i32 367 %v1 = irdl.is i64 368 %r2 = irdl.region(%v0, %v1) 369 %r3 = irdl.region with size 3 370 371 irdl.regions(foo: %r0, bar: %r1, baz: %r2, qux: %r3) 372 } 373 } 374 ``` 375 376 The above snippet demonstrates an operation named `@op_with_regions`, 377 which is constrained to have four regions. 378 379 * Region `foo` doesn't have any constraints on the arguments 380 or the number of blocks. 381 * Region `bar` should have an empty set of arguments. 382 * Region `baz` should have two arguments of types `i32` and `i64`. 383 * Region `qux` should contain exactly three blocks. 384 }]; 385 let arguments = (ins Variadic<IRDL_AttributeType>:$entryBlockArgs, 386 OptionalAttr<I32Attr>:$numberOfBlocks, 387 UnitAttr:$constrainedArguments); 388 let results = (outs IRDL_RegionType:$output); 389 390 let assemblyFormat = [{ 391 ``(`(` $entryBlockArgs $constrainedArguments^ `)`)? 392 ``(` ` `with` `size` $numberOfBlocks^)? attr-dict 393 }]; 394 395 let hasVerifier = true; 396} 397 398def IRDL_RegionsOp : IRDL_Op<"regions", [HasParent<"OperationOp">]> { 399 let summary = "Define the regions of an operation"; 400 let description = [{ 401 `irdl.regions` defines the regions of an operation by accepting 402 values produced by `irdl.region` operation as arguments. Each 403 region has an identifier as name. 404 405 Example: 406 407 ```mlir 408 irdl.dialect @example { 409 irdl.operation @op_with_regions { 410 %r1 = irdl.region with size 3 411 %0 = irdl.any 412 %r2 = irdl.region(%0) 413 irdl.regions(foo: %r1, bar: %r2) 414 } 415 } 416 ``` 417 418 In the snippet above the operation is constrained to have two regions. 419 The first region (`foo`) should contain three blocks. 420 The second region (`bar`) should have one region with one argument. 421 }]; 422 423 let arguments = (ins Variadic<IRDL_RegionType>:$args, StrArrayAttr:$names); 424 let assemblyFormat = " `` custom<NamedValueList>($args, $names) attr-dict "; 425 let hasVerifier = true; 426} 427 428//===----------------------------------------------------------------------===// 429// IRDL Constraint operations 430//===----------------------------------------------------------------------===// 431 432class IRDL_ConstraintOp<string mnemonic, list<Trait> traits = []> 433 : IRDL_Op<mnemonic, [VerifyConstraintInterface, 434 DeclareOpInterfaceMethods<VerifyConstraintInterface>] # traits> { 435} 436 437def IRDL_IsOp : IRDL_ConstraintOp<"is", 438 [ParentOneOf<["TypeOp", "AttributeOp", "OperationOp"]>, Pure]> { 439 let summary = "Constraints an attribute/type to be a specific attribute instance"; 440 let description = [{ 441 `irdl.is` defines a constraint that only accepts a specific instance of a 442 type or attribute. 443 444 Example: 445 446 ```mlir 447 irdl.dialect @cmath { 448 irdl.type @complex_i32 { 449 %0 = irdl.is i32 450 irdl.parameters(%0) 451 } 452 } 453 ``` 454 455 The above program defines a `complex_i32` type inside the dialect `cmath` 456 that can only have a `i32` as its parameter. 457 }]; 458 459 let arguments = (ins AnyAttr:$expected); 460 let results = (outs IRDL_AttributeType:$output); 461 let assemblyFormat = " $expected ` ` attr-dict "; 462} 463 464def IRDL_BaseOp : IRDL_ConstraintOp<"base", 465 [ParentOneOf<["TypeOp", "AttributeOp", "OperationOp"]>, 466 DeclareOpInterfaceMethods<SymbolUserOpInterface>]> { 467 let summary = "Constraints an attribute/type base"; 468 let description = [{ 469 `irdl.base` defines a constraint that only accepts a single type 470 or attribute base, e.g. an `IntegerType`. The attribute base is defined 471 either by a symbolic reference to the corresponding IRDL definition, 472 or by the name of the base. Named bases are prefixed with `!` or `#` 473 respectively for types and attributes. 474 475 Example: 476 477 ```mlir 478 irdl.dialect @cmath { 479 irdl.type @complex { 480 %0 = irdl.base "!builtin.integer" 481 irdl.parameters(%0) 482 } 483 484 irdl.type @complex_wrapper { 485 %0 = irdl.base @cmath::@complex 486 irdl.parameters(%0) 487 } 488 } 489 ``` 490 491 The above program defines a `cmath.complex` type that expects a single 492 parameter, which is a type with base name `builtin.integer`, which is the 493 name of an `IntegerType` type. 494 It also defines a `cmath.complex_wrapper` type that expects a single 495 parameter, which is a type of base type `cmath.complex`. 496 }]; 497 498 let arguments = (ins OptionalAttr<SymbolRefAttr>:$base_ref, 499 OptionalAttr<StrAttr>:$base_name); 500 let results = (outs IRDL_AttributeType:$output); 501 let assemblyFormat = " ($base_ref^)? ($base_name^)? ` ` attr-dict"; 502 503 let builders = [ 504 OpBuilder<(ins "SymbolRefAttr":$base_ref), [{ 505 build($_builder, $_state, base_ref, {}); 506 }]>, 507 OpBuilder<(ins "StringAttr":$base_name), [{ 508 build($_builder, $_state, {}, base_name); 509 }]>, 510 ]; 511 512 let hasVerifier = 1; 513} 514 515def IRDL_ParametricOp : IRDL_ConstraintOp<"parametric", 516 [ParentOneOf<["TypeOp", "AttributeOp", "OperationOp"]>, 517 DeclareOpInterfaceMethods<SymbolUserOpInterface>, Pure]> { 518 let summary = "Constraints an attribute/type base and its parameters"; 519 let description = [{ 520 `irdl.parametric` defines a constraint that accepts only a single type 521 or attribute base. The attribute base is defined by a symbolic reference 522 to the corresponding definition. It will additionally constraint the 523 parameters of the type/attribute. 524 525 Example: 526 527 ```mlir 528 irdl.dialect @cmath { 529 530 irdl.type @complex { /* ... */ } 531 532 irdl.operation @norm { 533 %0 = irdl.any 534 %1 = irdl.parametric @cmath::@complex<%0> 535 irdl.operands(%1) 536 irdl.results(%0) 537 } 538 } 539 ``` 540 541 The above program defines an operation `norm` inside the dialect `cmath` that 542 for any `T` takes a `cmath.complex` with parameter `T` and returns a `T`. 543 }]; 544 545 let arguments = (ins SymbolRefAttr:$base_type, 546 Variadic<IRDL_AttributeType>:$args); 547 let results = (outs IRDL_AttributeType:$output); 548 let assemblyFormat = " $base_type `<` $args `>` ` ` attr-dict "; 549} 550 551def IRDL_AnyOp : IRDL_ConstraintOp<"any", 552 [ParentOneOf<["TypeOp", "AttributeOp", "OperationOp"]>]> { 553 let summary = "Accept any type or attribute"; 554 let description = [{ 555 `irdl.any` defines a constraint that accepts any type or attribute. 556 557 Example: 558 559 ```mlir 560 irdl.dialect @cmath { 561 irdl.type @complex_flexible { 562 %0 = irdl.any 563 irdl.parameters(%0) 564 } 565 } 566 ``` 567 568 The above program defines a type `complex_flexible` inside the dialect 569 `cmath` that has a single parameter that can be any attribute. 570 }]; 571 572 let results = (outs IRDL_AttributeType:$output); 573 let assemblyFormat = " attr-dict "; 574} 575 576def IRDL_AnyOfOp : IRDL_ConstraintOp<"any_of", 577 [ParentOneOf<["TypeOp", "AttributeOp", "OperationOp"]>, 578 SameOperandsAndResultType]> { 579 let summary = "Constraints to the union of the provided constraints"; 580 let description = [{ 581 `irdl.any_of` defines a constraint that accepts any type or attribute that 582 satisfies at least one of its provided type constraints. 583 584 Example: 585 586 ```mlir 587 irdl.dialect @cmath { 588 irdl.type @complex { 589 %0 = irdl.is i32 590 %1 = irdl.is i64 591 %2 = irdl.is f32 592 %3 = irdl.is f64 593 %4 = irdl.any_of(%0, %1, %2, %3) 594 irdl.parameters(%4) 595 } 596 } 597 ``` 598 599 The above program defines a type `complex` inside the dialect `cmath` that 600 can have a single type parameter that can be either `i32`, `i64`, `f32` or 601 `f64`. 602 }]; 603 604 let arguments = (ins Variadic<IRDL_AttributeType>:$args); 605 let results = (outs IRDL_AttributeType:$output); 606 let assemblyFormat = [{ `(` $args `)` ` ` attr-dict }]; 607} 608 609def IRDL_AllOfOp : IRDL_ConstraintOp<"all_of", 610 [ParentOneOf<["TypeOp", "AttributeOp", "OperationOp"]>, 611 SameOperandsAndResultType]> { 612 let summary = "Constraints to the intersection of the provided constraints"; 613 let description = [{ 614 `irdl.all_of` defines a constraint that accepts any type or attribute that 615 satisfies all of its provided constraints. 616 617 Example: 618 619 ```mlir 620 irdl.dialect @cmath { 621 irdl.type @complex_f32 { 622 %0 = irdl.is i32 623 %1 = irdl.is f32 624 %2 = irdl.any_of(%0, %1) // is 32-bit 625 626 %3 = irdl.is f32 627 %4 = irdl.is f64 628 %5 = irdl.any_of(%3, %4) // is a float 629 630 %6 = irdl.all_of(%2, %5) // is a 32-bit float 631 irdl.parameters(%6) 632 } 633 } 634 ``` 635 636 The above program defines a type `complex` inside the dialect `cmath` that 637 can has one parameter that must be 32-bit long and a float (in other 638 words, that must be `f32`). 639 }]; 640 641 let arguments = (ins Variadic<IRDL_AttributeType>:$args); 642 let results = (outs IRDL_AttributeType:$output); 643 let assemblyFormat = [{ `(` $args `)` ` ` attr-dict }]; 644} 645 646def IRDL_CPredOp : IRDL_Op<"c_pred"> { 647 let summary = "Constraints an attribute using a C++ predicate"; 648 let description = [{ 649 `irdl.c_pred` defines a constraint that is written in C++. 650 651 Dialects using this operation cannot be registered at runtime, as it relies 652 on C++ code. 653 654 Special placeholders can be used to refer to entities in the context where 655 this predicate is used. They serve as "hooks" to the enclosing environment. 656 The following special placeholders are supported in constraints for an op: 657 658 * `$_builder` will be replaced by a mlir::Builder instance. 659 * `$_op` will be replaced by the current operation. 660 * `$_self` will be replaced with the entity this predicate is attached to. 661 Compared to ODS, `$_self` is always of type `mlir::Attribute`, and types 662 are manipulated as `TypeAttr` attributes. 663 664 Example: 665 ```mlir 666 irdl.type @op_with_attr { 667 %0 = irdl.c_pred "::llvm::isa<::mlir::IntegerAttr>($_self)" 668 irdl.parameters(%0) 669 } 670 ``` 671 672 In this example, @op_with_attr is defined as a type with a single 673 parameter, which is an `IntegerAttr`, as constrained by the C++ predicate. 674 }]; 675 676 let arguments = (ins StrAttr:$pred); 677 let results = (outs IRDL_AttributeType:$output); 678 let assemblyFormat = "$pred ` ` attr-dict"; 679} 680 681#endif // MLIR_DIALECT_IRDL_IR_IRDLOPS 682