xref: /llvm-project/mlir/include/mlir/Dialect/PDLInterp/IR/PDLInterpOps.td (revision 8ec28af8eaff5acd0df3e53340159c034f08533d)
1//===- PDLInterpOps.td - Pattern Interpreter 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 PDL interpreter dialect ops.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef MLIR_DIALECT_PDLINTERP_IR_PDLINTERPOPS
14#define MLIR_DIALECT_PDLINTERP_IR_PDLINTERPOPS
15
16include "mlir/Dialect/PDL/IR/PDLTypes.td"
17include "mlir/Interfaces/FunctionInterfaces.td"
18include "mlir/IR/SymbolInterfaces.td"
19include "mlir/Interfaces/SideEffectInterfaces.td"
20
21//===----------------------------------------------------------------------===//
22// PDLInterp Dialect
23//===----------------------------------------------------------------------===//
24
25def PDLInterp_Dialect : Dialect {
26  let summary = "Interpreted pattern execution dialect";
27  let description = [{
28    The PDL Interpreter dialect provides a lower level abstraction compared to
29    the PDL dialect, and is targeted towards low level optimization and
30    interpreter code generation. The dialect operations encapsulates
31    low-level pattern match and rewrite "primitives", such as navigating the
32    IR (Operation::getOperand), creating new operations (OpBuilder::create),
33    etc. Many of the operations within this dialect also fuse branching control
34    flow with some form of a predicate comparison operation. This type of fusion
35    reduces the amount of work that an interpreter must do when executing.
36  }];
37
38  let name = "pdl_interp";
39  let cppNamespace = "::mlir::pdl_interp";
40  let dependentDialects = ["pdl::PDLDialect"];
41  let extraClassDeclaration = [{
42    /// Returns the name of the function containing the matcher code. This
43    /// function is called by the interpreter when matching an operation.
44    static StringRef getMatcherFunctionName() { return "matcher"; }
45
46    /// Returns the name of the module containing the rewrite functions. These
47    /// functions are invoked by distinct patterns within the matcher function
48    /// to rewrite the IR after a successful match.
49    static StringRef getRewriterModuleName() { return "rewriters"; }
50  }];
51}
52
53//===----------------------------------------------------------------------===//
54// PDLInterp Operations
55//===----------------------------------------------------------------------===//
56
57// Generic interpreter operation.
58class PDLInterp_Op<string mnemonic, list<Trait> traits = []> :
59    Op<PDLInterp_Dialect, mnemonic, traits>;
60
61//===----------------------------------------------------------------------===//
62// PDLInterp_PredicateOp
63
64// Check operations evaluate a predicate on a positional value and then
65// conditionally branch on the result.
66class PDLInterp_PredicateOp<string mnemonic, list<Trait> traits = []> :
67    PDLInterp_Op<mnemonic, !listconcat([Terminator], traits)> {
68  let successors = (successor AnySuccessor:$trueDest, AnySuccessor:$falseDest);
69}
70
71//===----------------------------------------------------------------------===//
72// PDLInterp_SwitchOp
73
74// Switch operations evaluate a predicate on a positional value and then
75// conditionally branch on the result.
76class PDLInterp_SwitchOp<string mnemonic, list<Trait> traits = []> :
77    PDLInterp_Op<mnemonic, !listconcat([Terminator], traits)> {
78  let successors = (successor AnySuccessor:$defaultDest,
79                              VariadicSuccessor<AnySuccessor>:$cases);
80}
81
82//===----------------------------------------------------------------------===//
83// pdl_interp::ApplyConstraintOp
84//===----------------------------------------------------------------------===//
85
86def PDLInterp_ApplyConstraintOp : PDLInterp_PredicateOp<"apply_constraint"> {
87  let summary = "Apply a constraint to a set of positional values";
88  let description = [{
89    `pdl_interp.apply_constraint` operations apply a generic constraint, that
90    has been registered with the interpreter, with a given set of positional
91    values.
92    The constraint function may return any number of results.
93    On success, this operation branches to the true destination,
94    otherwise the false destination is taken. This behavior can be reversed
95    by setting the attribute `isNegated` to true.
96
97    Example:
98
99    ```mlir
100    // Apply `myConstraint` to the entities defined by `input`, `attr`, and
101    // `op`.
102    pdl_interp.apply_constraint "myConstraint"(%input, %attr, %op : !pdl.value, !pdl.attribute, !pdl.operation) -> ^matchDest, ^failureDest
103    ```
104  }];
105
106  let arguments = (ins StrAttr:$name,
107                       Variadic<PDL_AnyType>:$args,
108                       DefaultValuedAttr<BoolAttr, "false">:$isNegated);
109  let results = (outs Variadic<PDL_AnyType>:$results);
110  let assemblyFormat = [{
111    $name `(` $args `:` type($args) `)` (`:` type($results)^)? attr-dict
112    `->` successors
113  }];
114}
115
116//===----------------------------------------------------------------------===//
117// pdl_interp::ApplyRewriteOp
118//===----------------------------------------------------------------------===//
119
120def PDLInterp_ApplyRewriteOp : PDLInterp_Op<"apply_rewrite"> {
121  let summary = "Invoke and apply an externally registered rewrite method";
122  let description = [{
123    `pdl_interp.apply_rewrite` operations invoke an external rewriter that has
124    been registered with the interpreter to perform the rewrite after a
125    successful match. The rewrite is passed a set of positional arguments. The
126    rewrite function may return any number of results.
127
128    Example:
129
130    ```mlir
131    // Rewriter operating solely on the root operation.
132    pdl_interp.apply_rewrite "rewriter"(%root : !pdl.operation)
133
134    // Rewriter operating solely on the root operation and return an attribute.
135    %attr = pdl_interp.apply_rewrite "rewriter"(%root : !pdl.operation) : !pdl.attribute
136
137    // Rewriter operating on the root operation along with additional arguments
138    // from the matcher.
139    pdl_interp.apply_rewrite "rewriter"(%root : !pdl.operation, %value : !pdl.value)
140    ```
141  }];
142  let arguments = (ins StrAttr:$name, Variadic<PDL_AnyType>:$args);
143  let results = (outs Variadic<PDL_AnyType>:$results);
144  let assemblyFormat = [{
145    $name (`(` $args^ `:` type($args) `)`)? (`:` type($results)^)? attr-dict
146  }];
147}
148
149//===----------------------------------------------------------------------===//
150// pdl_interp::AreEqualOp
151//===----------------------------------------------------------------------===//
152
153def PDLInterp_AreEqualOp
154    : PDLInterp_PredicateOp<"are_equal", [Pure, SameTypeOperands]> {
155  let summary = "Check if two positional values or ranges are equivalent";
156  let description = [{
157    `pdl_interp.are_equal` operations compare two positional values for
158    equality. On success, this operation branches to the true destination,
159    otherwise the false destination is taken.
160
161    Example:
162
163    ```mlir
164    pdl_interp.are_equal %result1, %result2 : !pdl.value -> ^matchDest, ^failureDest
165    ```
166  }];
167
168  let arguments = (ins PDL_AnyType:$lhs, PDL_AnyType:$rhs);
169  let assemblyFormat = "operands `:` type($lhs) attr-dict `->` successors";
170}
171
172//===----------------------------------------------------------------------===//
173// pdl_interp::BranchOp
174//===----------------------------------------------------------------------===//
175
176def PDLInterp_BranchOp : PDLInterp_Op<"branch", [Pure, Terminator]> {
177  let summary = "General branch operation";
178  let description = [{
179    `pdl_interp.branch` operations expose general branch functionality to the
180    interpreter, and are generally used to branch from one pattern match
181    sequence to another.
182
183    Example:
184
185    ```mlir
186    pdl_interp.branch ^dest
187    ```
188  }];
189
190  let successors = (successor AnySuccessor:$dest);
191  let assemblyFormat = "$dest attr-dict";
192}
193
194//===----------------------------------------------------------------------===//
195// pdl_interp::CheckAttributeOp
196//===----------------------------------------------------------------------===//
197
198def PDLInterp_CheckAttributeOp
199    : PDLInterp_PredicateOp<"check_attribute", [Pure]> {
200  let summary = "Check the value of an `Attribute`";
201  let description = [{
202    `pdl_interp.check_attribute` operations compare the value of a given
203    attribute with a constant value. On success, this operation branches to the
204    true destination, otherwise the false destination is taken.
205
206    Example:
207
208    ```mlir
209    pdl_interp.check_attribute %attr is 10 -> ^matchDest, ^failureDest
210    ```
211  }];
212
213  let arguments = (ins PDL_Attribute:$attribute, AnyAttr:$constantValue);
214  let assemblyFormat = [{
215    $attribute `is` $constantValue attr-dict `->` successors
216  }];
217}
218
219//===----------------------------------------------------------------------===//
220// pdl_interp::CheckOperandCountOp
221//===----------------------------------------------------------------------===//
222
223def PDLInterp_CheckOperandCountOp
224    : PDLInterp_PredicateOp<"check_operand_count", [Pure]> {
225  let summary = "Check the number of operands of an `Operation`";
226  let description = [{
227    `pdl_interp.check_operand_count` operations compare the number of operands
228    of a given operation value with a constant. The comparison is either exact
229    or at_least, with the latter used to compare against a minimum number of
230    expected operands. On success, this operation branches to the true
231    destination, otherwise the false destination is taken.
232
233    Example:
234
235    ```mlir
236    // Check for exact equality.
237    pdl_interp.check_operand_count of %op is 2 -> ^matchDest, ^failureDest
238
239    // Check for at least N operands.
240    pdl_interp.check_operand_count of %op is at_least 2 -> ^matchDest, ^failureDest
241    ```
242  }];
243
244  let arguments = (ins PDL_Operation:$inputOp,
245                       ConfinedAttr<I32Attr, [IntNonNegative]>:$count,
246                       UnitAttr:$compareAtLeast);
247  let assemblyFormat = [{
248    `of` $inputOp `is` (`at_least` $compareAtLeast^)? $count attr-dict
249    `->` successors
250  }];
251}
252
253//===----------------------------------------------------------------------===//
254// pdl_interp::CheckOperationNameOp
255//===----------------------------------------------------------------------===//
256
257def PDLInterp_CheckOperationNameOp
258    : PDLInterp_PredicateOp<"check_operation_name", [Pure]> {
259  let summary = "Check the OperationName of an `Operation`";
260  let description = [{
261    `pdl_interp.check_operation_name` operations compare the name of a given
262    operation with a known name. On success, this operation branches to the true
263    destination, otherwise the false destination is taken.
264
265    Example:
266
267    ```mlir
268    pdl_interp.check_operation_name of %op is "foo.op" -> ^matchDest, ^failureDest
269    ```
270  }];
271
272  let arguments = (ins PDL_Operation:$inputOp, StrAttr:$name);
273  let assemblyFormat = "`of` $inputOp `is` $name attr-dict `->` successors";
274}
275
276//===----------------------------------------------------------------------===//
277// pdl_interp::CheckResultCountOp
278//===----------------------------------------------------------------------===//
279
280def PDLInterp_CheckResultCountOp
281    : PDLInterp_PredicateOp<"check_result_count", [Pure]> {
282  let summary = "Check the number of results of an `Operation`";
283  let description = [{
284    `pdl_interp.check_result_count` operations compare the number of results
285    of a given operation value with a constant. The comparison is either exact
286    or at_least, with the latter used to compare against a minimum number of
287    expected results. On success, this operation branches to the true
288    destination, otherwise the false destination is taken.
289
290    Example:
291
292    ```mlir
293    // Check for exact equality.
294    pdl_interp.check_result_count of %op is 2 -> ^matchDest, ^failureDest
295
296    // Check for at least N results.
297    pdl_interp.check_result_count of %op is at_least 2 -> ^matchDest, ^failureDest
298    ```
299  }];
300
301  let arguments = (ins PDL_Operation:$inputOp,
302                       ConfinedAttr<I32Attr, [IntNonNegative]>:$count,
303                       UnitAttr:$compareAtLeast);
304  let assemblyFormat = [{
305    `of` $inputOp `is` (`at_least` $compareAtLeast^)? $count attr-dict
306    `->` successors
307  }];
308}
309
310//===----------------------------------------------------------------------===//
311// pdl_interp::CheckTypeOp
312//===----------------------------------------------------------------------===//
313
314def PDLInterp_CheckTypeOp
315    : PDLInterp_PredicateOp<"check_type", [Pure]> {
316  let summary = "Compare a type to a known value";
317  let description = [{
318    `pdl_interp.check_type` operations compare a type with a statically known
319    type. On success, this operation branches to the true destination, otherwise
320    the false destination is taken.
321
322    Example:
323
324    ```mlir
325    pdl_interp.check_type %type is i32 -> ^matchDest, ^failureDest
326    ```
327  }];
328
329  let arguments = (ins PDL_Type:$value, TypeAttr:$type);
330  let assemblyFormat = "$value `is` $type attr-dict `->` successors";
331}
332
333//===----------------------------------------------------------------------===//
334// pdl_interp::CheckTypesOp
335//===----------------------------------------------------------------------===//
336
337def PDLInterp_CheckTypesOp
338    : PDLInterp_PredicateOp<"check_types", [Pure]> {
339  let summary = "Compare a range of types to a range of known values";
340  let description = [{
341    `pdl_interp.check_types` operations compare a range of types with a
342    statically known range of types. On success, this operation branches
343    to the true destination, otherwise the false destination is taken.
344
345    Example:
346
347    ```mlir
348    pdl_interp.check_types %type are [i32, i64] -> ^matchDest, ^failureDest
349    ```
350  }];
351
352  let arguments = (ins PDL_RangeOf<PDL_Type>:$value,
353                       TypeArrayAttr:$types);
354  let assemblyFormat = "$value `are` $types attr-dict `->` successors";
355}
356
357//===----------------------------------------------------------------------===//
358// pdl_interp::ContinueOp
359//===----------------------------------------------------------------------===//
360
361def PDLInterp_ContinueOp
362    : PDLInterp_Op<"continue", [Pure, HasParent<"ForEachOp">,
363                               Terminator]> {
364  let summary = "Breaks the current iteration";
365  let description = [{
366    `pdl_interp.continue` operation breaks the current iteration within the
367    `pdl_interp.foreach` region and continues with the next iteration from
368    the beginning of the region.
369
370    Example:
371
372    ```mlir
373    pdl_interp.continue
374    ```
375  }];
376
377  let assemblyFormat = "attr-dict";
378}
379
380//===----------------------------------------------------------------------===//
381// pdl_interp::CreateAttributeOp
382//===----------------------------------------------------------------------===//
383
384def PDLInterp_CreateAttributeOp
385    : PDLInterp_Op<"create_attribute", [Pure]> {
386  let summary = "Create an interpreter handle to a constant `Attribute`";
387  let description = [{
388    `pdl_interp.create_attribute` operations generate a handle within the
389    interpreter for a specific constant attribute value.
390
391    Example:
392
393    ```mlir
394    %attr = pdl_interp.create_attribute 10 : i64
395    ```
396  }];
397
398  let arguments = (ins AnyAttr:$value);
399  let results = (outs PDL_Attribute:$attribute);
400  let assemblyFormat = "$value attr-dict-with-keyword";
401
402  let builders = [
403    OpBuilder<(ins "Attribute":$value), [{
404      build($_builder, $_state, $_builder.getType<pdl::AttributeType>(), value);
405    }]>];
406}
407
408//===----------------------------------------------------------------------===//
409// pdl_interp::CreateOperationOp
410//===----------------------------------------------------------------------===//
411
412def PDLInterp_CreateOperationOp
413    : PDLInterp_Op<"create_operation", [AttrSizedOperandSegments]> {
414  let summary = "Create an instance of a specific `Operation`";
415  let description = [{
416    `pdl_interp.create_operation` operations create an `Operation` instance with
417    the specified attributes, operands, and result types. See `pdl.operation`
418    for a more detailed description on the general interpretation of the arguments
419    to this operation.
420
421    Example:
422
423    ```mlir
424    // Create an instance of a `foo.op` operation.
425    %op = pdl_interp.create_operation "foo.op"(%arg0 : !pdl.value) {"attrA" = %attr0} -> (%type : !pdl.type)
426
427    // Create an instance of a `foo.op` operation that has inferred result types
428    // (using the InferTypeOpInterface).
429    %op = pdl_interp.create_operation "foo.op"(%arg0 : !pdl.value) {"attrA" = %attr0} -> <inferred>
430    ```
431  }];
432
433  let arguments = (ins StrAttr:$name,
434                       Variadic<PDL_InstOrRangeOf<PDL_Value>>:$inputOperands,
435                       Variadic<PDL_Attribute>:$inputAttributes,
436                       StrArrayAttr:$inputAttributeNames,
437                       Variadic<PDL_InstOrRangeOf<PDL_Type>>:$inputResultTypes,
438                       UnitAttr:$inferredResultTypes);
439  let results = (outs PDL_Operation:$resultOp);
440
441  let builders = [
442    OpBuilder<(ins "StringRef":$name, "ValueRange":$types,
443      "bool":$inferredResultTypes, "ValueRange":$operands,
444      "ValueRange":$attributes, "ArrayAttr":$attributeNames), [{
445      build($_builder, $_state, $_builder.getType<pdl::OperationType>(), name,
446            operands, attributes, attributeNames, types, inferredResultTypes);
447    }]>
448  ];
449  let assemblyFormat = [{
450    $name (`(` $inputOperands^ `:` type($inputOperands) `)`)? ``
451    custom<CreateOperationOpAttributes>($inputAttributes, $inputAttributeNames)
452    custom<CreateOperationOpResults>($inputResultTypes, type($inputResultTypes),
453                                     $inferredResultTypes)
454    attr-dict
455  }];
456  let hasVerifier = 1;
457}
458
459//===----------------------------------------------------------------------===//
460// pdl_interp::CreateTypeOp
461//===----------------------------------------------------------------------===//
462
463def PDLInterp_CreateTypeOp : PDLInterp_Op<"create_type", [Pure]> {
464  let summary = "Create an interpreter handle to a constant `Type`";
465  let description = [{
466    `pdl_interp.create_type` operations generate a handle within the interpreter
467    for a specific constant type value.
468
469    Example:
470
471    ```mlir
472    pdl_interp.create_type i64
473    ```
474  }];
475
476  let arguments = (ins TypeAttr:$value);
477  let results = (outs PDL_Type:$result);
478  let assemblyFormat = "$value attr-dict";
479
480  let builders = [
481    OpBuilder<(ins "TypeAttr":$type), [{
482      build($_builder, $_state, $_builder.getType<pdl::TypeType>(), type);
483    }]>
484  ];
485}
486
487//===----------------------------------------------------------------------===//
488// pdl_interp::CreateTypesOp
489//===----------------------------------------------------------------------===//
490
491def PDLInterp_CreateTypesOp : PDLInterp_Op<"create_types", [Pure]> {
492  let summary = "Create an interpreter handle to a range of constant `Type`s";
493  let description = [{
494    `pdl_interp.create_types` operations generate a handle within the
495    interpreter for a specific range of constant type values.
496
497    Example:
498
499    ```mlir
500    pdl_interp.create_types [i64, i64]
501    ```
502  }];
503
504  let arguments = (ins TypeArrayAttr:$value);
505  let results = (outs PDL_RangeOf<PDL_Type>:$result);
506  let assemblyFormat = "$value attr-dict";
507
508  let builders = [
509    OpBuilder<(ins "ArrayAttr":$type), [{
510      build($_builder, $_state,
511            pdl::RangeType::get($_builder.getType<pdl::TypeType>()), type);
512    }]>
513  ];
514}
515
516//===----------------------------------------------------------------------===//
517// pdl_interp::EraseOp
518//===----------------------------------------------------------------------===//
519
520def PDLInterp_EraseOp : PDLInterp_Op<"erase"> {
521  let summary = "Mark an operation as `erased`";
522  let description = [{
523    `pdl.erase` operations are used to specify that an operation should be
524    marked as erased. The semantics of this operation correspond with the
525    `eraseOp` method on a `PatternRewriter`.
526
527    Example:
528
529    ```mlir
530    pdl_interp.erase %root
531    ```
532  }];
533
534  let arguments = (ins PDL_Operation:$inputOp);
535  let assemblyFormat = "$inputOp attr-dict";
536}
537
538//===----------------------------------------------------------------------===//
539// pdl_interp::ExtractOp
540//===----------------------------------------------------------------------===//
541
542def PDLInterp_ExtractOp
543    : PDLInterp_Op<"extract", [Pure,
544     TypesMatchWith<
545        "`range` is a PDL range whose element type matches type of `result`",
546        "result", "range", "pdl::RangeType::get($_self)">]> {
547  let summary = "Extract the item at the specified index in a range";
548  let description = [{
549    `pdl_interp.extract` operations are used to extract an item from a range
550    at the specified index. If the index is out of range, returns null.
551
552    Example:
553
554    ```mlir
555    // Extract the value at index 1 from a range of values.
556    %ops = pdl_interp.extract 1 of %values : !pdl.value
557    ```
558  }];
559
560  let arguments = (ins PDL_RangeOf<PDL_AnyType>:$range,
561                       ConfinedAttr<I32Attr, [IntNonNegative]>:$index);
562  let results = (outs PDL_AnyType:$result);
563  let assemblyFormat = "$index `of` $range `:` type($result) attr-dict";
564
565  let builders = [
566    OpBuilder<(ins "Value":$range, "unsigned":$index), [{
567      build($_builder, $_state,
568            ::llvm::cast<pdl::RangeType>(range.getType()).getElementType(),
569            range, index);
570    }]>,
571  ];
572}
573
574//===----------------------------------------------------------------------===//
575// pdl_interp::FinalizeOp
576//===----------------------------------------------------------------------===//
577
578def PDLInterp_FinalizeOp
579    : PDLInterp_Op<"finalize", [Pure, Terminator]> {
580  let summary = "Finalize a pattern match or rewrite sequence";
581  let description = [{
582    `pdl_interp.finalize` is used to denote the termination of a match or
583    rewrite sequence.
584
585    Example:
586
587    ```mlir
588    pdl_interp.finalize
589    ```
590  }];
591  let assemblyFormat = "attr-dict";
592}
593
594//===----------------------------------------------------------------------===//
595// pdl_interp::ForEachOp
596//===----------------------------------------------------------------------===//
597
598def PDLInterp_ForEachOp
599    : PDLInterp_Op<"foreach", [Terminator]> {
600  let summary = "Iterates over a range of values or ranges";
601  let description = [{
602    `pdl_interp.foreach` iteratively selects an element from a range of values
603    and executes the region until pdl.continue is reached.
604
605    In the bytecode interpreter, this operation is implemented by looping over
606    the values and, for each selection, running the bytecode until we reach
607    pdl.continue. This may result in multiple matches being reported. Note
608    that the input range is mutated (popped from).
609
610    Example:
611
612    ```mlir
613    pdl_interp.foreach %op : !pdl.operation in %ops {
614      pdl_interp.continue
615    } -> ^next
616    ```
617  }];
618
619  let arguments = (ins PDL_RangeOf<PDL_AnyType>:$values);
620  let regions = (region AnyRegion:$region);
621  let successors = (successor AnySuccessor:$successor);
622
623  let builders = [
624    OpBuilder<(ins "Value":$range, "Block *":$successor, "bool":$initLoop)>
625  ];
626
627  let extraClassDeclaration = [{
628    /// Returns the loop variable.
629    BlockArgument getLoopVariable() { return getRegion().getArgument(0); }
630  }];
631  let hasCustomAssemblyFormat = 1;
632  let hasVerifier = 1;
633}
634
635//===----------------------------------------------------------------------===//
636// pdl_interp::FuncOp
637//===----------------------------------------------------------------------===//
638
639def PDLInterp_FuncOp : PDLInterp_Op<"func", [
640    FunctionOpInterface, IsolatedFromAbove
641  ]> {
642  let summary = "PDL Interpreter Function Operation";
643  let description = [{
644    `pdl_interp.func` operations act as interpreter functions. These are
645    callable SSA-region operations that contain other interpreter operations.
646    Interpreter functions are used for both the matching and the rewriting
647    portion of the interpreter.
648
649    Example:
650
651    ```mlir
652    pdl_interp.func @rewriter(%root: !pdl.operation) {
653      %op = pdl_interp.create_operation "foo.new_operation"
654      pdl_interp.erase %root
655      pdl_interp.finalize
656    }
657    ```
658  }];
659
660  let arguments = (ins
661    SymbolNameAttr:$sym_name,
662    TypeAttrOf<FunctionType>:$function_type,
663    OptionalAttr<DictArrayAttr>:$arg_attrs,
664    OptionalAttr<DictArrayAttr>:$res_attrs
665  );
666  let regions = (region MinSizedRegion<1>:$body);
667
668  // Create the function with the given name and type. This also automatically
669  // inserts the entry block for the function.
670  let builders = [OpBuilder<(ins
671    "StringRef":$name, "FunctionType":$type,
672    CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)
673  >];
674  let extraClassDeclaration = [{
675    //===------------------------------------------------------------------===//
676    // FunctionOpInterface Methods
677    //===------------------------------------------------------------------===//
678
679    /// Returns the argument types of this function.
680    ArrayRef<Type> getArgumentTypes() { return getFunctionType().getInputs(); }
681
682    /// Returns the result types of this function.
683    ArrayRef<Type> getResultTypes() { return getFunctionType().getResults(); }
684
685    Region *getCallableRegion() { return &getBody(); }
686  }];
687  let hasCustomAssemblyFormat = 1;
688  let skipDefaultBuilders = 1;
689}
690
691//===----------------------------------------------------------------------===//
692// pdl_interp::GetAttributeOp
693//===----------------------------------------------------------------------===//
694
695def PDLInterp_GetAttributeOp : PDLInterp_Op<"get_attribute", [Pure]> {
696  let summary = "Get a specified attribute value from an `Operation`";
697  let description = [{
698    `pdl_interp.get_attribute` operations try to get a specific attribute from
699    an operation. If the operation does not have that attribute, a null value is
700    returned.
701
702    Example:
703
704    ```mlir
705    %attr = pdl_interp.get_attribute "attr" of %op
706    ```
707  }];
708
709  let arguments = (ins PDL_Operation:$inputOp, StrAttr:$name);
710  let results = (outs PDL_Attribute:$attribute);
711  let assemblyFormat = "$name `of` $inputOp attr-dict";
712}
713
714//===----------------------------------------------------------------------===//
715// pdl_interp::GetAttributeTypeOp
716//===----------------------------------------------------------------------===//
717
718def PDLInterp_GetAttributeTypeOp
719    : PDLInterp_Op<"get_attribute_type", [Pure]> {
720  let summary = "Get the result type of a specified `Attribute`";
721  let description = [{
722    `pdl_interp.get_attribute_type` operations get the resulting type of a
723    specific attribute.
724
725    Example:
726
727    ```mlir
728    %type = pdl_interp.get_attribute_type of %attr
729    ```
730  }];
731
732  let arguments = (ins PDL_Attribute:$value);
733  let results = (outs PDL_Type:$result);
734  let assemblyFormat = "`of` $value attr-dict";
735
736  let builders = [
737    OpBuilder<(ins "Value":$value), [{
738      build($_builder, $_state, $_builder.getType<pdl::TypeType>(), value);
739    }]>
740  ];
741}
742
743//===----------------------------------------------------------------------===//
744// pdl_interp::GetDefiningOpOp
745//===----------------------------------------------------------------------===//
746
747def PDLInterp_GetDefiningOpOp
748    : PDLInterp_Op<"get_defining_op", [Pure]> {
749  let summary = "Get the defining operation of a `Value`";
750  let description = [{
751    `pdl_interp.get_defining_op` operations try to get the defining operation
752    of a specific value or range of values. In the case of range, the defining
753    op of the first value is returned. If the value is not an operation result
754    or range of operand results, null is returned.
755
756    Example:
757
758    ```mlir
759    %op = pdl_interp.get_defining_op of %value : !pdl.value
760    ```
761  }];
762
763  let arguments = (ins PDL_InstOrRangeOf<PDL_Value>:$value);
764  let results = (outs PDL_Operation:$inputOp);
765  let assemblyFormat = "`of` $value `:` type($value) attr-dict";
766}
767
768//===----------------------------------------------------------------------===//
769// pdl_interp::GetOperandOp
770//===----------------------------------------------------------------------===//
771
772def PDLInterp_GetOperandOp : PDLInterp_Op<"get_operand", [Pure]> {
773  let summary = "Get a specified operand from an `Operation`";
774  let description = [{
775    `pdl_interp.get_operand` operations try to get a specific operand from an
776    operation If the operation does not have an operand for the given index, a
777    null value is returned.
778
779    Example:
780
781    ```mlir
782    %operand = pdl_interp.get_operand 1 of %op
783    ```
784  }];
785
786  let arguments = (ins PDL_Operation:$inputOp,
787                       ConfinedAttr<I32Attr, [IntNonNegative]>:$index);
788  let results = (outs PDL_Value:$value);
789  let assemblyFormat = "$index `of` $inputOp attr-dict";
790}
791
792//===----------------------------------------------------------------------===//
793// pdl_interp::GetOperandsOp
794//===----------------------------------------------------------------------===//
795
796def PDLInterp_GetOperandsOp : PDLInterp_Op<"get_operands", [Pure]> {
797  let summary = "Get a specified operand group from an `Operation`";
798  let description = [{
799    `pdl_interp.get_operands` operations try to get a specific operand
800    group from an operation. If the expected result is a single Value, null is
801    returned if the operand group is not of size 1. If a range is expected,
802    null is returned if the operand group is invalid. If no index is provided,
803    the returned operand group corresponds to all operands of the operation.
804
805    Example:
806
807    ```mlir
808    // Get the first group of operands from an operation, and expect a single
809    // element.
810    %operand = pdl_interp.get_operands 0 of %op : !pdl.value
811
812    // Get the first group of operands from an operation.
813    %operands = pdl_interp.get_operands 0 of %op : !pdl.range<value>
814
815    // Get all of the operands from an operation.
816    %operands = pdl_interp.get_operands of %op : !pdl.range<value>
817    ```
818  }];
819
820  let arguments = (ins
821    PDL_Operation:$inputOp,
822    OptionalAttr<ConfinedAttr<I32Attr, [IntNonNegative]>>:$index
823  );
824  let results = (outs PDL_InstOrRangeOf<PDL_Value>:$value);
825  let assemblyFormat = "($index^)? `of` $inputOp `:` type($value) attr-dict";
826  let builders = [
827    OpBuilder<(ins "Type":$resultType, "Value":$inputOp,
828                   "std::optional<unsigned>":$index), [{
829      build($_builder, $_state, resultType, inputOp,
830            index ? $_builder.getI32IntegerAttr(*index) : IntegerAttr());
831    }]>,
832  ];
833}
834
835//===----------------------------------------------------------------------===//
836// pdl_interp::GetResultOp
837//===----------------------------------------------------------------------===//
838
839def PDLInterp_GetResultOp : PDLInterp_Op<"get_result", [Pure]> {
840  let summary = "Get a specified result from an `Operation`";
841  let description = [{
842    `pdl_interp.get_result` operations try to get a specific result from an
843    operation. If the operation does not have a result for the given index, a
844    null value is returned.
845
846    Example:
847
848    ```mlir
849    %result = pdl_interp.get_result 1 of %op
850    ```
851  }];
852
853  let arguments = (ins PDL_Operation:$inputOp,
854                       ConfinedAttr<I32Attr, [IntNonNegative]>:$index);
855  let results = (outs PDL_Value:$value);
856  let assemblyFormat = "$index `of` $inputOp attr-dict";
857}
858
859//===----------------------------------------------------------------------===//
860// pdl_interp::GetResultsOp
861//===----------------------------------------------------------------------===//
862
863def PDLInterp_GetResultsOp : PDLInterp_Op<"get_results", [Pure]> {
864  let summary = "Get a specified result group from an `Operation`";
865  let description = [{
866    `pdl_interp.get_results` operations try to get a specific result group
867    from an operation. If the expected result is a single Value, null is
868    returned if the result group is not of size 1. If a range is expected,
869    null is returned if the result group is invalid. If no index is provided,
870    the returned operand group corresponds to all results of the operation.
871
872    Example:
873
874    ```mlir
875    // Get the first group of results from an operation, and expect a single
876    // element.
877    %result = pdl_interp.get_results 0 of %op : !pdl.value
878
879    // Get the first group of results from an operation.
880    %results = pdl_interp.get_results 0 of %op : !pdl.range<value>
881
882    // Get all of the results from an operation.
883    %results = pdl_interp.get_results of %op : !pdl.range<value>
884    ```
885  }];
886
887  let arguments = (ins
888    PDL_Operation:$inputOp,
889    OptionalAttr<ConfinedAttr<I32Attr, [IntNonNegative]>>:$index
890  );
891  let results = (outs PDL_InstOrRangeOf<PDL_Value>:$value);
892  let assemblyFormat = "($index^)? `of` $inputOp `:` type($value) attr-dict";
893  let builders = [
894    OpBuilder<(ins "Type":$resultType, "Value":$inputOp,
895                   "std::optional<unsigned>":$index), [{
896      build($_builder, $_state, resultType, inputOp,
897            index ? $_builder.getI32IntegerAttr(*index) : IntegerAttr());
898    }]>,
899    OpBuilder<(ins "Value":$inputOp), [{
900      build($_builder, $_state,
901            pdl::RangeType::get($_builder.getType<pdl::ValueType>()), inputOp,
902            IntegerAttr());
903    }]>,
904  ];
905}
906
907//===----------------------------------------------------------------------===//
908// pdl_interp::GetUsersOp
909//===----------------------------------------------------------------------===//
910
911def PDLInterp_GetUsersOp
912    : PDLInterp_Op<"get_users", [Pure]> {
913  let summary = "Get the users of a `Value`";
914  let description = [{
915    `pdl_interp.get_users` extracts the users that accept this value. In the
916    case of a range, the union of users of the all the values are returned,
917    similarly to ResultRange::getUsers.
918
919    Example:
920
921    ```mlir
922    // Get all the users of a single value.
923    %ops = pdl_interp.get_users of %value : !pdl.value
924
925    // Get all the users of the first value in a range.
926    %ops = pdl_interp.get_users of %values : !pdl.range<value>
927    ```
928  }];
929
930  let arguments = (ins PDL_InstOrRangeOf<PDL_Value>:$value);
931  let results = (outs PDL_RangeOf<PDL_Operation>:$operations);
932  let assemblyFormat = "`of` $value `:` type($value) attr-dict";
933
934  let builders = [
935    OpBuilder<(ins "Value":$value), [{
936      build($_builder, $_state,
937            pdl::RangeType::get($_builder.getType<pdl::OperationType>()),
938            value);
939    }]>,
940  ];
941}
942
943//===----------------------------------------------------------------------===//
944// pdl_interp::GetValueTypeOp
945//===----------------------------------------------------------------------===//
946
947def PDLInterp_GetValueTypeOp : PDLInterp_Op<"get_value_type", [Pure,
948     TypesMatchWith<"`value` type matches arity of `result`",
949                    "result", "value", "getGetValueTypeOpValueType($_self)">]> {
950  let summary = "Get the result type of a specified `Value`";
951  let description = [{
952    `pdl_interp.get_value_type` operations get the resulting type of a specific
953    value or range thereof.
954
955    Example:
956
957    ```mlir
958    // Get the type of a single value.
959    %type = pdl_interp.get_value_type of %value : !pdl.type
960
961    // Get the types of a value range.
962    %type = pdl_interp.get_value_type of %values : !pdl.range<type>
963    ```
964  }];
965
966  let arguments = (ins PDL_InstOrRangeOf<PDL_Value>:$value);
967  let results = (outs PDL_InstOrRangeOf<PDL_Type>:$result);
968  let assemblyFormat = "`of` $value `:` type($result) attr-dict";
969
970  let builders = [
971    OpBuilder<(ins "Value":$value), [{
972      Type valType = value.getType();
973      Type typeType = $_builder.getType<pdl::TypeType>();
974      build($_builder, $_state,
975            ::llvm::isa<pdl::RangeType>(valType) ? pdl::RangeType::get(typeType)
976                                          : typeType,
977            value);
978    }]>
979  ];
980}
981
982//===----------------------------------------------------------------------===//
983// pdl_interp::IsNotNullOp
984//===----------------------------------------------------------------------===//
985
986def PDLInterp_IsNotNullOp
987    : PDLInterp_PredicateOp<"is_not_null", [Pure]> {
988  let summary = "Check if a positional value is non-null";
989  let description = [{
990    `pdl_interp.is_not_null` operations check that a positional value or range
991    exists. For ranges, this does not mean that the range was simply empty. On
992    success, this operation branches to the true destination. Otherwise, the
993    false destination is taken.
994
995    Example:
996
997    ```mlir
998    pdl_interp.is_not_null %value : !pdl.value -> ^matchDest, ^failureDest
999    ```
1000  }];
1001
1002  let arguments = (ins PDL_AnyType:$value);
1003  let assemblyFormat = "$value `:` type($value) attr-dict `->` successors";
1004}
1005
1006
1007//===----------------------------------------------------------------------===//
1008// pdl_interp::CreateRangeOp
1009//===----------------------------------------------------------------------===//
1010
1011def PDLInterp_CreateRangeOp : PDLInterp_Op<"create_range", [Pure]> {
1012  let summary = "Construct a range of PDL entities";
1013  let description = [{
1014    `pdl_interp.create_range` operations construct a range from a given set of PDL
1015    entities, which all share the same underlying element type. For example, a
1016    `!pdl.range<value>` may be constructed from a list of `!pdl.value`
1017    or `!pdl.range<value>` entities.
1018
1019    Example:
1020
1021    ```mlir
1022    // Construct a range of values.
1023    %valueRange = pdl_interp.create_range %inputValue, %inputRange : !pdl.value, !pdl.range<value>
1024
1025    // Construct a range of types.
1026    %typeRange = pdl_interp.create_range %inputType, %inputRange : !pdl.type, !pdl.range<type>
1027
1028    // Construct an empty range of types.
1029    %valueRange = pdl_interp.create_range : !pdl.range<type>
1030    ```
1031  }];
1032
1033  let arguments = (ins Variadic<PDL_AnyType>:$arguments);
1034  let results = (outs PDL_RangeOf<AnyTypeOf<[PDL_Type, PDL_Value]>>:$result);
1035  let assemblyFormat = [{
1036    ($arguments^ `:` type($arguments))?
1037    custom<RangeType>(ref(type($arguments)), type($result))
1038    attr-dict
1039  }];
1040  let hasVerifier = 1;
1041}
1042
1043//===----------------------------------------------------------------------===//
1044// pdl_interp::RecordMatchOp
1045//===----------------------------------------------------------------------===//
1046
1047def PDLInterp_RecordMatchOp
1048    : PDLInterp_Op<"record_match", [AttrSizedOperandSegments, Terminator]> {
1049  let summary = "Record the metadata for a successful pattern match";
1050  let description = [{
1051    `pdl_interp.record_match` operations record a successful pattern match with
1052    the interpreter and branch to the next part of the matcher. The metadata
1053    recorded by these operations correspond to a specific `pdl.pattern`, as well
1054    as what values were used during that match that should be propagated to the
1055    rewriter.
1056
1057    Example:
1058
1059    ```mlir
1060    pdl_interp.record_match @rewriters::myRewriter(%root : !pdl.operation) : benefit(1), loc([%root, %op1]), root("foo.op") -> ^nextDest
1061    ```
1062  }];
1063
1064  let arguments = (ins Variadic<PDL_AnyType>:$inputs,
1065                       Variadic<PDL_Operation>:$matchedOps,
1066                       SymbolRefAttr:$rewriter,
1067                       OptionalAttr<StrAttr>:$rootKind,
1068                       OptionalAttr<StrArrayAttr>:$generatedOps,
1069                       ConfinedAttr<I16Attr, [IntNonNegative]>:$benefit);
1070  let successors = (successor AnySuccessor:$dest);
1071  let assemblyFormat = [{
1072    $rewriter (`(` $inputs^ `:` type($inputs) `)`)? `:`
1073    `benefit` `(` $benefit `)` `,`
1074    (`generatedOps` `(` $generatedOps^ `)` `,`)?
1075    `loc` `(` `[` $matchedOps `]` `)`
1076    (`,` `root` `(` $rootKind^ `)`)? attr-dict `->` $dest
1077  }];
1078}
1079
1080//===----------------------------------------------------------------------===//
1081// pdl_interp::ReplaceOp
1082//===----------------------------------------------------------------------===//
1083
1084def PDLInterp_ReplaceOp : PDLInterp_Op<"replace"> {
1085  let summary = "Mark an operation as `replace`d";
1086  let description = [{
1087    `pdl_interp.replaced` operations are used to specify that an operation
1088    should be marked as replaced. The semantics of this operation correspond
1089    with the `replaceOp` method on a `PatternRewriter`. The set of replacement
1090    values must match the number of results specified by the operation.
1091
1092    Example:
1093
1094    ```mlir
1095    // Replace root node with 2 values:
1096    pdl_interp.replace %root with (%val0, %val1 : !pdl.type, !pdl.type)
1097    ```
1098  }];
1099  let arguments = (ins PDL_Operation:$inputOp,
1100                       Variadic<PDL_InstOrRangeOf<PDL_Value>>:$replValues);
1101  let assemblyFormat = [{
1102    $inputOp `with` ` ` `(` ($replValues^ `:` type($replValues))? `)`
1103    attr-dict
1104  }];
1105}
1106
1107//===----------------------------------------------------------------------===//
1108// pdl_interp::SwitchAttributeOp
1109//===----------------------------------------------------------------------===//
1110
1111def PDLInterp_SwitchAttributeOp
1112    : PDLInterp_SwitchOp<"switch_attribute", [Pure]> {
1113  let summary = "Switch on the value of an `Attribute`";
1114  let description = [{
1115    `pdl_interp.switch_attribute` operations compare the value of a given
1116    attribute with a set of constant attributes. If the value matches one of the
1117    provided case values the destination for that case value is taken, otherwise
1118    the default destination is taken.
1119
1120    Example:
1121
1122    ```mlir
1123    pdl_interp.switch_attribute %attr to [10, true](^10Dest, ^trueDest) -> ^defaultDest
1124    ```
1125  }];
1126  let arguments = (ins PDL_Attribute:$attribute, ArrayAttr:$caseValues);
1127  let assemblyFormat = [{
1128    $attribute `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest
1129  }];
1130
1131  let builders = [
1132    OpBuilder<(ins "Value":$attribute, "ArrayRef<Attribute>":$caseValues,
1133      "Block *":$defaultDest, "BlockRange":$dests), [{
1134    build($_builder, $_state, attribute, $_builder.getArrayAttr(caseValues),
1135          defaultDest, dests);
1136  }]>];
1137  let hasVerifier = 1;
1138}
1139
1140//===----------------------------------------------------------------------===//
1141// pdl_interp::SwitchOperandCountOp
1142//===----------------------------------------------------------------------===//
1143
1144def PDLInterp_SwitchOperandCountOp
1145    : PDLInterp_SwitchOp<"switch_operand_count", [Pure]> {
1146  let summary = "Switch on the operand count of an `Operation`";
1147  let description = [{
1148    `pdl_interp.switch_operand_count` operations compare the operand count of a
1149    given operation with a set of potential counts. If the value matches one of
1150    the provided case values the destination for that case value is taken,
1151    otherwise the default destination is taken.
1152
1153    Example:
1154
1155    ```mlir
1156    pdl_interp.switch_operand_count of %op to [10, 2] -> ^10Dest, ^2Dest, ^defaultDest
1157    ```
1158  }];
1159
1160  let arguments = (ins PDL_Operation:$inputOp, I32ElementsAttr:$caseValues);
1161  let assemblyFormat = [{
1162    `of` $inputOp `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest
1163  }];
1164
1165  let builders = [
1166    OpBuilder<(ins "Value":$inputOp, "ArrayRef<int32_t>":$counts,
1167                   "Block *":$defaultDest, "BlockRange":$dests), [{
1168    build($_builder, $_state, inputOp, $_builder.getI32VectorAttr(counts),
1169          defaultDest, dests);
1170  }]>];
1171  let hasVerifier = 1;
1172}
1173
1174//===----------------------------------------------------------------------===//
1175// pdl_interp::SwitchOperationNameOp
1176//===----------------------------------------------------------------------===//
1177
1178def PDLInterp_SwitchOperationNameOp
1179    : PDLInterp_SwitchOp<"switch_operation_name", [Pure]> {
1180  let summary = "Switch on the OperationName of an `Operation`";
1181  let description = [{
1182    `pdl_interp.switch_operation_name` operations compare the name of a given
1183    operation with a set of known names. If the value matches one of the
1184    provided case values the destination for that case value is taken, otherwise
1185    the default destination is taken.
1186
1187    Example:
1188
1189    ```mlir
1190    pdl_interp.switch_operation_name of %op to ["foo.op", "bar.op"](^fooDest, ^barDest) -> ^defaultDest
1191    ```
1192  }];
1193
1194  let arguments = (ins PDL_Operation:$inputOp,
1195                       StrArrayAttr:$caseValues);
1196  let assemblyFormat = [{
1197    `of` $inputOp `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest
1198  }];
1199
1200  let builders = [
1201    OpBuilder<(ins "Value":$inputOp, "ArrayRef<OperationName>":$names,
1202      "Block *":$defaultDest, "BlockRange":$dests), [{
1203      auto stringNames = llvm::to_vector<8>(llvm::map_range(names,
1204          [](OperationName name) { return name.getStringRef(); }));
1205      build($_builder, $_state, inputOp, $_builder.getStrArrayAttr(stringNames),
1206            defaultDest, dests);
1207    }]>,
1208  ];
1209  let hasVerifier = 1;
1210}
1211
1212//===----------------------------------------------------------------------===//
1213// pdl_interp::SwitchResultCountOp
1214//===----------------------------------------------------------------------===//
1215
1216def PDLInterp_SwitchResultCountOp
1217    : PDLInterp_SwitchOp<"switch_result_count", [Pure]> {
1218  let summary = "Switch on the result count of an `Operation`";
1219  let description = [{
1220    `pdl_interp.switch_result_count` operations compare the result count of a
1221    given operation with a set of potential counts. If the value matches one of
1222    the provided case values the destination for that case value is taken,
1223    otherwise the default destination is taken.
1224
1225    Example:
1226
1227    ```mlir
1228    pdl_interp.switch_result_count of %op to [0, 2](^0Dest, ^2Dest) -> ^defaultDest
1229    ```
1230  }];
1231
1232  let arguments = (ins PDL_Operation:$inputOp, I32ElementsAttr:$caseValues);
1233  let assemblyFormat = [{
1234    `of` $inputOp `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest
1235  }];
1236
1237  let builders = [
1238    OpBuilder<(ins "Value":$inputOp, "ArrayRef<int32_t>":$counts,
1239                   "Block *":$defaultDest, "BlockRange":$dests), [{
1240    build($_builder, $_state, inputOp, $_builder.getI32VectorAttr(counts),
1241          defaultDest, dests);
1242  }]>];
1243  let hasVerifier = 1;
1244}
1245
1246//===----------------------------------------------------------------------===//
1247// pdl_interp::SwitchTypeOp
1248//===----------------------------------------------------------------------===//
1249
1250def PDLInterp_SwitchTypeOp : PDLInterp_SwitchOp<"switch_type", [Pure]> {
1251  let summary = "Switch on a `Type` value";
1252  let description = [{
1253    `pdl_interp.switch_type` operations compare a type with a set of statically
1254    known types. If the value matches one of the provided case values the
1255    destination for that case value is taken, otherwise the default destination
1256    is taken.
1257
1258    Example:
1259
1260    ```mlir
1261    pdl_interp.switch_type %type to [i32, i64] -> ^i32Dest, ^i64Dest, ^defaultDest
1262    ```
1263  }];
1264
1265  let arguments = (ins PDL_Type:$value, TypeArrayAttr:$caseValues);
1266  let assemblyFormat = [{
1267    $value `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest
1268  }];
1269
1270  let builders = [
1271    OpBuilder<(ins "Value":$edge, "ArrayRef<Attribute>":$types,
1272                   "Block *":$defaultDest, "BlockRange":$dests), [{
1273      build($_builder, $_state, edge, $_builder.getArrayAttr(types),
1274            defaultDest, dests);
1275    }]>,
1276  ];
1277
1278  let extraClassDeclaration = [{
1279    auto getCaseTypes() { return getCaseValues().getAsValueRange<TypeAttr>(); }
1280  }];
1281  let hasVerifier = 1;
1282}
1283
1284//===----------------------------------------------------------------------===//
1285// pdl_interp::SwitchTypesOp
1286//===----------------------------------------------------------------------===//
1287
1288def PDLInterp_SwitchTypesOp : PDLInterp_SwitchOp<"switch_types",
1289                                                 [Pure]> {
1290  let summary = "Switch on a range of `Type` values";
1291  let description = [{
1292    `pdl_interp.switch_types` operations compare a range of types with a set of
1293    statically known ranges. If the value matches one of the provided case
1294    values the destination for that case value is taken, otherwise the default
1295    destination is taken.
1296
1297    Example:
1298
1299    ```mlir
1300    pdl_interp.switch_types %type is [[i32], [i64, i64]] -> ^i32Dest, ^i64Dest, ^defaultDest
1301    ```
1302  }];
1303
1304  let arguments = (ins
1305    PDL_RangeOf<PDL_Type>:$value,
1306    TypedArrayAttrBase<TypeArrayAttr, "type-array array attribute">:$caseValues
1307  );
1308  let assemblyFormat = [{
1309    $value `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest
1310  }];
1311
1312  let builders = [
1313    OpBuilder<(ins "Value":$edge, "ArrayRef<Attribute>":$types,
1314                   "Block *":$defaultDest, "BlockRange":$dests), [{
1315      build($_builder, $_state, edge, $_builder.getArrayAttr(types),
1316            defaultDest, dests);
1317    }]>,
1318  ];
1319
1320  let extraClassDeclaration = [{
1321    auto getCaseTypes() { return getCaseValues().getAsRange<ArrayAttr>(); }
1322  }];
1323  let hasVerifier = 1;
1324}
1325
1326#endif // MLIR_DIALECT_PDLINTERP_IR_PDLINTERPOPS
1327