//===- MatchersInternal.h - Structural query framework ----------*- 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 // //===----------------------------------------------------------------------===// // // Implements the base layer of the matcher framework. // // Matchers are methods that return a Matcher which provides a // `match(...)` method whose parameters define the context of the match. // Support includes simple (unary) matchers as well as matcher combinators // (anyOf, allOf, etc.) // // This file contains the wrapper classes needed to construct matchers for // mlir-query. // //===----------------------------------------------------------------------===// #ifndef MLIR_TOOLS_MLIRQUERY_MATCHER_MATCHERSINTERNAL_H #define MLIR_TOOLS_MLIRQUERY_MATCHER_MATCHERSINTERNAL_H #include "mlir/IR/Matchers.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" namespace mlir::query::matcher { class DynMatcher; namespace internal { bool allOfVariadicOperator(Operation *op, SetVector *matchedOps, ArrayRef innerMatchers); bool anyOfVariadicOperator(Operation *op, SetVector *matchedOps, ArrayRef innerMatchers); } // namespace internal // Defaults to false if T has no match() method with the signature: // match(Operation* op). template struct has_simple_match : std::false_type {}; // Specialized type trait that evaluates to true if T has a match() method // with the signature: match(Operation* op). template struct has_simple_match().match( std::declval()))>> : std::true_type {}; // Defaults to false if T has no match() method with the signature: // match(Operation* op, SetVector&). template struct has_bound_match : std::false_type {}; // Specialized type trait that evaluates to true if T has a match() method // with the signature: match(Operation* op, SetVector&). template struct has_bound_match().match( std::declval(), std::declval &>()))>> : std::true_type {}; // Generic interface for matchers on an MLIR operation. class MatcherInterface : public llvm::ThreadSafeRefCountedBase { public: virtual ~MatcherInterface() = default; virtual bool match(Operation *op) = 0; virtual bool match(Operation *op, SetVector &matchedOps) = 0; }; // MatcherFnImpl takes a matcher function object and implements // MatcherInterface. template class MatcherFnImpl : public MatcherInterface { public: MatcherFnImpl(MatcherFn &matcherFn) : matcherFn(matcherFn) {} bool match(Operation *op) override { if constexpr (has_simple_match::value) return matcherFn.match(op); return false; } bool match(Operation *op, SetVector &matchedOps) override { if constexpr (has_bound_match::value) return matcherFn.match(op, matchedOps); return false; } private: MatcherFn matcherFn; }; // VariadicMatcher takes a vector of Matchers and returns true if any Matchers // match the given operation. using VariadicOperatorFunction = bool (*)(Operation *op, SetVector *matchedOps, ArrayRef innerMatchers); template class VariadicMatcher : public MatcherInterface { public: VariadicMatcher(std::vector matchers) : matchers(std::move(matchers)) {} bool match(Operation *op) override { return Func(op, nullptr, matchers); } bool match(Operation *op, SetVector &matchedOps) override { return Func(op, &matchedOps, matchers); } private: std::vector matchers; }; // Matcher wraps a MatcherInterface implementation and provides match() // methods that redirect calls to the underlying implementation. class DynMatcher { public: // Takes ownership of the provided implementation pointer. DynMatcher(MatcherInterface *implementation) : implementation(implementation) {} // Construct from a variadic function. enum VariadicOperator { // Matches operations for which all provided matchers match. AllOf, // Matches operations for which at least one of the provided matchers // matches. AnyOf }; static std::unique_ptr constructVariadic(VariadicOperator Op, std::vector innerMatchers) { switch (Op) { case AllOf: return std::make_unique( new VariadicMatcher( std::move(innerMatchers))); case AnyOf: return std::make_unique( new VariadicMatcher( std::move(innerMatchers))); } llvm_unreachable("Invalid Op value."); } template static std::unique_ptr constructDynMatcherFromMatcherFn(MatcherFn &matcherFn) { auto impl = std::make_unique>(matcherFn); return std::make_unique(impl.release()); } bool match(Operation *op) const { return implementation->match(op); } bool match(Operation *op, SetVector &matchedOps) const { return implementation->match(op, matchedOps); } void setFunctionName(StringRef name) { functionName = name.str(); } bool hasFunctionName() const { return !functionName.empty(); } StringRef getFunctionName() const { return functionName; } private: llvm::IntrusiveRefCntPtr implementation; std::string functionName; }; // VariadicOperatorMatcher related types. template class VariadicOperatorMatcher { public: VariadicOperatorMatcher(DynMatcher::VariadicOperator varOp, Ps &&...params) : varOp(varOp), params(std::forward(params)...) {} operator std::unique_ptr() const & { return DynMatcher::constructVariadic( varOp, getMatchers(std::index_sequence_for())); } operator std::unique_ptr() && { return DynMatcher::constructVariadic( varOp, std::move(*this).getMatchers(std::index_sequence_for())); } private: // Helper method to unpack the tuple into a vector. template std::vector getMatchers(std::index_sequence) const & { return {DynMatcher(std::get(params))...}; } template std::vector getMatchers(std::index_sequence) && { return {DynMatcher(std::get(std::move(params)))...}; } const DynMatcher::VariadicOperator varOp; std::tuple params; }; // Overloaded function object to generate VariadicOperatorMatcher objects from // arbitrary matchers. template struct VariadicOperatorMatcherFunc { DynMatcher::VariadicOperator varOp; template VariadicOperatorMatcher operator()(Ms &&...Ps) const { static_assert(MinCount <= sizeof...(Ms) && sizeof...(Ms) <= MaxCount, "invalid number of parameters for variadic matcher"); return VariadicOperatorMatcher(varOp, std::forward(Ps)...); } }; namespace internal { const VariadicOperatorMatcherFunc<1, std::numeric_limits::max()> anyOf = {DynMatcher::AnyOf}; const VariadicOperatorMatcherFunc<1, std::numeric_limits::max()> allOf = {DynMatcher::AllOf}; } // namespace internal } // namespace mlir::query::matcher #endif // MLIR_TOOLS_MLIRQUERY_MATCHER_MATCHERSINTERNAL_H