• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/PDLBase.td"
17include "mlir/Interfaces/SideEffectInterfaces.td"
18
19//===----------------------------------------------------------------------===//
20// PDLInterp Dialect
21//===----------------------------------------------------------------------===//
22
23def PDLInterp_Dialect : Dialect {
24  let summary = "Interpreted pattern execution dialect";
25  let description = [{
26    The PDL Interpreter dialect provides a lower level abstraction compared to
27    the PDL dialect, and is targeted towards low level optimization and
28    interpreter code generation. The dialect operations encapsulates
29    low-level pattern match and rewrite "primitives", such as navigating the
30    IR (Operation::getOperand), creating new operations (OpBuilder::create),
31    etc. Many of the operations within this dialect also fuse branching control
32    flow with some form of a predicate comparison operation. This type of fusion
33    reduces the amount of work that an interpreter must do when executing.
34  }];
35
36  let name = "pdl_interp";
37  let cppNamespace = "::mlir::pdl_interp";
38  let dependentDialects = ["pdl::PDLDialect"];
39  let extraClassDeclaration = [{
40    /// Returns the name of the function containing the matcher code. This
41    /// function is called by the interpreter when matching an operation.
42    static StringRef getMatcherFunctionName() { return "matcher"; }
43
44    /// Returns the name of the module containing the rewrite functions. These
45    /// functions are invoked by distinct patterns within the matcher function
46    /// to rewrite the IR after a successful match.
47    static StringRef getRewriterModuleName() { return "rewriters"; }
48  }];
49}
50
51//===----------------------------------------------------------------------===//
52// PDLInterp Operations
53//===----------------------------------------------------------------------===//
54
55// Generic interpreter operation.
56class PDLInterp_Op<string mnemonic, list<OpTrait> traits = []> :
57    Op<PDLInterp_Dialect, mnemonic, traits>;
58
59//===----------------------------------------------------------------------===//
60// PDLInterp_PredicateOp
61
62// Check operations evaluate a predicate on a positional value and then
63// conditionally branch on the result.
64class PDLInterp_PredicateOp<string mnemonic, list<OpTrait> traits = []> :
65    PDLInterp_Op<mnemonic, !listconcat([Terminator], traits)> {
66  let successors = (successor AnySuccessor:$trueDest, AnySuccessor:$falseDest);
67}
68
69//===----------------------------------------------------------------------===//
70// PDLInterp_SwitchOp
71
72// Switch operations evaluate a predicate on a positional value and then
73// conditionally branch on the result.
74class PDLInterp_SwitchOp<string mnemonic, list<OpTrait> traits = []> :
75    PDLInterp_Op<mnemonic, !listconcat([Terminator], traits)> {
76  let successors = (successor AnySuccessor:$defaultDest,
77                              VariadicSuccessor<AnySuccessor>:$cases);
78
79  let verifier = [{
80    // Verify that the number of case destinations matches the number of case
81    // values.
82    size_t numDests = cases().size();
83    size_t numValues = caseValues().size();
84    if (numDests != numValues) {
85      return emitOpError("expected number of cases to match the number of case "
86                         "values, got ")
87          << numDests << " but expected " << numValues;
88    }
89    return success();
90  }];
91}
92
93//===----------------------------------------------------------------------===//
94// pdl_interp::ApplyConstraintOp
95//===----------------------------------------------------------------------===//
96
97def PDLInterp_ApplyConstraintOp : PDLInterp_PredicateOp<"apply_constraint"> {
98  let summary = "Apply a constraint to a set of positional values";
99  let description = [{
100    `pdl_interp.apply_constraint` operations apply a generic constraint, that
101    has been registered with the interpreter, with a given set of positional
102    values. The constraint may have any number of constant parameters. On
103    success, this operation branches to the true destination, otherwise the
104    false destination is taken.
105
106    Example:
107
108    ```mlir
109    // Apply `myConstraint` to the entities defined by `input`, `attr`, and
110    // `op`.
111    pdl_interp.apply_constraint "myConstraint"[42, "abc", i32](%input, %attr, %op : !pdl.value, !pdl.attribute, !pdl.operation) -> ^matchDest, ^failureDest
112    ```
113  }];
114
115  let arguments = (ins StrAttr:$name,
116                       Variadic<PDL_PositionalValue>:$args,
117                       OptionalAttr<ArrayAttr>:$constParams);
118  let assemblyFormat = [{
119    $name ($constParams^)? `(` $args `:` type($args) `)` attr-dict `->`
120    successors
121  }];
122}
123
124//===----------------------------------------------------------------------===//
125// pdl_interp::ApplyRewriteOp
126//===----------------------------------------------------------------------===//
127
128def PDLInterp_ApplyRewriteOp : PDLInterp_Op<"apply_rewrite"> {
129  let summary = "Invoke and apply an externally registered rewrite method";
130  let description = [{
131    `pdl_interp.apply_rewrite` operations invoke an external rewriter that has
132    been registered with the interpreter to perform the rewrite after a
133    successful match. The rewrite is passed the root operation being matched, a
134    set of additional positional arguments generated within the matcher, and a
135    set of constant parameters.
136
137    Example:
138
139    ```mlir
140    // Rewriter operating solely on the root operation.
141    pdl_interp.apply_rewrite "rewriter" on %root
142
143    // Rewriter operating on the root operation along with additional arguments
144    // from the matcher.
145    pdl_interp.apply_rewrite "rewriter"(%value : !pdl.value) on %root
146
147    // Rewriter operating on the root operation along with additional arguments
148    // and constant parameters.
149    pdl_interp.apply_rewrite "rewriter"[42](%value : !pdl.value) on %root
150    ```
151  }];
152  let arguments = (ins StrAttr:$name,
153                       PDL_Operation:$root,
154                       Variadic<PDL_PositionalValue>:$args,
155                       OptionalAttr<ArrayAttr>:$constParams);
156  let assemblyFormat = [{
157    $name ($constParams^)? (`(` $args^ `:` type($args) `)`)? `on` $root
158    attr-dict
159  }];
160}
161
162//===----------------------------------------------------------------------===//
163// pdl_interp::AreEqualOp
164//===----------------------------------------------------------------------===//
165
166def PDLInterp_AreEqualOp
167    : PDLInterp_PredicateOp<"are_equal", [NoSideEffect, SameTypeOperands]> {
168  let summary = "Check if two positional values are equivalent";
169  let description = [{
170    `pdl_interp.are_equal` operations compare two positional values for
171    equality. On success, this operation branches to the true destination,
172    otherwise the false destination is taken.
173
174    Example:
175
176    ```mlir
177    pdl_interp.are_equal %result1, %result2 : !pdl.value -> ^matchDest, ^failureDest
178    ```
179  }];
180
181  let arguments = (ins PDL_PositionalValue:$lhs,
182                       PDL_PositionalValue:$rhs);
183  let assemblyFormat = "operands `:` type($lhs) attr-dict `->` successors";
184}
185
186//===----------------------------------------------------------------------===//
187// pdl_interp::BranchOp
188//===----------------------------------------------------------------------===//
189
190def PDLInterp_BranchOp : PDLInterp_Op<"branch", [NoSideEffect, Terminator]> {
191  let summary = "General branch operation";
192  let description = [{
193    `pdl_interp.branch` operations expose general branch functionality to the
194    interpreter, and are generally used to branch from one pattern match
195    sequence to another.
196
197    Example:
198
199    ```mlir
200    pdl_interp.branch ^dest
201    ```
202  }];
203
204  let successors = (successor AnySuccessor:$dest);
205  let assemblyFormat = "$dest attr-dict";
206}
207
208//===----------------------------------------------------------------------===//
209// pdl_interp::CheckAttributeOp
210//===----------------------------------------------------------------------===//
211
212def PDLInterp_CheckAttributeOp
213    : PDLInterp_PredicateOp<"check_attribute", [NoSideEffect]> {
214  let summary = "Check the value of an `Attribute`";
215  let description = [{
216    `pdl_interp.check_attribute` operations compare the value of a given
217    attribute with a constant value. On success, this operation branches to the
218    true destination, otherwise the false destination is taken.
219
220    Example:
221
222    ```mlir
223    pdl_interp.check_attribute %attr is 10 -> ^matchDest, ^failureDest
224    ```
225  }];
226
227  let arguments = (ins PDL_Attribute:$attribute, AnyAttr:$constantValue);
228  let assemblyFormat = [{
229    $attribute `is` $constantValue attr-dict `->` successors
230  }];
231}
232
233//===----------------------------------------------------------------------===//
234// pdl_interp::CheckOperandCountOp
235//===----------------------------------------------------------------------===//
236
237def PDLInterp_CheckOperandCountOp
238    : PDLInterp_PredicateOp<"check_operand_count", [NoSideEffect]> {
239  let summary = "Check the number of operands of an `Operation`";
240  let description = [{
241    `pdl_interp.check_operand_count` operations compare the number of operands
242    of a given operation value with a constant. On success, this operation
243    branches to the true destination, otherwise the false destination is taken.
244
245    Example:
246
247    ```mlir
248    pdl_interp.check_operand_count of %op is 2 -> ^matchDest, ^failureDest
249    ```
250  }];
251
252  let arguments = (ins PDL_Operation:$operation,
253                       Confined<I32Attr, [IntNonNegative]>:$count);
254  let assemblyFormat = "`of` $operation `is` $count attr-dict `->` successors";
255}
256
257//===----------------------------------------------------------------------===//
258// pdl_interp::CheckOperationNameOp
259//===----------------------------------------------------------------------===//
260
261def PDLInterp_CheckOperationNameOp
262    : PDLInterp_PredicateOp<"check_operation_name", [NoSideEffect]> {
263  let summary = "Check the OperationName of an `Operation`";
264  let description = [{
265    `pdl_interp.check_operation_name` operations compare the name of a given
266    operation with a known name. On success, this operation branches to the true
267    destination, otherwise the false destination is taken.
268
269    Example:
270
271    ```mlir
272    pdl_interp.check_operation_name of %op is "foo.op" -> ^matchDest, ^failureDest
273    ```
274  }];
275
276  let arguments = (ins PDL_Operation:$operation, StrAttr:$name);
277  let assemblyFormat = "`of` $operation `is` $name attr-dict `->` successors";
278}
279
280//===----------------------------------------------------------------------===//
281// pdl_interp::CheckResultCountOp
282//===----------------------------------------------------------------------===//
283
284def PDLInterp_CheckResultCountOp
285    : PDLInterp_PredicateOp<"check_result_count", [NoSideEffect]> {
286  let summary = "Check the number of results of an `Operation`";
287  let description = [{
288    `pdl_interp.check_result_count` operations compare the number of results
289    of a given operation value with a constant. On success, this operation
290    branches to the true destination, otherwise the false destination is taken.
291
292    Example:
293
294    ```mlir
295    pdl_interp.check_result_count of %op is 0 -> ^matchDest, ^failureDest
296    ```
297  }];
298
299  let arguments = (ins PDL_Operation:$operation,
300                       Confined<I32Attr, [IntNonNegative]>:$count);
301  let assemblyFormat = "`of` $operation `is` $count attr-dict `->` successors";
302}
303
304//===----------------------------------------------------------------------===//
305// pdl_interp::CheckTypeOp
306//===----------------------------------------------------------------------===//
307
308def PDLInterp_CheckTypeOp
309    : PDLInterp_PredicateOp<"check_type", [NoSideEffect]> {
310  let summary = "Compare a type to a known value";
311  let description = [{
312    `pdl_interp.check_type` operations compare a type with a statically known
313    type. On success, this operation branches to the true destination, otherwise
314    the false destination is taken.
315
316    Example:
317
318    ```mlir
319    pdl_interp.check_type %type is i32 -> ^matchDest, ^failureDest
320    ```
321  }];
322
323  let arguments = (ins PDL_Type:$value, TypeAttr:$type);
324  let assemblyFormat = "$value `is` $type attr-dict `->` successors";
325}
326
327//===----------------------------------------------------------------------===//
328// pdl_interp::CreateAttributeOp
329//===----------------------------------------------------------------------===//
330
331def PDLInterp_CreateAttributeOp
332    : PDLInterp_Op<"create_attribute", [NoSideEffect]> {
333  let summary = "Create an interpreter handle to a constant `Attribute`";
334  let description = [{
335    `pdl_interp.create_attribute` operations generate a handle within the
336    interpreter for a specific constant attribute value.
337
338    Example:
339
340    ```mlir
341    %attr = pdl_interp.create_attribute 10 : i64
342    ```
343  }];
344
345  let arguments = (ins AnyAttr:$value);
346  let results = (outs PDL_Attribute:$attribute);
347  let assemblyFormat = "$value attr-dict";
348
349  let builders = [
350    OpBuilderDAG<(ins "Attribute":$value), [{
351      build($_builder, $_state, $_builder.getType<pdl::AttributeType>(), value);
352    }]>];
353}
354
355//===----------------------------------------------------------------------===//
356// pdl_interp::CreateNativeOp
357//===----------------------------------------------------------------------===//
358
359def PDLInterp_CreateNativeOp : PDLInterp_Op<"create_native"> {
360  let summary = "Call a native creation method to construct an `Attribute`, "
361                "`Operation`, `Type`, or `Value`";
362  let description = [{
363    `pdl_interp.create_native` operations invoke a native C++ function, that has
364    been registered externally with the consumer of PDL, to create an
365    `Attribute`, `Operation`, `Type`, or `Value`. The native function must
366    produce a value of the specified return type, and may accept any number of
367    positional arguments and constant attribute parameters.
368
369    Example:
370
371    ```mlir
372    %ret = pdl_interp.create_native "myNativeFunc"[42, "gt"](%arg0, %arg1 : !pdl.value, !pdl.value) : !pdl.attribute
373    ```
374  }];
375
376  let arguments = (ins StrAttr:$name,
377                       Variadic<PDL_PositionalValue>:$args,
378                       OptionalAttr<ArrayAttr>:$constParams);
379  let results = (outs PDL_PositionalValue:$result);
380  let assemblyFormat = [{
381    $name ($constParams^)? (`(` $args^ `:` type($args) `)`)? `:` type($result)
382    attr-dict
383  }];
384  let verifier = ?;
385}
386
387//===----------------------------------------------------------------------===//
388// pdl_interp::CreateOperationOp
389//===----------------------------------------------------------------------===//
390
391def PDLInterp_CreateOperationOp
392    : PDLInterp_Op<"create_operation", [AttrSizedOperandSegments]> {
393  let summary = "Create an instance of a specific `Operation`";
394  let description = [{
395    `pdl_interp.create_operation` operations create an `Operation` instance with
396    the specified attributes, operands, and result types.
397
398    Example:
399
400    ```mlir
401    // Create an instance of a `foo.op` operation.
402    %op = pdl_interp.create_operation "foo.op"(%arg0) {"attrA" = %attr0} -> %type, %type
403    ```
404  }];
405
406  let arguments = (ins StrAttr:$name,
407                       Variadic<PDL_Value>:$operands,
408                       Variadic<PDL_Attribute>:$attributes,
409                       StrArrayAttr:$attributeNames,
410                       Variadic<PDL_Type>:$types);
411  let results = (outs PDL_Operation:$operation);
412
413  let builders = [
414    OpBuilderDAG<(ins "StringRef":$name, "ValueRange":$types,
415      "ValueRange":$operands, "ValueRange":$attributes,
416      "ArrayAttr":$attributeNames), [{
417      build($_builder, $_state, $_builder.getType<pdl::OperationType>(), name,
418            operands, attributes, attributeNames, types);
419    }]>];
420  let parser = [{ return ::parseCreateOperationOp(parser, result); }];
421  let printer = [{ ::print(p, *this); }];
422}
423
424//===----------------------------------------------------------------------===//
425// pdl_interp::CreateTypeOp
426//===----------------------------------------------------------------------===//
427
428def PDLInterp_CreateTypeOp : PDLInterp_Op<"create_type", [NoSideEffect]> {
429  let summary = "Create an interpreter handle to a constant `Type`";
430  let description = [{
431    `pdl_interp.create_type` operations generate a handle within the interpreter
432    for a specific constant type value.
433
434    Example:
435
436    ```mlir
437    pdl_interp.create_type i64
438    ```
439  }];
440
441  let arguments = (ins TypeAttr:$value);
442  let results = (outs PDL_Type:$result);
443  let assemblyFormat = "$value attr-dict";
444
445  let builders = [
446    OpBuilderDAG<(ins "TypeAttr":$type), [{
447      build($_builder, $_state, $_builder.getType<pdl::TypeType>(), type);
448    }]>
449  ];
450}
451
452//===----------------------------------------------------------------------===//
453// pdl_interp::EraseOp
454//===----------------------------------------------------------------------===//
455
456def PDLInterp_EraseOp : PDLInterp_Op<"erase"> {
457  let summary = "Mark an operation as `erased`";
458  let description = [{
459    `pdl.erase` operations are used to specify that an operation should be
460    marked as erased. The semantics of this operation correspond with the
461    `eraseOp` method on a `PatternRewriter`.
462
463    Example:
464
465    ```mlir
466    pdl_interp.erase %root
467    ```
468  }];
469
470  let arguments = (ins PDL_Operation:$operation);
471  let assemblyFormat = "$operation attr-dict";
472}
473
474//===----------------------------------------------------------------------===//
475// pdl_interp::FinalizeOp
476//===----------------------------------------------------------------------===//
477
478def PDLInterp_FinalizeOp
479    : PDLInterp_Op<"finalize", [NoSideEffect, Terminator]> {
480  let summary = "Finalize a pattern match or rewrite sequence";
481  let description = [{
482    `pdl_interp.finalize` is used to denote the termination of a match or
483    rewrite sequence.
484
485    Example:
486
487    ```mlir
488    pdl_interp.finalize
489    ```
490  }];
491  let assemblyFormat = "attr-dict";
492}
493
494//===----------------------------------------------------------------------===//
495// pdl_interp::GetAttributeOp
496//===----------------------------------------------------------------------===//
497
498def PDLInterp_GetAttributeOp : PDLInterp_Op<"get_attribute", [NoSideEffect]> {
499  let summary = "Get a specified attribute value from an `Operation`";
500  let description = [{
501    `pdl_interp.get_attribute` operations try to get a specific attribute from
502    an operation. If the operation does not have that attribute, a null value is
503    returned.
504
505    Example:
506
507    ```mlir
508    %attr = pdl_interp.get_attribute "attr" of %op
509    ```
510  }];
511
512  let arguments = (ins PDL_Operation:$operation,
513                       StrAttr:$name);
514  let results = (outs PDL_Attribute:$attribute);
515  let assemblyFormat = "$name `of` $operation attr-dict";
516}
517
518//===----------------------------------------------------------------------===//
519// pdl_interp::GetAttributeTypeOp
520//===----------------------------------------------------------------------===//
521
522def PDLInterp_GetAttributeTypeOp
523    : PDLInterp_Op<"get_attribute_type", [NoSideEffect]> {
524  let summary = "Get the result type of a specified `Attribute`";
525  let description = [{
526    `pdl_interp.get_attribute_type` operations get the resulting type of a
527    specific attribute.
528
529    Example:
530
531    ```mlir
532    %type = pdl_interp.get_attribute_type of %attr
533    ```
534  }];
535
536  let arguments = (ins PDL_Attribute:$value);
537  let results = (outs PDL_Type:$result);
538  let assemblyFormat = "`of` $value attr-dict";
539
540  let builders = [
541    OpBuilderDAG<(ins "Value":$value), [{
542      build($_builder, $_state, $_builder.getType<pdl::TypeType>(), value);
543    }]>
544  ];
545}
546
547//===----------------------------------------------------------------------===//
548// pdl_interp::GetDefiningOpOp
549//===----------------------------------------------------------------------===//
550
551def PDLInterp_GetDefiningOpOp
552    : PDLInterp_Op<"get_defining_op", [NoSideEffect]> {
553  let summary = "Get the defining operation of a `Value`";
554  let description = [{
555    `pdl_interp.get_defining_op` operations try to get the defining operation
556    of a specific value. If the value is not an operation result, null is
557    returned.
558
559    Example:
560
561    ```mlir
562    %op = pdl_interp.get_defining_op of %value
563    ```
564  }];
565
566  let arguments = (ins PDL_Value:$value);
567  let results = (outs PDL_Operation:$operation);
568  let assemblyFormat = "`of` $value attr-dict";
569}
570
571//===----------------------------------------------------------------------===//
572// pdl_interp::GetOperandOp
573//===----------------------------------------------------------------------===//
574
575def PDLInterp_GetOperandOp : PDLInterp_Op<"get_operand", [NoSideEffect]> {
576  let summary = "Get a specified operand from an `Operation`";
577  let description = [{
578    `pdl_interp.get_operand` operations try to get a specific operand from an
579    operation If the operation does not have an operand for the given index, a
580    null value is returned.
581
582    Example:
583
584    ```mlir
585    %operand = pdl_interp.get_operand 1 of %op
586    ```
587  }];
588
589  let arguments = (ins PDL_Operation:$operation,
590                       Confined<I32Attr, [IntNonNegative]>:$index);
591  let results = (outs PDL_Value:$value);
592  let assemblyFormat = "$index `of` $operation attr-dict";
593}
594
595//===----------------------------------------------------------------------===//
596// pdl_interp::GetResultOp
597//===----------------------------------------------------------------------===//
598
599def PDLInterp_GetResultOp : PDLInterp_Op<"get_result", [NoSideEffect]> {
600  let summary = "Get a specified result from an `Operation`";
601  let description = [{
602    `pdl_interp.get_result` operations try to get a specific result from an
603    operation. If the operation does not have a result for the given index, a
604    null value is returned.
605
606    Example:
607
608    ```mlir
609    %result = pdl_interp.get_result 1 of %op
610    ```
611  }];
612
613  let arguments = (ins PDL_Operation:$operation,
614                       Confined<I32Attr, [IntNonNegative]>:$index);
615  let results = (outs PDL_Value:$value);
616  let assemblyFormat = "$index `of` $operation attr-dict";
617}
618
619//===----------------------------------------------------------------------===//
620// pdl_interp::GetValueTypeOp
621//===----------------------------------------------------------------------===//
622
623// Get a type from the root operation, held in the rewriter context.
624def PDLInterp_GetValueTypeOp : PDLInterp_Op<"get_value_type", [NoSideEffect]> {
625  let summary = "Get the result type of a specified `Value`";
626  let description = [{
627    `pdl_interp.get_value_type` operations get the resulting type of a specific
628    value.
629
630    Example:
631
632    ```mlir
633    %type = pdl_interp.get_value_type of %value
634    ```
635  }];
636
637  let arguments = (ins PDL_Value:$value);
638  let results = (outs PDL_Type:$result);
639  let assemblyFormat = "`of` $value attr-dict";
640
641  let builders = [
642    OpBuilderDAG<(ins "Value":$value), [{
643      build($_builder, $_state, $_builder.getType<pdl::TypeType>(), value);
644    }]>
645  ];
646}
647
648//===----------------------------------------------------------------------===//
649// pdl_interp::InferredTypeOp
650//===----------------------------------------------------------------------===//
651
652def PDLInterp_InferredTypeOp : PDLInterp_Op<"inferred_type"> {
653  let summary = "Generate a handle to a Type that is \"inferred\"";
654  let description = [{
655    `pdl_interp.inferred_type` operations generate a handle to a type that
656    should be inferred. This signals to other operations, such as
657    `pdl_interp.create_operation`, that this type should be inferred.
658
659    Example:
660
661    ```mlir
662    pdl_interp.inferred_type
663    ```
664  }];
665  let results = (outs PDL_Type:$type);
666  let assemblyFormat = "attr-dict";
667
668  let builders = [
669    OpBuilderDAG<(ins), [{
670      build($_builder, $_state, $_builder.getType<pdl::TypeType>());
671    }]>,
672  ];
673}
674
675//===----------------------------------------------------------------------===//
676// pdl_interp::IsNotNullOp
677//===----------------------------------------------------------------------===//
678
679def PDLInterp_IsNotNullOp
680    : PDLInterp_PredicateOp<"is_not_null", [NoSideEffect]> {
681  let summary = "Check if a positional value is non-null";
682  let description = [{
683    `pdl_interp.is_not_null` operations check that a positional value exists. On
684    success, this operation branches to the true destination. Otherwise, the
685    false destination is taken.
686
687    Example:
688
689    ```mlir
690    pdl_interp.is_not_null %value : !pdl.value -> ^matchDest, ^failureDest
691    ```
692  }];
693
694  let arguments = (ins PDL_PositionalValue:$value);
695  let assemblyFormat = "$value `:` type($value) attr-dict `->` successors";
696}
697
698//===----------------------------------------------------------------------===//
699// pdl_interp::RecordMatchOp
700//===----------------------------------------------------------------------===//
701
702def PDLInterp_RecordMatchOp
703    : PDLInterp_Op<"record_match", [AttrSizedOperandSegments, Terminator]> {
704  let summary = "Record the metadata for a successful pattern match";
705  let description = [{
706    `pdl_interp.record_match` operations record a successful pattern match with
707    the interpreter and branch to the next part of the matcher. The metadata
708    recorded by these operations correspond to a specific `pdl.pattern`, as well
709    as what values were used during that match that should be propagated to the
710    rewriter.
711
712    Example:
713
714    ```mlir
715    pdl_interp.record_match @rewriters::myRewriter(%root : !pdl.operation) : benefit(1), loc([%root, %op1]), root("foo.op") -> ^nextDest
716    ```
717  }];
718
719  let arguments = (ins Variadic<PDL_PositionalValue>:$inputs,
720                       Variadic<PDL_Operation>:$matchedOps,
721                       SymbolRefAttr:$rewriter,
722                       OptionalAttr<StrAttr>:$rootKind,
723                       OptionalAttr<StrArrayAttr>:$generatedOps,
724                       Confined<I16Attr, [IntNonNegative]>:$benefit);
725  let successors = (successor AnySuccessor:$dest);
726  let assemblyFormat = [{
727    $rewriter (`(` $inputs^ `:` type($inputs) `)`)? `:`
728    `benefit` `(` $benefit `)` `,`
729    (`generatedOps` `(` $generatedOps^ `)` `,`)?
730    `loc` `(` `[` $matchedOps `]` `)`
731    (`,` `root` `(` $rootKind^ `)`)? attr-dict `->` $dest
732  }];
733}
734
735//===----------------------------------------------------------------------===//
736// pdl_interp::ReplaceOp
737//===----------------------------------------------------------------------===//
738
739def PDLInterp_ReplaceOp : PDLInterp_Op<"replace"> {
740  let summary = "Mark an operation as `replace`d";
741  let description = [{
742    `pdl_interp.replaced` operations are used to specify that an operation
743    should be marked as replaced. The semantics of this operation correspond
744    with the `replaceOp` method on a `PatternRewriter`. The set of replacement
745    values must match the number of results specified by the operation.
746
747    Example:
748
749    ```mlir
750    // Replace root node with 2 values:
751    pdl_interp.replace %root with (%val0, %val1)
752    ```
753  }];
754  let arguments = (ins PDL_Operation:$operation,
755                       Variadic<PDL_Value>:$replValues);
756  let assemblyFormat = "$operation `with` `(` $replValues `)` attr-dict";
757}
758
759//===----------------------------------------------------------------------===//
760// pdl_interp::SwitchAttributeOp
761//===----------------------------------------------------------------------===//
762
763def PDLInterp_SwitchAttributeOp
764    : PDLInterp_SwitchOp<"switch_attribute", [NoSideEffect]> {
765  let summary = "Switch on the value of an `Attribute`";
766  let description = [{
767    `pdl_interp.switch_attribute` operations compare the value of a given
768    attribute with a set of constant attributes. If the value matches one of the
769    provided case values the destination for that case value is taken, otherwise
770    the default destination is taken.
771
772    Example:
773
774    ```mlir
775    pdl_interp.switch_attribute %attr to [10, true](^10Dest, ^trueDest) -> ^defaultDest
776    ```
777  }];
778  let arguments = (ins PDL_Attribute:$attribute, ArrayAttr:$caseValues);
779  let assemblyFormat = [{
780    $attribute `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest
781  }];
782
783  let builders = [
784    OpBuilderDAG<(ins "Value":$attribute, "ArrayRef<Attribute>":$caseValues,
785      "Block *":$defaultDest, "BlockRange":$dests), [{
786    build($_builder, $_state, attribute, $_builder.getArrayAttr(caseValues),
787          defaultDest, dests);
788  }]>];
789}
790
791//===----------------------------------------------------------------------===//
792// pdl_interp::SwitchOperandCountOp
793//===----------------------------------------------------------------------===//
794
795def PDLInterp_SwitchOperandCountOp
796    : PDLInterp_SwitchOp<"switch_operand_count", [NoSideEffect]> {
797  let summary = "Switch on the operand count of an `Operation`";
798  let description = [{
799    `pdl_interp.switch_operand_count` operations compare the operand count of a
800    given operation with a set of potential counts. If the value matches one of
801    the provided case values the destination for that case value is taken,
802    otherwise the default destination is taken.
803
804    Example:
805
806    ```mlir
807    pdl_interp.switch_operand_count of %op to [10, 2] -> ^10Dest, ^2Dest, ^defaultDest
808    ```
809  }];
810
811  let arguments = (ins PDL_Operation:$operation, I32ElementsAttr:$caseValues);
812  let assemblyFormat = [{
813    `of` $operation `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest
814  }];
815
816  let builders = [
817    OpBuilderDAG<(ins "Value":$operation, "ArrayRef<int32_t>":$counts,
818      "Block *":$defaultDest, "BlockRange":$dests), [{
819    build($_builder, $_state, operation, $_builder.getI32VectorAttr(counts),
820          defaultDest, dests);
821  }]>];
822}
823
824//===----------------------------------------------------------------------===//
825// pdl_interp::SwitchOperationNameOp
826//===----------------------------------------------------------------------===//
827
828def PDLInterp_SwitchOperationNameOp
829    : PDLInterp_SwitchOp<"switch_operation_name", [NoSideEffect]> {
830  let summary = "Switch on the OperationName of an `Operation`";
831  let description = [{
832    `pdl_interp.switch_operation_name` operations compare the name of a given
833    operation with a set of known names. If the value matches one of the
834    provided case values the destination for that case value is taken, otherwise
835    the default destination is taken.
836
837    Example:
838
839    ```mlir
840    pdl_interp.switch_operation_name of %op to ["foo.op", "bar.op"](^fooDest, ^barDest) -> ^defaultDest
841    ```
842  }];
843
844  let arguments = (ins PDL_Operation:$operation,
845                       StrArrayAttr:$caseValues);
846  let assemblyFormat = [{
847    `of` $operation `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest
848  }];
849
850  let builders = [
851    OpBuilderDAG<(ins "Value":$operation, "ArrayRef<OperationName>":$names,
852      "Block *":$defaultDest, "BlockRange":$dests), [{
853      auto stringNames = llvm::to_vector<8>(llvm::map_range(names,
854          [](OperationName name) { return name.getStringRef(); }));
855      build($_builder, $_state, operation, $_builder.getStrArrayAttr(stringNames),
856            defaultDest, dests);
857    }]>,
858  ];
859}
860
861//===----------------------------------------------------------------------===//
862// pdl_interp::SwitchResultCountOp
863//===----------------------------------------------------------------------===//
864
865def PDLInterp_SwitchResultCountOp
866    : PDLInterp_SwitchOp<"switch_result_count", [NoSideEffect]> {
867  let summary = "Switch on the result count of an `Operation`";
868  let description = [{
869    `pdl_interp.switch_result_count` operations compare the result count of a
870    given operation with a set of potential counts. If the value matches one of
871    the provided case values the destination for that case value is taken,
872    otherwise the default destination is taken.
873
874    Example:
875
876    ```mlir
877    pdl_interp.switch_result_count of %op to [0, 2](^0Dest, ^2Dest) -> ^defaultDest
878    ```
879  }];
880
881  let arguments = (ins PDL_Operation:$operation, I32ElementsAttr:$caseValues);
882  let assemblyFormat = [{
883    `of` $operation `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest
884  }];
885
886  let builders = [
887    OpBuilderDAG<(ins "Value":$operation, "ArrayRef<int32_t>":$counts,
888      "Block *":$defaultDest, "BlockRange":$dests), [{
889    build($_builder, $_state, operation, $_builder.getI32VectorAttr(counts),
890          defaultDest, dests);
891  }]>];
892}
893
894//===----------------------------------------------------------------------===//
895// pdl_interp::SwitchTypeOp
896//===----------------------------------------------------------------------===//
897
898def PDLInterp_SwitchTypeOp : PDLInterp_SwitchOp<"switch_type", [NoSideEffect]> {
899  let summary = "Switch on a `Type` value";
900  let description = [{
901    `pdl_interp.switch_type` operations compare a type with a set of statically
902    known types. If the value matches one of the provided case values the
903    destination for that case value is taken, otherwise the default destination
904    is taken.
905
906    Example:
907
908    ```mlir
909    pdl_interp.switch_type %type to [i32, i64] -> ^i32Dest, ^i64Dest, ^defaultDest
910    ```
911  }];
912
913  let arguments = (ins PDL_Type:$value, TypeArrayAttr:$caseValues);
914  let assemblyFormat = [{
915    $value `to` $caseValues `(` $cases `)` attr-dict `->` $defaultDest
916  }];
917
918  let builders = [
919    OpBuilderDAG<(ins "Value":$edge, "TypeRange":$types, "Block *":$defaultDest,
920      "BlockRange":$dests), [{
921      build($_builder, $_state, edge, $_builder.getTypeArrayAttr(types),
922            defaultDest, dests);
923    }]>,
924  ];
925
926  let extraClassDeclaration = [{
927    auto getCaseTypes() { return caseValues().getAsValueRange<TypeAttr>(); }
928  }];
929}
930
931#endif // MLIR_DIALECT_PDLINTERP_IR_PDLINTERPOPS
932