//===- Predicate.h - Pattern predicates -------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains definitions for "predicates" used when converting PDL into // a matcher tree. Predicates are composed of three different parts: // // * Positions // - A position refers to a specific location on the input DAG, i.e. an // existing MLIR entity being matched. These can be attributes, operands, // operations, results, and types. Each position also defines a relation to // its parent. For example, the operand `[0] -> 1` has a parent operation // position `[0]`. The attribute `[0, 1] -> "myAttr"` has parent operation // position of `[0, 1]`. The operation `[0, 1]` has a parent operand edge // `[0] -> 1` (i.e. it is the defining op of operand 1). The only position // without a parent is `[0]`, which refers to the root operation. // * Questions // - A question refers to a query on a specific positional value. For // example, an operation name question checks the name of an operation // position. // * Answers // - An answer is the expected result of a question. For example, when // matching an operation with the name "foo.op". The question would be an // operation name question, with an expected answer of "foo.op". // //===----------------------------------------------------------------------===// #ifndef MLIR_LIB_CONVERSION_PDLTOPDLINTERP_PREDICATE_H_ #define MLIR_LIB_CONVERSION_PDLTOPDLINTERP_PREDICATE_H_ #include "mlir/IR/MLIRContext.h" #include "mlir/IR/OperationSupport.h" #include "mlir/IR/PatternMatch.h" #include "mlir/IR/Types.h" namespace mlir { namespace pdl_to_pdl_interp { namespace Predicates { /// An enumeration of the kinds of predicates. enum Kind : unsigned { … }; } // namespace Predicates /// Base class for all predicates, used to allow efficient pointer comparison. template <typename ConcreteT, typename BaseT, typename Key, Predicates::Kind Kind> class PredicateBase : public BaseT { … }; /// Base storage for simple predicates that only unique with the kind. PredicateBase<ConcreteT, BaseT, void, Kind>; //===----------------------------------------------------------------------===// // Positions //===----------------------------------------------------------------------===// struct OperationPosition; /// A position describes a value on the input IR on which a predicate may be /// applied, such as an operation or attribute. This enables re-use between /// predicates, and assists generating bytecode and memory management. /// /// Operation positions form the base of other positions, which are formed /// relative to a parent operation. Operations are anchored at Operand nodes, /// except for the root operation which is parentless. class Position : public StorageUniquer::BaseStorage { … }; //===----------------------------------------------------------------------===// // AttributePosition /// A position describing an attribute of an operation. struct AttributePosition : public PredicateBase<AttributePosition, Position, std::pair<OperationPosition *, StringAttr>, Predicates::AttributePos> { … }; //===----------------------------------------------------------------------===// // AttributeLiteralPosition /// A position describing a literal attribute. struct AttributeLiteralPosition : public PredicateBase<AttributeLiteralPosition, Position, Attribute, Predicates::AttributeLiteralPos> { … }; //===----------------------------------------------------------------------===// // ForEachPosition /// A position describing an iterative choice of an operation. struct ForEachPosition : public PredicateBase<ForEachPosition, Position, std::pair<Position *, unsigned>, Predicates::ForEachPos> { … }; //===----------------------------------------------------------------------===// // OperandPosition /// A position describing an operand of an operation. struct OperandPosition : public PredicateBase<OperandPosition, Position, std::pair<OperationPosition *, unsigned>, Predicates::OperandPos> { … }; //===----------------------------------------------------------------------===// // OperandGroupPosition /// A position describing an operand group of an operation. struct OperandGroupPosition : public PredicateBase< OperandGroupPosition, Position, std::tuple<OperationPosition *, std::optional<unsigned>, bool>, Predicates::OperandGroupPos> { … }; //===----------------------------------------------------------------------===// // OperationPosition /// An operation position describes an operation node in the IR. Other position /// kinds are formed with respect to an operation position. struct OperationPosition : public PredicateBase<OperationPosition, Position, std::pair<Position *, unsigned>, Predicates::OperationPos> { … }; //===----------------------------------------------------------------------===// // ConstraintPosition struct ConstraintQuestion; /// A position describing the result of a native constraint. It saves the /// corresponding ConstraintQuestion and result index to enable referring /// back to them struct ConstraintPosition : public PredicateBase<ConstraintPosition, Position, std::pair<ConstraintQuestion *, unsigned>, Predicates::ConstraintResultPos> { … }; //===----------------------------------------------------------------------===// // ResultPosition /// A position describing a result of an operation. struct ResultPosition : public PredicateBase<ResultPosition, Position, std::pair<OperationPosition *, unsigned>, Predicates::ResultPos> { … }; //===----------------------------------------------------------------------===// // ResultGroupPosition /// A position describing a result group of an operation. struct ResultGroupPosition : public PredicateBase< ResultGroupPosition, Position, std::tuple<OperationPosition *, std::optional<unsigned>, bool>, Predicates::ResultGroupPos> { … }; //===----------------------------------------------------------------------===// // TypePosition /// A position describing the result type of an entity, i.e. an Attribute, /// Operand, Result, etc. struct TypePosition : public PredicateBase<TypePosition, Position, Position *, Predicates::TypePos> { … }; //===----------------------------------------------------------------------===// // TypeLiteralPosition /// A position describing a literal type or type range. The value is stored as /// either a TypeAttr, or an ArrayAttr of TypeAttr. struct TypeLiteralPosition : public PredicateBase<TypeLiteralPosition, Position, Attribute, Predicates::TypeLiteralPos> { … }; //===----------------------------------------------------------------------===// // UsersPosition /// A position describing the users of a value or a range of values. The second /// value in the key indicates whether we choose users of a representative for /// a range (this is true, e.g., in the upward traversals). struct UsersPosition : public PredicateBase<UsersPosition, Position, std::pair<Position *, bool>, Predicates::UsersPos> { … }; //===----------------------------------------------------------------------===// // Qualifiers //===----------------------------------------------------------------------===// /// An ordinal predicate consists of a "Question" and a set of acceptable /// "Answers" (later converted to ordinal values). A predicate will query some /// property of a positional value and decide what to do based on the result. /// /// This makes top-level predicate representations ordinal (SwitchOp). Later, /// predicates that end up with only one acceptable answer (including all /// boolean kinds) will be converted to boolean predicates (PredicateOp) in the /// matcher. /// /// For simplicity, both are represented as "qualifiers", with a base kind and /// perhaps additional properties. For example, all OperationName predicates ask /// the same question, but GenericConstraint predicates may ask different ones. class Qualifier : public StorageUniquer::BaseStorage { … }; //===----------------------------------------------------------------------===// // Answers /// An Answer representing an `Attribute` value. struct AttributeAnswer : public PredicateBase<AttributeAnswer, Qualifier, Attribute, Predicates::AttributeAnswer> { … }; /// An Answer representing an `OperationName` value. struct OperationNameAnswer : public PredicateBase<OperationNameAnswer, Qualifier, OperationName, Predicates::OperationNameAnswer> { … }; /// An Answer representing a boolean `true` value. struct TrueAnswer : PredicateBase<TrueAnswer, Qualifier, void, Predicates::TrueAnswer> { … }; /// An Answer representing a boolean 'false' value. struct FalseAnswer : PredicateBase<FalseAnswer, Qualifier, void, Predicates::FalseAnswer> { … }; /// An Answer representing a `Type` value. The value is stored as either a /// TypeAttr, or an ArrayAttr of TypeAttr. struct TypeAnswer : public PredicateBase<TypeAnswer, Qualifier, Attribute, Predicates::TypeAnswer> { … }; /// An Answer representing an unsigned value. struct UnsignedAnswer : public PredicateBase<UnsignedAnswer, Qualifier, unsigned, Predicates::UnsignedAnswer> { … }; //===----------------------------------------------------------------------===// // Questions /// Compare an `Attribute` to a constant value. struct AttributeQuestion : public PredicateBase<AttributeQuestion, Qualifier, void, Predicates::AttributeQuestion> { … }; /// Apply a parameterized constraint to multiple position values and possibly /// produce results. struct ConstraintQuestion : public PredicateBase< ConstraintQuestion, Qualifier, std::tuple<StringRef, ArrayRef<Position *>, ArrayRef<Type>, bool>, Predicates::ConstraintQuestion> { … }; /// Compare the equality of two values. struct EqualToQuestion : public PredicateBase<EqualToQuestion, Qualifier, Position *, Predicates::EqualToQuestion> { … }; /// Compare a positional value with null, i.e. check if it exists. struct IsNotNullQuestion : public PredicateBase<IsNotNullQuestion, Qualifier, void, Predicates::IsNotNullQuestion> { … }; /// Compare the number of operands of an operation with a known value. struct OperandCountQuestion : public PredicateBase<OperandCountQuestion, Qualifier, void, Predicates::OperandCountQuestion> { … }; struct OperandCountAtLeastQuestion : public PredicateBase<OperandCountAtLeastQuestion, Qualifier, void, Predicates::OperandCountAtLeastQuestion> { … }; /// Compare the name of an operation with a known value. struct OperationNameQuestion : public PredicateBase<OperationNameQuestion, Qualifier, void, Predicates::OperationNameQuestion> { … }; /// Compare the number of results of an operation with a known value. struct ResultCountQuestion : public PredicateBase<ResultCountQuestion, Qualifier, void, Predicates::ResultCountQuestion> { … }; struct ResultCountAtLeastQuestion : public PredicateBase<ResultCountAtLeastQuestion, Qualifier, void, Predicates::ResultCountAtLeastQuestion> { … }; /// Compare the type of an attribute or value with a known type. struct TypeQuestion : public PredicateBase<TypeQuestion, Qualifier, void, Predicates::TypeQuestion> { … }; //===----------------------------------------------------------------------===// // PredicateUniquer //===----------------------------------------------------------------------===// /// This class provides a storage uniquer that is used to allocate predicate /// instances. class PredicateUniquer : public StorageUniquer { … }; //===----------------------------------------------------------------------===// // PredicateBuilder //===----------------------------------------------------------------------===// /// This class provides utilities for constructing predicates. class PredicateBuilder { … }; } // namespace pdl_to_pdl_interp } // namespace mlir #endif // MLIR_CONVERSION_PDLTOPDLINTERP_PREDICATE_H_