xref: /llvm-project/mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td (revision 69d3ba3db922fca8cfc47b5f115b6bea6a737aab)
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