1 //===- Predicate.h - Pattern predicates -------------------------*- C++ -*-===//
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 contains definitions for "predicates" used when converting PDL into
10 // a matcher tree. Predicates are composed of three different parts:
11 //
12 //  * Positions
13 //    - A position refers to a specific location on the input DAG, i.e. an
14 //      existing MLIR entity being matched. These can be attributes, operands,
15 //      operations, results, and types. Each position also defines a relation to
16 //      its parent. For example, the operand `[0] -> 1` has a parent operation
17 //      position `[0]`. The attribute `[0, 1] -> "myAttr"` has parent operation
18 //      position of `[0, 1]`. The operation `[0, 1]` has a parent operand edge
19 //      `[0] -> 1` (i.e. it is the defining op of operand 1). The only position
20 //      without a parent is `[0]`, which refers to the root operation.
21 //  * Questions
22 //    - A question refers to a query on a specific positional value. For
23 //    example, an operation name question checks the name of an operation
24 //    position.
25 //  * Answers
26 //    - An answer is the expected result of a question. For example, when
27 //    matching an operation with the name "foo.op". The question would be an
28 //    operation name question, with an expected answer of "foo.op".
29 //
30 //===----------------------------------------------------------------------===//
31 
32 #ifndef MLIR_LIB_CONVERSION_PDLTOPDLINTERP_PREDICATE_H_
33 #define MLIR_LIB_CONVERSION_PDLTOPDLINTERP_PREDICATE_H_
34 
35 #include "mlir/IR/MLIRContext.h"
36 #include "mlir/IR/OperationSupport.h"
37 #include "mlir/IR/PatternMatch.h"
38 #include "mlir/IR/Types.h"
39 
40 namespace mlir {
41 namespace pdl_to_pdl_interp {
42 namespace Predicates {
43 /// An enumeration of the kinds of predicates.
44 enum Kind : unsigned {
45   /// Positions, ordered by decreasing priority.
46   OperationPos,
47   OperandPos,
48   OperandGroupPos,
49   AttributePos,
50   ResultPos,
51   ResultGroupPos,
52   TypePos,
53 
54   // Questions, ordered by dependency and decreasing priority.
55   IsNotNullQuestion,
56   OperationNameQuestion,
57   TypeQuestion,
58   AttributeQuestion,
59   OperandCountAtLeastQuestion,
60   OperandCountQuestion,
61   ResultCountAtLeastQuestion,
62   ResultCountQuestion,
63   EqualToQuestion,
64   ConstraintQuestion,
65 
66   // Answers.
67   AttributeAnswer,
68   TrueAnswer,
69   OperationNameAnswer,
70   TypeAnswer,
71   UnsignedAnswer,
72 };
73 } // end namespace Predicates
74 
75 /// Base class for all predicates, used to allow efficient pointer comparison.
76 template <typename ConcreteT, typename BaseT, typename Key,
77           Predicates::Kind Kind>
78 class PredicateBase : public BaseT {
79 public:
80   using KeyTy = Key;
81   using Base = PredicateBase<ConcreteT, BaseT, Key, Kind>;
82 
83   template <typename KeyT>
PredicateBase(KeyT && key)84   explicit PredicateBase(KeyT &&key)
85       : BaseT(Kind), key(std::forward<KeyT>(key)) {}
86 
87   /// Get an instance of this position.
88   template <typename... Args>
get(StorageUniquer & uniquer,Args &&...args)89   static ConcreteT *get(StorageUniquer &uniquer, Args &&...args) {
90     return uniquer.get<ConcreteT>(/*initFn=*/{}, std::forward<Args>(args)...);
91   }
92 
93   /// Construct an instance with the given storage allocator.
94   template <typename KeyT>
construct(StorageUniquer::StorageAllocator & alloc,KeyT && key)95   static ConcreteT *construct(StorageUniquer::StorageAllocator &alloc,
96                               KeyT &&key) {
97     return new (alloc.allocate<ConcreteT>()) ConcreteT(std::forward<KeyT>(key));
98   }
99 
100   /// Utility methods required by the storage allocator.
101   bool operator==(const KeyTy &key) const { return this->key == key; }
classof(const BaseT * pred)102   static bool classof(const BaseT *pred) { return pred->getKind() == Kind; }
103 
104   /// Return the key value of this predicate.
getValue()105   const KeyTy &getValue() const { return key; }
106 
107 protected:
108   KeyTy key;
109 };
110 
111 /// Base storage for simple predicates that only unique with the kind.
112 template <typename ConcreteT, typename BaseT, Predicates::Kind Kind>
113 class PredicateBase<ConcreteT, BaseT, void, Kind> : public BaseT {
114 public:
115   using Base = PredicateBase<ConcreteT, BaseT, void, Kind>;
116 
PredicateBase()117   explicit PredicateBase() : BaseT(Kind) {}
118 
get(StorageUniquer & uniquer)119   static ConcreteT *get(StorageUniquer &uniquer) {
120     return uniquer.get<ConcreteT>();
121   }
classof(const BaseT * pred)122   static bool classof(const BaseT *pred) { return pred->getKind() == Kind; }
123 };
124 
125 //===----------------------------------------------------------------------===//
126 // Positions
127 //===----------------------------------------------------------------------===//
128 
129 struct OperationPosition;
130 
131 /// A position describes a value on the input IR on which a predicate may be
132 /// applied, such as an operation or attribute. This enables re-use between
133 /// predicates, and assists generating bytecode and memory management.
134 ///
135 /// Operation positions form the base of other positions, which are formed
136 /// relative to a parent operation. Operations are anchored at Operand nodes,
137 /// except for the root operation which is parentless.
138 class Position : public StorageUniquer::BaseStorage {
139 public:
Position(Predicates::Kind kind)140   explicit Position(Predicates::Kind kind) : kind(kind) {}
141   virtual ~Position();
142 
143   /// Returns the depth of the first ancestor operation position.
144   unsigned getOperationDepth() const;
145 
146   /// Returns the parent position. The root operation position has no parent.
getParent()147   Position *getParent() const { return parent; }
148 
149   /// Returns the kind of this position.
getKind()150   Predicates::Kind getKind() const { return kind; }
151 
152 protected:
153   /// Link to the parent position.
154   Position *parent = nullptr;
155 
156 private:
157   /// The kind of this position.
158   Predicates::Kind kind;
159 };
160 
161 //===----------------------------------------------------------------------===//
162 // AttributePosition
163 
164 /// A position describing an attribute of an operation.
165 struct AttributePosition
166     : public PredicateBase<AttributePosition, Position,
167                            std::pair<OperationPosition *, Identifier>,
168                            Predicates::AttributePos> {
169   explicit AttributePosition(const KeyTy &key);
170 
171   /// Returns the attribute name of this position.
getNameAttributePosition172   Identifier getName() const { return key.second; }
173 };
174 
175 //===----------------------------------------------------------------------===//
176 // OperandPosition
177 
178 /// A position describing an operand of an operation.
179 struct OperandPosition
180     : public PredicateBase<OperandPosition, Position,
181                            std::pair<OperationPosition *, unsigned>,
182                            Predicates::OperandPos> {
183   explicit OperandPosition(const KeyTy &key);
184 
185   /// Returns the operand number of this position.
getOperandNumberOperandPosition186   unsigned getOperandNumber() const { return key.second; }
187 };
188 
189 //===----------------------------------------------------------------------===//
190 // OperandGroupPosition
191 
192 /// A position describing an operand group of an operation.
193 struct OperandGroupPosition
194     : public PredicateBase<
195           OperandGroupPosition, Position,
196           std::tuple<OperationPosition *, Optional<unsigned>, bool>,
197           Predicates::OperandGroupPos> {
198   explicit OperandGroupPosition(const KeyTy &key);
199 
200   /// Returns a hash suitable for the given keytype.
hashKeyOperandGroupPosition201   static llvm::hash_code hashKey(const KeyTy &key) {
202     return llvm::hash_value(key);
203   }
204 
205   /// Returns the group number of this position. If None, this group refers to
206   /// all operands.
getOperandGroupNumberOperandGroupPosition207   Optional<unsigned> getOperandGroupNumber() const { return std::get<1>(key); }
208 
209   /// Returns if the operand group has unknown size. If false, the operand group
210   /// has at max one element.
isVariadicOperandGroupPosition211   bool isVariadic() const { return std::get<2>(key); }
212 };
213 
214 //===----------------------------------------------------------------------===//
215 // OperationPosition
216 
217 /// An operation position describes an operation node in the IR. Other position
218 /// kinds are formed with respect to an operation position.
219 struct OperationPosition : public PredicateBase<OperationPosition, Position,
220                                                 std::pair<Position *, unsigned>,
221                                                 Predicates::OperationPos> {
OperationPositionOperationPosition222   explicit OperationPosition(const KeyTy &key) : Base(key) {
223     parent = key.first;
224   }
225 
226   /// Gets the root position.
getRootOperationPosition227   static OperationPosition *getRoot(StorageUniquer &uniquer) {
228     return Base::get(uniquer, nullptr, 0);
229   }
230   /// Gets an operation position with the given parent.
getOperationPosition231   static OperationPosition *get(StorageUniquer &uniquer, Position *parent) {
232     return Base::get(uniquer, parent, parent->getOperationDepth() + 1);
233   }
234 
235   /// Returns the depth of this position.
getDepthOperationPosition236   unsigned getDepth() const { return key.second; }
237 
238   /// Returns if this operation position corresponds to the root.
isRootOperationPosition239   bool isRoot() const { return getDepth() == 0; }
240 };
241 
242 //===----------------------------------------------------------------------===//
243 // ResultPosition
244 
245 /// A position describing a result of an operation.
246 struct ResultPosition
247     : public PredicateBase<ResultPosition, Position,
248                            std::pair<OperationPosition *, unsigned>,
249                            Predicates::ResultPos> {
ResultPositionResultPosition250   explicit ResultPosition(const KeyTy &key) : Base(key) { parent = key.first; }
251 
252   /// Returns the result number of this position.
getResultNumberResultPosition253   unsigned getResultNumber() const { return key.second; }
254 };
255 
256 //===----------------------------------------------------------------------===//
257 // ResultGroupPosition
258 
259 /// A position describing a result group of an operation.
260 struct ResultGroupPosition
261     : public PredicateBase<
262           ResultGroupPosition, Position,
263           std::tuple<OperationPosition *, Optional<unsigned>, bool>,
264           Predicates::ResultGroupPos> {
ResultGroupPositionResultGroupPosition265   explicit ResultGroupPosition(const KeyTy &key) : Base(key) {
266     parent = std::get<0>(key);
267   }
268 
269   /// Returns a hash suitable for the given keytype.
hashKeyResultGroupPosition270   static llvm::hash_code hashKey(const KeyTy &key) {
271     return llvm::hash_value(key);
272   }
273 
274   /// Returns the group number of this position. If None, this group refers to
275   /// all results.
getResultGroupNumberResultGroupPosition276   Optional<unsigned> getResultGroupNumber() const { return std::get<1>(key); }
277 
278   /// Returns if the result group has unknown size. If false, the result group
279   /// has at max one element.
isVariadicResultGroupPosition280   bool isVariadic() const { return std::get<2>(key); }
281 };
282 
283 //===----------------------------------------------------------------------===//
284 // TypePosition
285 
286 /// A position describing the result type of an entity, i.e. an Attribute,
287 /// Operand, Result, etc.
288 struct TypePosition : public PredicateBase<TypePosition, Position, Position *,
289                                            Predicates::TypePos> {
TypePositionTypePosition290   explicit TypePosition(const KeyTy &key) : Base(key) {
291     assert((isa<AttributePosition, OperandPosition, OperandGroupPosition,
292                 ResultPosition, ResultGroupPosition>(key)) &&
293            "expected parent to be an attribute, operand, or result");
294     parent = key;
295   }
296 };
297 
298 //===----------------------------------------------------------------------===//
299 // Qualifiers
300 //===----------------------------------------------------------------------===//
301 
302 /// An ordinal predicate consists of a "Question" and a set of acceptable
303 /// "Answers" (later converted to ordinal values). A predicate will query some
304 /// property of a positional value and decide what to do based on the result.
305 ///
306 /// This makes top-level predicate representations ordinal (SwitchOp). Later,
307 /// predicates that end up with only one acceptable answer (including all
308 /// boolean kinds) will be converted to boolean predicates (PredicateOp) in the
309 /// matcher.
310 ///
311 /// For simplicity, both are represented as "qualifiers", with a base kind and
312 /// perhaps additional properties. For example, all OperationName predicates ask
313 /// the same question, but GenericConstraint predicates may ask different ones.
314 class Qualifier : public StorageUniquer::BaseStorage {
315 public:
Qualifier(Predicates::Kind kind)316   explicit Qualifier(Predicates::Kind kind) : kind(kind) {}
317 
318   /// Returns the kind of this qualifier.
getKind()319   Predicates::Kind getKind() const { return kind; }
320 
321 private:
322   /// The kind of this position.
323   Predicates::Kind kind;
324 };
325 
326 //===----------------------------------------------------------------------===//
327 // Answers
328 
329 /// An Answer representing an `Attribute` value.
330 struct AttributeAnswer
331     : public PredicateBase<AttributeAnswer, Qualifier, Attribute,
332                            Predicates::AttributeAnswer> {
333   using Base::Base;
334 };
335 
336 /// An Answer representing an `OperationName` value.
337 struct OperationNameAnswer
338     : public PredicateBase<OperationNameAnswer, Qualifier, OperationName,
339                            Predicates::OperationNameAnswer> {
340   using Base::Base;
341 };
342 
343 /// An Answer representing a boolean `true` value.
344 struct TrueAnswer
345     : PredicateBase<TrueAnswer, Qualifier, void, Predicates::TrueAnswer> {
346   using Base::Base;
347 };
348 
349 /// An Answer representing a `Type` value. The value is stored as either a
350 /// TypeAttr, or an ArrayAttr of TypeAttr.
351 struct TypeAnswer : public PredicateBase<TypeAnswer, Qualifier, Attribute,
352                                          Predicates::TypeAnswer> {
353   using Base::Base;
354 };
355 
356 /// An Answer representing an unsigned value.
357 struct UnsignedAnswer
358     : public PredicateBase<UnsignedAnswer, Qualifier, unsigned,
359                            Predicates::UnsignedAnswer> {
360   using Base::Base;
361 };
362 
363 //===----------------------------------------------------------------------===//
364 // Questions
365 
366 /// Compare an `Attribute` to a constant value.
367 struct AttributeQuestion
368     : public PredicateBase<AttributeQuestion, Qualifier, void,
369                            Predicates::AttributeQuestion> {};
370 
371 /// Apply a parameterized constraint to multiple position values.
372 struct ConstraintQuestion
373     : public PredicateBase<
374           ConstraintQuestion, Qualifier,
375           std::tuple<StringRef, ArrayRef<Position *>, Attribute>,
376           Predicates::ConstraintQuestion> {
377   using Base::Base;
378 
379   /// Construct an instance with the given storage allocator.
constructConstraintQuestion380   static ConstraintQuestion *construct(StorageUniquer::StorageAllocator &alloc,
381                                        KeyTy key) {
382     return Base::construct(alloc, KeyTy{alloc.copyInto(std::get<0>(key)),
383                                         alloc.copyInto(std::get<1>(key)),
384                                         std::get<2>(key)});
385   }
386 };
387 
388 /// Compare the equality of two values.
389 struct EqualToQuestion
390     : public PredicateBase<EqualToQuestion, Qualifier, Position *,
391                            Predicates::EqualToQuestion> {
392   using Base::Base;
393 };
394 
395 /// Compare a positional value with null, i.e. check if it exists.
396 struct IsNotNullQuestion
397     : public PredicateBase<IsNotNullQuestion, Qualifier, void,
398                            Predicates::IsNotNullQuestion> {};
399 
400 /// Compare the number of operands of an operation with a known value.
401 struct OperandCountQuestion
402     : public PredicateBase<OperandCountQuestion, Qualifier, void,
403                            Predicates::OperandCountQuestion> {};
404 struct OperandCountAtLeastQuestion
405     : public PredicateBase<OperandCountAtLeastQuestion, Qualifier, void,
406                            Predicates::OperandCountAtLeastQuestion> {};
407 
408 /// Compare the name of an operation with a known value.
409 struct OperationNameQuestion
410     : public PredicateBase<OperationNameQuestion, Qualifier, void,
411                            Predicates::OperationNameQuestion> {};
412 
413 /// Compare the number of results of an operation with a known value.
414 struct ResultCountQuestion
415     : public PredicateBase<ResultCountQuestion, Qualifier, void,
416                            Predicates::ResultCountQuestion> {};
417 struct ResultCountAtLeastQuestion
418     : public PredicateBase<ResultCountAtLeastQuestion, Qualifier, void,
419                            Predicates::ResultCountAtLeastQuestion> {};
420 
421 /// Compare the type of an attribute or value with a known type.
422 struct TypeQuestion : public PredicateBase<TypeQuestion, Qualifier, void,
423                                            Predicates::TypeQuestion> {};
424 
425 //===----------------------------------------------------------------------===//
426 // PredicateUniquer
427 //===----------------------------------------------------------------------===//
428 
429 /// This class provides a storage uniquer that is used to allocate predicate
430 /// instances.
431 class PredicateUniquer : public StorageUniquer {
432 public:
PredicateUniquer()433   PredicateUniquer() {
434     // Register the types of Positions with the uniquer.
435     registerParametricStorageType<AttributePosition>();
436     registerParametricStorageType<OperandPosition>();
437     registerParametricStorageType<OperandGroupPosition>();
438     registerParametricStorageType<OperationPosition>();
439     registerParametricStorageType<ResultPosition>();
440     registerParametricStorageType<ResultGroupPosition>();
441     registerParametricStorageType<TypePosition>();
442 
443     // Register the types of Questions with the uniquer.
444     registerParametricStorageType<AttributeAnswer>();
445     registerParametricStorageType<OperationNameAnswer>();
446     registerParametricStorageType<TypeAnswer>();
447     registerParametricStorageType<UnsignedAnswer>();
448     registerSingletonStorageType<TrueAnswer>();
449 
450     // Register the types of Answers with the uniquer.
451     registerParametricStorageType<ConstraintQuestion>();
452     registerParametricStorageType<EqualToQuestion>();
453     registerSingletonStorageType<AttributeQuestion>();
454     registerSingletonStorageType<IsNotNullQuestion>();
455     registerSingletonStorageType<OperandCountQuestion>();
456     registerSingletonStorageType<OperandCountAtLeastQuestion>();
457     registerSingletonStorageType<OperationNameQuestion>();
458     registerSingletonStorageType<ResultCountQuestion>();
459     registerSingletonStorageType<ResultCountAtLeastQuestion>();
460     registerSingletonStorageType<TypeQuestion>();
461   }
462 };
463 
464 //===----------------------------------------------------------------------===//
465 // PredicateBuilder
466 //===----------------------------------------------------------------------===//
467 
468 /// This class provides utilities for constructing predicates.
469 class PredicateBuilder {
470 public:
PredicateBuilder(PredicateUniquer & uniquer,MLIRContext * ctx)471   PredicateBuilder(PredicateUniquer &uniquer, MLIRContext *ctx)
472       : uniquer(uniquer), ctx(ctx) {}
473 
474   //===--------------------------------------------------------------------===//
475   // Positions
476   //===--------------------------------------------------------------------===//
477 
478   /// Returns the root operation position.
getRoot()479   Position *getRoot() { return OperationPosition::getRoot(uniquer); }
480 
481   /// Returns the parent position defining the value held by the given operand.
getOperandDefiningOp(Position * p)482   OperationPosition *getOperandDefiningOp(Position *p) {
483     assert((isa<OperandPosition, OperandGroupPosition>(p)) &&
484            "expected operand position");
485     return OperationPosition::get(uniquer, p);
486   }
487 
488   /// Returns an attribute position for an attribute of the given operation.
getAttribute(OperationPosition * p,StringRef name)489   Position *getAttribute(OperationPosition *p, StringRef name) {
490     return AttributePosition::get(uniquer, p, Identifier::get(name, ctx));
491   }
492 
493   /// Returns an operand position for an operand of the given operation.
getOperand(OperationPosition * p,unsigned operand)494   Position *getOperand(OperationPosition *p, unsigned operand) {
495     return OperandPosition::get(uniquer, p, operand);
496   }
497 
498   /// Returns a position for a group of operands of the given operation.
getOperandGroup(OperationPosition * p,Optional<unsigned> group,bool isVariadic)499   Position *getOperandGroup(OperationPosition *p, Optional<unsigned> group,
500                             bool isVariadic) {
501     return OperandGroupPosition::get(uniquer, p, group, isVariadic);
502   }
getAllOperands(OperationPosition * p)503   Position *getAllOperands(OperationPosition *p) {
504     return getOperandGroup(p, /*group=*/llvm::None, /*isVariadic=*/true);
505   }
506 
507   /// Returns a result position for a result of the given operation.
getResult(OperationPosition * p,unsigned result)508   Position *getResult(OperationPosition *p, unsigned result) {
509     return ResultPosition::get(uniquer, p, result);
510   }
511 
512   /// Returns a position for a group of results of the given operation.
getResultGroup(OperationPosition * p,Optional<unsigned> group,bool isVariadic)513   Position *getResultGroup(OperationPosition *p, Optional<unsigned> group,
514                            bool isVariadic) {
515     return ResultGroupPosition::get(uniquer, p, group, isVariadic);
516   }
getAllResults(OperationPosition * p)517   Position *getAllResults(OperationPosition *p) {
518     return getResultGroup(p, /*group=*/llvm::None, /*isVariadic=*/true);
519   }
520 
521   /// Returns a type position for the given entity.
getType(Position * p)522   Position *getType(Position *p) { return TypePosition::get(uniquer, p); }
523 
524   //===--------------------------------------------------------------------===//
525   // Qualifiers
526   //===--------------------------------------------------------------------===//
527 
528   /// An ordinal predicate consists of a "Question" and a set of acceptable
529   /// "Answers" (later converted to ordinal values). A predicate will query some
530   /// property of a positional value and decide what to do based on the result.
531   using Predicate = std::pair<Qualifier *, Qualifier *>;
532 
533   /// Create a predicate comparing an attribute to a known value.
getAttributeConstraint(Attribute attr)534   Predicate getAttributeConstraint(Attribute attr) {
535     return {AttributeQuestion::get(uniquer),
536             AttributeAnswer::get(uniquer, attr)};
537   }
538 
539   /// Create a predicate comparing two values.
getEqualTo(Position * pos)540   Predicate getEqualTo(Position *pos) {
541     return {EqualToQuestion::get(uniquer, pos), TrueAnswer::get(uniquer)};
542   }
543 
544   /// Create a predicate that applies a generic constraint.
getConstraint(StringRef name,ArrayRef<Position * > pos,Attribute params)545   Predicate getConstraint(StringRef name, ArrayRef<Position *> pos,
546                           Attribute params) {
547     return {
548         ConstraintQuestion::get(uniquer, std::make_tuple(name, pos, params)),
549         TrueAnswer::get(uniquer)};
550   }
551 
552   /// Create a predicate comparing a value with null.
getIsNotNull()553   Predicate getIsNotNull() {
554     return {IsNotNullQuestion::get(uniquer), TrueAnswer::get(uniquer)};
555   }
556 
557   /// Create a predicate comparing the number of operands of an operation to a
558   /// known value.
getOperandCount(unsigned count)559   Predicate getOperandCount(unsigned count) {
560     return {OperandCountQuestion::get(uniquer),
561             UnsignedAnswer::get(uniquer, count)};
562   }
getOperandCountAtLeast(unsigned count)563   Predicate getOperandCountAtLeast(unsigned count) {
564     return {OperandCountAtLeastQuestion::get(uniquer),
565             UnsignedAnswer::get(uniquer, count)};
566   }
567 
568   /// Create a predicate comparing the name of an operation to a known value.
getOperationName(StringRef name)569   Predicate getOperationName(StringRef name) {
570     return {OperationNameQuestion::get(uniquer),
571             OperationNameAnswer::get(uniquer, OperationName(name, ctx))};
572   }
573 
574   /// Create a predicate comparing the number of results of an operation to a
575   /// known value.
getResultCount(unsigned count)576   Predicate getResultCount(unsigned count) {
577     return {ResultCountQuestion::get(uniquer),
578             UnsignedAnswer::get(uniquer, count)};
579   }
getResultCountAtLeast(unsigned count)580   Predicate getResultCountAtLeast(unsigned count) {
581     return {ResultCountAtLeastQuestion::get(uniquer),
582             UnsignedAnswer::get(uniquer, count)};
583   }
584 
585   /// Create a predicate comparing the type of an attribute or value to a known
586   /// type. The value is stored as either a TypeAttr, or an ArrayAttr of
587   /// TypeAttr.
getTypeConstraint(Attribute type)588   Predicate getTypeConstraint(Attribute type) {
589     return {TypeQuestion::get(uniquer), TypeAnswer::get(uniquer, type)};
590   }
591 
592 private:
593   /// The uniquer used when allocating predicate nodes.
594   PredicateUniquer &uniquer;
595 
596   /// The current MLIR context.
597   MLIRContext *ctx;
598 };
599 
600 } // end namespace pdl_to_pdl_interp
601 } // end namespace mlir
602 
603 #endif // MLIR_CONVERSION_PDLTOPDLINTERP_PREDICATE_H_
604