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