Files
gps/tools/local/circt/include/mlir/Query/Matcher/Marshallers.h
T
2026-07-12 11:01:51 +03:00

291 lines
10 KiB
C++

//===--- Marshallers.h - Generic matcher function marshallers ---*- 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 function templates and classes to wrap matcher construct
// functions. It provides a collection of template function and classes that
// present a generic marshalling layer on top of matcher construct functions.
// The registry uses these to export all marshaller constructors with a uniform
// interface. This mechanism takes inspiration from clang-query.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_TOOLS_MLIRQUERY_MATCHER_MARSHALLERS_H
#define MLIR_TOOLS_MLIRQUERY_MATCHER_MARSHALLERS_H
#include "ErrorBuilder.h"
#include "VariantValue.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
namespace mlir::query::matcher::internal {
// Helper template class for jumping from argument type to the correct is/get
// functions in VariantValue. This is used for verifying and extracting the
// matcher arguments.
template <class T>
struct ArgTypeTraits;
template <class T>
struct ArgTypeTraits<const T &> : public ArgTypeTraits<T> {};
template <>
struct ArgTypeTraits<llvm::StringRef> {
static bool hasCorrectType(const VariantValue &value) {
return value.isString();
}
static const llvm::StringRef &get(const VariantValue &value) {
return value.getString();
}
static ArgKind getKind() { return ArgKind::String; }
static std::optional<std::string> getBestGuess(const VariantValue &) {
return std::nullopt;
}
};
template <>
struct ArgTypeTraits<int64_t> {
static bool hasCorrectType(const VariantValue &value) {
return value.isSigned();
}
static unsigned get(const VariantValue &value) { return value.getSigned(); }
static ArgKind getKind() { return ArgKind::Signed; }
static std::optional<std::string> getBestGuess(const VariantValue &) {
return std::nullopt;
}
};
template <>
struct ArgTypeTraits<bool> {
static bool hasCorrectType(const VariantValue &value) {
return value.isBoolean();
}
static unsigned get(const VariantValue &value) { return value.getBoolean(); }
static ArgKind getKind() { return ArgKind::Boolean; }
static std::optional<std::string> getBestGuess(const VariantValue &) {
return std::nullopt;
}
};
template <>
struct ArgTypeTraits<DynMatcher> {
static bool hasCorrectType(const VariantValue &value) {
return value.isMatcher();
}
static DynMatcher get(const VariantValue &value) {
return *value.getMatcher().getDynMatcher();
}
static ArgKind getKind() { return ArgKind::Matcher; }
static std::optional<std::string> getBestGuess(const VariantValue &) {
return std::nullopt;
}
};
// Interface for generic matcher descriptor.
// Offers a create() method that constructs the matcher from the provided
// arguments.
class MatcherDescriptor {
public:
virtual ~MatcherDescriptor() = default;
virtual VariantMatcher create(SourceRange nameRange,
const llvm::ArrayRef<ParserValue> args,
Diagnostics *error) const = 0;
// If the matcher is variadic, it can take any number of arguments.
virtual bool isVariadic() const = 0;
// Returns the number of arguments accepted by the matcher.
virtual unsigned getNumArgs() const = 0;
// Append the set of argument types accepted for argument 'argNo' to
// 'argKinds'.
virtual void getArgKinds(unsigned argNo,
std::vector<ArgKind> &argKinds) const = 0;
};
class FixedArgCountMatcherDescriptor : public MatcherDescriptor {
public:
using MarshallerType = VariantMatcher (*)(void (*matcherFunc)(),
llvm::StringRef matcherName,
SourceRange nameRange,
llvm::ArrayRef<ParserValue> args,
Diagnostics *error);
// Marshaller Function to unpack the arguments and call Func. Func is the
// Matcher construct function. This is the function that the matcher
// expressions would use to create the matcher.
FixedArgCountMatcherDescriptor(MarshallerType marshaller,
void (*matcherFunc)(),
llvm::StringRef matcherName,
llvm::ArrayRef<ArgKind> argKinds)
: marshaller(marshaller), matcherFunc(matcherFunc),
matcherName(matcherName), argKinds(argKinds.begin(), argKinds.end()) {}
VariantMatcher create(SourceRange nameRange, llvm::ArrayRef<ParserValue> args,
Diagnostics *error) const override {
return marshaller(matcherFunc, matcherName, nameRange, args, error);
}
bool isVariadic() const override { return false; }
unsigned getNumArgs() const override { return argKinds.size(); }
void getArgKinds(unsigned argNo, std::vector<ArgKind> &kinds) const override {
kinds.push_back(argKinds[argNo]);
}
private:
const MarshallerType marshaller;
void (*const matcherFunc)();
const llvm::StringRef matcherName;
const std::vector<ArgKind> argKinds;
};
class VariadicOperatorMatcherDescriptor : public MatcherDescriptor {
public:
using VarOp = DynMatcher::VariadicOperator;
VariadicOperatorMatcherDescriptor(unsigned minCount, unsigned maxCount,
VarOp varOp, StringRef matcherName)
: minCount(minCount), maxCount(maxCount), varOp(varOp),
matcherName(matcherName) {}
VariantMatcher create(SourceRange nameRange, ArrayRef<ParserValue> args,
Diagnostics *error) const override {
if (args.size() < minCount || maxCount < args.size()) {
addError(error, nameRange, ErrorType::RegistryWrongArgCount,
{llvm::Twine("requires between "), llvm::Twine(minCount),
llvm::Twine(" and "), llvm::Twine(maxCount),
llvm::Twine(" args, got "), llvm::Twine(args.size())});
return VariantMatcher();
}
std::vector<VariantMatcher> innerArgs;
for (int64_t i = 0, e = args.size(); i != e; ++i) {
const ParserValue &arg = args[i];
const VariantValue &value = arg.value;
if (!value.isMatcher()) {
addError(error, arg.range, ErrorType::RegistryWrongArgType,
{llvm::Twine(i + 1), llvm::Twine("matcher: "),
llvm::Twine(value.getTypeAsString())});
return VariantMatcher();
}
innerArgs.push_back(value.getMatcher());
}
return VariantMatcher::VariadicOperatorMatcher(varOp, std::move(innerArgs));
}
bool isVariadic() const override { return true; }
unsigned getNumArgs() const override { return 0; }
void getArgKinds(unsigned argNo, std::vector<ArgKind> &kinds) const override {
kinds.push_back(ArgKind(ArgKind::Matcher));
}
private:
const unsigned minCount;
const unsigned maxCount;
const VarOp varOp;
const StringRef matcherName;
};
// Helper function to check if argument count matches expected count
inline bool checkArgCount(SourceRange nameRange, size_t expectedArgCount,
llvm::ArrayRef<ParserValue> args,
Diagnostics *error) {
if (args.size() != expectedArgCount) {
addError(error, nameRange, ErrorType::RegistryWrongArgCount,
{llvm::Twine(expectedArgCount), llvm::Twine(args.size())});
return false;
}
return true;
}
// Helper function for checking argument type
template <typename ArgType, size_t Index>
inline bool checkArgTypeAtIndex(llvm::StringRef matcherName,
llvm::ArrayRef<ParserValue> args,
Diagnostics *error) {
if (!ArgTypeTraits<ArgType>::hasCorrectType(args[Index].value)) {
addError(error, args[Index].range, ErrorType::RegistryWrongArgType,
{llvm::Twine(matcherName), llvm::Twine(Index + 1)});
return false;
}
return true;
}
// Marshaller function for fixed number of arguments
template <typename ReturnType, typename... ArgTypes, size_t... Is>
static VariantMatcher
matcherMarshallFixedImpl(void (*matcherFunc)(), llvm::StringRef matcherName,
SourceRange nameRange,
llvm::ArrayRef<ParserValue> args, Diagnostics *error,
std::index_sequence<Is...>) {
using FuncType = ReturnType (*)(ArgTypes...);
// Check if the argument count matches the expected count
if (!checkArgCount(nameRange, sizeof...(ArgTypes), args, error))
return VariantMatcher();
// Check if each argument at the corresponding index has the correct type
if ((... && checkArgTypeAtIndex<ArgTypes, Is>(matcherName, args, error))) {
ReturnType fnPointer = reinterpret_cast<FuncType>(matcherFunc)(
ArgTypeTraits<ArgTypes>::get(args[Is].value)...);
return VariantMatcher::SingleMatcher(
*DynMatcher::constructDynMatcherFromMatcherFn(fnPointer));
}
return VariantMatcher();
}
template <typename ReturnType, typename... ArgTypes>
static VariantMatcher
matcherMarshallFixed(void (*matcherFunc)(), llvm::StringRef matcherName,
SourceRange nameRange, llvm::ArrayRef<ParserValue> args,
Diagnostics *error) {
return matcherMarshallFixedImpl<ReturnType, ArgTypes...>(
matcherFunc, matcherName, nameRange, args, error,
std::index_sequence_for<ArgTypes...>{});
}
// Fixed number of arguments overload
template <typename ReturnType, typename... ArgTypes>
std::unique_ptr<MatcherDescriptor>
makeMatcherAutoMarshall(ReturnType (*matcherFunc)(ArgTypes...),
llvm::StringRef matcherName) {
// Create a vector of argument kinds
std::vector<ArgKind> argKinds = {ArgTypeTraits<ArgTypes>::getKind()...};
return std::make_unique<FixedArgCountMatcherDescriptor>(
matcherMarshallFixed<ReturnType, ArgTypes...>,
reinterpret_cast<void (*)()>(matcherFunc), matcherName, argKinds);
}
// Variadic operator overload.
template <unsigned MinCount, unsigned MaxCount>
std::unique_ptr<MatcherDescriptor>
makeMatcherAutoMarshall(VariadicOperatorMatcherFunc<MinCount, MaxCount> func,
StringRef matcherName) {
return std::make_unique<VariadicOperatorMatcherDescriptor>(
MinCount, MaxCount, func.varOp, matcherName);
}
} // namespace mlir::query::matcher::internal
#endif // MLIR_TOOLS_MLIRQUERY_MATCHER_MARSHALLERS_H