//===- PatternMatch.h - PatternMatcher classes -------==---------*- 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 // //===----------------------------------------------------------------------===// #ifndef MLIR_IR_PATTERNMATCH_H #define MLIR_IR_PATTERNMATCH_H #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinOps.h" #include "llvm/ADT/FunctionExtras.h" #include "llvm/Support/TypeName.h" #include using llvm::SmallPtrSetImpl; namespace mlir { class PatternRewriter; //===----------------------------------------------------------------------===// // PatternBenefit class //===----------------------------------------------------------------------===// /// This class represents the benefit of a pattern match in a unitless scheme /// that ranges from 0 (very little benefit) to 65K. The most common unit to /// use here is the "number of operations matched" by the pattern. /// /// This also has a sentinel representation that can be used for patterns that /// fail to match. /// class PatternBenefit { enum { ImpossibleToMatchSentinel = 65535 }; public: PatternBenefit() = default; PatternBenefit(unsigned benefit); PatternBenefit(const PatternBenefit &) = default; PatternBenefit &operator=(const PatternBenefit &) = default; static PatternBenefit impossibleToMatch() { return PatternBenefit(); } bool isImpossibleToMatch() const { return *this == impossibleToMatch(); } /// If the corresponding pattern can match, return its benefit. If the // corresponding pattern isImpossibleToMatch() then this aborts. unsigned short getBenefit() const; bool operator==(const PatternBenefit &rhs) const { return representation == rhs.representation; } bool operator!=(const PatternBenefit &rhs) const { return !(*this == rhs); } bool operator<(const PatternBenefit &rhs) const { return representation < rhs.representation; } bool operator>(const PatternBenefit &rhs) const { return rhs < *this; } bool operator<=(const PatternBenefit &rhs) const { return !(*this > rhs); } bool operator>=(const PatternBenefit &rhs) const { return !(*this < rhs); } private: unsigned short representation{ImpossibleToMatchSentinel}; }; //===----------------------------------------------------------------------===// // Pattern //===----------------------------------------------------------------------===// /// This class contains all of the data related to a pattern, but does not /// contain any methods or logic for the actual matching. This class is solely /// used to interface with the metadata of a pattern, such as the benefit or /// root operation. class Pattern { /// This enum represents the kind of value used to select the root operations /// that match this pattern. enum class RootKind { /// The pattern root matches "any" operation. Any, /// The pattern root is matched using a concrete operation name. OperationName, /// The pattern root is matched using an interface ID. InterfaceID, /// The patter root is matched using a trait ID. TraitID }; public: /// Return a list of operations that may be generated when rewriting an /// operation instance with this pattern. ArrayRef getGeneratedOps() const { return generatedOps; } /// Return the root node that this pattern matches. Patterns that can match /// multiple root types return std::nullopt. std::optional getRootKind() const { if (rootKind == RootKind::OperationName) return OperationName::getFromOpaquePointer(rootValue); return std::nullopt; } /// Return the interface ID used to match the root operation of this pattern. /// If the pattern does not use an interface ID for deciding the root match, /// this returns std::nullopt. std::optional getRootInterfaceID() const { if (rootKind == RootKind::InterfaceID) return TypeID::getFromOpaquePointer(rootValue); return std::nullopt; } /// Return the trait ID used to match the root operation of this pattern. /// If the pattern does not use a trait ID for deciding the root match, this /// returns std::nullopt. std::optional getRootTraitID() const { if (rootKind == RootKind::TraitID) return TypeID::getFromOpaquePointer(rootValue); return std::nullopt; } /// Return the benefit (the inverse of "cost") of matching this pattern. The /// benefit of a Pattern is always static - rewrites that may have dynamic /// benefit can be instantiated multiple times (different Pattern instances) /// for each benefit that they may return, and be guarded by different match /// condition predicates. PatternBenefit getBenefit() const { return benefit; } /// Returns true if this pattern is known to result in recursive application, /// i.e. this pattern may generate IR that also matches this pattern, but is /// known to bound the recursion. This signals to a rewrite driver that it is /// safe to apply this pattern recursively to generated IR. bool hasBoundedRewriteRecursion() const { return contextAndHasBoundedRecursion.getInt(); } /// Return the MLIRContext used to create this pattern. MLIRContext *getContext() const { return contextAndHasBoundedRecursion.getPointer(); } /// Return a readable name for this pattern. This name should only be used for /// debugging purposes, and may be empty. StringRef getDebugName() const { return debugName; } /// Set the human readable debug name used for this pattern. This name will /// only be used for debugging purposes. void setDebugName(StringRef name) { debugName = name; } /// Return the set of debug labels attached to this pattern. ArrayRef getDebugLabels() const { return debugLabels; } /// Add the provided debug labels to this pattern. void addDebugLabels(ArrayRef labels) { debugLabels.append(labels.begin(), labels.end()); } void addDebugLabels(StringRef label) { debugLabels.push_back(label); } protected: /// This class acts as a special tag that makes the desire to match "any" /// operation type explicit. This helps to avoid unnecessary usages of this /// feature, and ensures that the user is making a conscious decision. struct MatchAnyOpTypeTag {}; /// This class acts as a special tag that makes the desire to match any /// operation that implements a given interface explicit. This helps to avoid /// unnecessary usages of this feature, and ensures that the user is making a /// conscious decision. struct MatchInterfaceOpTypeTag {}; /// This class acts as a special tag that makes the desire to match any /// operation that implements a given trait explicit. This helps to avoid /// unnecessary usages of this feature, and ensures that the user is making a /// conscious decision. struct MatchTraitOpTypeTag {}; /// Construct a pattern with a certain benefit that matches the operation /// with the given root name. Pattern(StringRef rootName, PatternBenefit benefit, MLIRContext *context, ArrayRef generatedNames = {}); /// Construct a pattern that may match any operation type. `generatedNames` /// contains the names of operations that may be generated during a successful /// rewrite. `MatchAnyOpTypeTag` is just a tag to ensure that the "match any" /// behavior is what the user actually desired, `MatchAnyOpTypeTag()` should /// always be supplied here. Pattern(MatchAnyOpTypeTag tag, PatternBenefit benefit, MLIRContext *context, ArrayRef generatedNames = {}); /// Construct a pattern that may match any operation that implements the /// interface defined by the provided `interfaceID`. `generatedNames` contains /// the names of operations that may be generated during a successful rewrite. /// `MatchInterfaceOpTypeTag` is just a tag to ensure that the "match /// interface" behavior is what the user actually desired, /// `MatchInterfaceOpTypeTag()` should always be supplied here. Pattern(MatchInterfaceOpTypeTag tag, TypeID interfaceID, PatternBenefit benefit, MLIRContext *context, ArrayRef generatedNames = {}); /// Construct a pattern that may match any operation that implements the /// trait defined by the provided `traitID`. `generatedNames` contains the /// names of operations that may be generated during a successful rewrite. /// `MatchTraitOpTypeTag` is just a tag to ensure that the "match trait" /// behavior is what the user actually desired, `MatchTraitOpTypeTag()` should /// always be supplied here. Pattern(MatchTraitOpTypeTag tag, TypeID traitID, PatternBenefit benefit, MLIRContext *context, ArrayRef generatedNames = {}); /// Set the flag detailing if this pattern has bounded rewrite recursion or /// not. void setHasBoundedRewriteRecursion(bool hasBoundedRecursionArg = true) { contextAndHasBoundedRecursion.setInt(hasBoundedRecursionArg); } private: Pattern(const void *rootValue, RootKind rootKind, ArrayRef generatedNames, PatternBenefit benefit, MLIRContext *context); /// The value used to match the root operation of the pattern. const void *rootValue; RootKind rootKind; /// The expected benefit of matching this pattern. const PatternBenefit benefit; /// The context this pattern was created from, and a boolean flag indicating /// whether this pattern has bounded recursion or not. llvm::PointerIntPair contextAndHasBoundedRecursion; /// A list of the potential operations that may be generated when rewriting /// an op with this pattern. SmallVector generatedOps; /// A readable name for this pattern. May be empty. StringRef debugName; /// The set of debug labels attached to this pattern. SmallVector debugLabels; }; //===----------------------------------------------------------------------===// // RewritePattern //===----------------------------------------------------------------------===// /// RewritePattern is the common base class for all DAG to DAG replacements. class RewritePattern : public Pattern { public: virtual ~RewritePattern() = default; /// Attempt to match against code rooted at the specified operation, /// which is the same operation code as getRootKind(). If successful, perform /// the rewrite. /// /// Note: Implementations must modify the IR if and only if the function /// returns "success". virtual LogicalResult matchAndRewrite(Operation *op, PatternRewriter &rewriter) const = 0; /// This method provides a convenient interface for creating and initializing /// derived rewrite patterns of the given type `T`. template static std::unique_ptr create(Args &&...args) { std::unique_ptr pattern = std::make_unique(std::forward(args)...); initializePattern(*pattern); // Set a default debug name if one wasn't provided. if (pattern->getDebugName().empty()) pattern->setDebugName(llvm::getTypeName()); return pattern; } protected: /// Inherit the base constructors from `Pattern`. using Pattern::Pattern; private: /// Trait to check if T provides a `initialize` method. template using has_initialize = decltype(std::declval().initialize()); template using detect_has_initialize = llvm::is_detected; /// Initialize the derived pattern by calling its `initialize` method if /// available. template static void initializePattern(T &pattern) { if constexpr (detect_has_initialize::value) pattern.initialize(); } /// An anchor for the virtual table. virtual void anchor(); }; namespace detail { /// OpOrInterfaceRewritePatternBase is a wrapper around RewritePattern that /// allows for matching and rewriting against an instance of a derived operation /// class or Interface. template struct OpOrInterfaceRewritePatternBase : public RewritePattern { using RewritePattern::RewritePattern; /// Wrapper around the RewritePattern method that passes the derived op type. LogicalResult matchAndRewrite(Operation *op, PatternRewriter &rewriter) const final { return matchAndRewrite(cast(op), rewriter); } /// Method that operates on the SourceOp type. Must be overridden by the /// derived pattern class. virtual LogicalResult matchAndRewrite(SourceOp op, PatternRewriter &rewriter) const = 0; }; } // namespace detail /// OpRewritePattern is a wrapper around RewritePattern that allows for /// matching and rewriting against an instance of a derived operation class as /// opposed to a raw Operation. template struct OpRewritePattern : public mlir::detail::OpOrInterfaceRewritePatternBase { /// Type alias to allow derived classes to inherit constructors with /// `using Base::Base;`. using Base = OpRewritePattern; /// Patterns must specify the root operation name they match against, and can /// also specify the benefit of the pattern matching and a list of generated /// ops. OpRewritePattern(MLIRContext *context, PatternBenefit benefit = 1, ArrayRef generatedNames = {}) : mlir::detail::OpOrInterfaceRewritePatternBase( SourceOp::getOperationName(), benefit, context, generatedNames) {} }; /// OpInterfaceRewritePattern is a wrapper around RewritePattern that allows for /// matching and rewriting against an instance of an operation interface instead /// of a raw Operation. template struct OpInterfaceRewritePattern : public mlir::detail::OpOrInterfaceRewritePatternBase { /// Type alias to allow derived classes to inherit constructors with /// `using Base::Base;`. using Base = OpInterfaceRewritePattern; OpInterfaceRewritePattern(MLIRContext *context, PatternBenefit benefit = 1) : mlir::detail::OpOrInterfaceRewritePatternBase( Pattern::MatchInterfaceOpTypeTag(), SourceOp::getInterfaceID(), benefit, context) {} }; /// OpTraitRewritePattern is a wrapper around RewritePattern that allows for /// matching and rewriting against instances of an operation that possess a /// given trait. template