904 lines
33 KiB
C++
904 lines
33 KiB
C++
//===- Class.h - Helper classes for C++ code emission -----------*- 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 defines several classes for C++ code emission. They are only
|
|
// expected to be used by MLIR TableGen backends.
|
|
//
|
|
// We emit the declarations and definitions into separate files: *.h.inc and
|
|
// *.cpp.inc. The former is to be included in the dialect *.h and the latter for
|
|
// dialect *.cpp. This way provides a cleaner interface.
|
|
//
|
|
// In order to do this split, we need to track method signature and
|
|
// implementation logic separately. Signature information is used for both
|
|
// declaration and definition, while implementation logic is only for
|
|
// definition. So we have the following classes for C++ code emission.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef MLIR_TABLEGEN_CLASS_H_
|
|
#define MLIR_TABLEGEN_CLASS_H_
|
|
|
|
#include "mlir/Support/IndentedOstream.h"
|
|
#include "mlir/Support/LLVM.h"
|
|
#include "mlir/TableGen/CodeGenHelpers.h"
|
|
#include "llvm/ADT/SetVector.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/StringSet.h"
|
|
#include "llvm/ADT/Twine.h"
|
|
|
|
#include <set>
|
|
#include <string>
|
|
|
|
namespace mlir {
|
|
namespace tblgen {
|
|
class FmtObjectBase;
|
|
|
|
/// This class contains a single method parameter for a C++ function.
|
|
class MethodParameter {
|
|
public:
|
|
/// Create a method parameter with a C++ type, parameter name, and an optional
|
|
/// default value. Marking a parameter as "optional" is a cosmetic effect on
|
|
/// the generated code.
|
|
template <typename TypeT, typename NameT, typename DefaultT>
|
|
MethodParameter(TypeT &&type, NameT &&name, DefaultT &&defaultValue,
|
|
bool optional = false)
|
|
: type(stringify(std::forward<TypeT>(type))),
|
|
name(stringify(std::forward<NameT>(name))),
|
|
defaultValue(stringify(std::forward<DefaultT>(defaultValue))),
|
|
optional(optional) {}
|
|
|
|
/// Create a method parameter with a C++ type, parameter name, and no default
|
|
/// value.
|
|
template <typename TypeT, typename NameT>
|
|
MethodParameter(TypeT &&type, NameT &&name, bool optional = false)
|
|
: MethodParameter(std::forward<TypeT>(type), std::forward<NameT>(name),
|
|
/*defaultValue=*/"", optional) {}
|
|
|
|
/// Write the parameter as part of a method declaration.
|
|
void writeDeclTo(raw_indented_ostream &os) const;
|
|
/// Write the parameter as part of a method definition.
|
|
void writeDefTo(raw_indented_ostream &os) const;
|
|
|
|
/// Get the C++ type.
|
|
StringRef getType() const { return type; }
|
|
/// Get the C++ parameter name.
|
|
StringRef getName() const { return name; }
|
|
/// Returns true if the parameter has a default value.
|
|
bool hasDefaultValue() const { return !defaultValue.empty(); }
|
|
/// Get the default value.
|
|
StringRef getDefaultValue() const { return defaultValue; }
|
|
/// Returns true if the parameter is optional.
|
|
bool isOptional() const { return optional; }
|
|
|
|
private:
|
|
/// The C++ type.
|
|
std::string type;
|
|
/// The variable name.
|
|
std::string name;
|
|
/// An optional default value. The default value exists if the string is not
|
|
/// empty.
|
|
std::string defaultValue;
|
|
/// Whether the parameter should be indicated as "optional".
|
|
bool optional;
|
|
};
|
|
|
|
/// This class contains a list of method parameters for constructor, class
|
|
/// methods, and method signatures.
|
|
class MethodParameters {
|
|
public:
|
|
/// Create a list of method parameters.
|
|
MethodParameters(std::initializer_list<MethodParameter> parameters)
|
|
: parameters(parameters) {}
|
|
MethodParameters(SmallVector<MethodParameter> parameters)
|
|
: parameters(std::move(parameters)) {}
|
|
|
|
/// Write the parameters as part of a method declaration.
|
|
void writeDeclTo(raw_indented_ostream &os) const;
|
|
/// Write the parameters as part of a method definition.
|
|
void writeDefTo(raw_indented_ostream &os) const;
|
|
|
|
/// Determine whether this list of parameters "subsumes" another, which occurs
|
|
/// when this parameter list is identical to the other and has zero or more
|
|
/// additional default-valued parameters.
|
|
bool subsumes(const MethodParameters &other) const;
|
|
|
|
/// Return the number of parameters.
|
|
unsigned getNumParameters() const { return parameters.size(); }
|
|
|
|
private:
|
|
/// The list of parameters.
|
|
SmallVector<MethodParameter> parameters;
|
|
};
|
|
|
|
/// This class contains the signature of a C++ method, including the return
|
|
/// type. method name, and method parameters.
|
|
class MethodSignature {
|
|
public:
|
|
/// Create a method signature with a return type, a method name, and a list of
|
|
/// parameters. Take ownership of the list.
|
|
template <typename RetTypeT, typename NameT>
|
|
MethodSignature(RetTypeT &&retType, NameT &&name,
|
|
SmallVector<MethodParameter> &¶meters)
|
|
: returnType(stringify(std::forward<RetTypeT>(retType))),
|
|
methodName(stringify(std::forward<NameT>(name))),
|
|
parameters(std::move(parameters)) {}
|
|
/// Create a method signature with a return type, a method name, and a list of
|
|
/// parameters.
|
|
template <typename RetTypeT, typename NameT>
|
|
MethodSignature(RetTypeT &&retType, NameT &&name,
|
|
ArrayRef<MethodParameter> parameters)
|
|
: MethodSignature(std::forward<RetTypeT>(retType),
|
|
std::forward<NameT>(name),
|
|
SmallVector<MethodParameter>(parameters)) {}
|
|
/// Create a method signature with a return type, a method name, and a
|
|
/// variadic list of parameters.
|
|
template <typename RetTypeT, typename NameT, typename... Parameters>
|
|
MethodSignature(RetTypeT &&retType, NameT &&name, Parameters &&...parameters)
|
|
: MethodSignature(std::forward<RetTypeT>(retType),
|
|
std::forward<NameT>(name),
|
|
ArrayRef<MethodParameter>(
|
|
{std::forward<Parameters>(parameters)...})) {}
|
|
|
|
/// Determine whether a method with this signature makes a method with
|
|
/// `other` signature redundant. This occurs if the signatures have the same
|
|
/// name and this signature's parameteres subsume the other's.
|
|
///
|
|
/// A method that makes another method redundant with a different return type
|
|
/// can replace the other, the assumption being that the subsuming method
|
|
/// provides a more resolved return type, e.g. IntegerAttr vs. Attribute.
|
|
bool makesRedundant(const MethodSignature &other) const;
|
|
|
|
/// Get the name of the method.
|
|
StringRef getName() const { return methodName; }
|
|
|
|
/// Get the return type of the method
|
|
StringRef getReturnType() const { return returnType; }
|
|
|
|
/// Get the number of parameters.
|
|
unsigned getNumParameters() const { return parameters.getNumParameters(); }
|
|
|
|
/// Write the signature as part of a method declaration.
|
|
void writeDeclTo(raw_indented_ostream &os) const;
|
|
|
|
/// Write the signature as part of a method definition. `namePrefix` is to be
|
|
/// prepended to the method name (typically namespaces for qualifying the
|
|
/// method definition).
|
|
void writeDefTo(raw_indented_ostream &os, StringRef namePrefix) const;
|
|
|
|
/// Write the template parameters of the signature.
|
|
void writeTemplateParamsTo(raw_indented_ostream &os) const;
|
|
|
|
/// Add a template parameter.
|
|
template <typename ParamT>
|
|
void addTemplateParam(ParamT param) {
|
|
templateParams.push_back(stringify(param));
|
|
}
|
|
|
|
/// Add a list of template parameters.
|
|
template <typename ContainerT>
|
|
void addTemplateParams(ContainerT &&container) {
|
|
templateParams.insert(std::begin(container), std::end(container));
|
|
}
|
|
|
|
private:
|
|
/// The method's C++ return type.
|
|
std::string returnType;
|
|
/// The method name.
|
|
std::string methodName;
|
|
/// The method's parameter list.
|
|
MethodParameters parameters;
|
|
/// An optional list of template parameters.
|
|
SmallVector<std::string, 0> templateParams;
|
|
};
|
|
|
|
/// This class contains the body of a C++ method.
|
|
class MethodBody {
|
|
public:
|
|
/// Create a method body, indicating whether it should be elided for methods
|
|
/// that are declaration-only.
|
|
MethodBody(bool declOnly);
|
|
|
|
/// Define a move constructor to correctly initialize the streams.
|
|
MethodBody(MethodBody &&other)
|
|
: declOnly(other.declOnly), body(std::move(other.body)), stringOs(body),
|
|
os(stringOs) {}
|
|
/// Define a move assignment operator. `raw_ostream` has deleted assignment
|
|
/// operators, so reinitialize the whole object.
|
|
MethodBody &operator=(MethodBody &&body) {
|
|
this->~MethodBody();
|
|
new (this) MethodBody(std::move(body));
|
|
return *this;
|
|
}
|
|
|
|
/// Write a value to the method body.
|
|
template <typename ValueT>
|
|
MethodBody &operator<<(ValueT &&value) {
|
|
if (!declOnly) {
|
|
os << std::forward<ValueT>(value);
|
|
os.flush();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/// Write the method body to the output stream. The body can be written as
|
|
/// part of the declaration of an inline method or just in the definition.
|
|
void writeTo(raw_indented_ostream &os) const;
|
|
|
|
/// Indent the output stream.
|
|
MethodBody &indent() {
|
|
os.indent();
|
|
return *this;
|
|
}
|
|
/// Unindent the output stream.
|
|
MethodBody &unindent() {
|
|
os.unindent();
|
|
return *this;
|
|
}
|
|
/// Create a delimited scope: immediately print `open`, indent if `indent` is
|
|
/// true, and print `close` on object destruction.
|
|
raw_indented_ostream::DelimitedScope
|
|
scope(StringRef open = "", StringRef close = "", bool indent = false) {
|
|
return os.scope(open, close, indent);
|
|
}
|
|
|
|
/// Get the underlying indented output stream.
|
|
raw_indented_ostream &getStream() { return os; }
|
|
|
|
private:
|
|
/// Whether the body should be elided.
|
|
bool declOnly;
|
|
/// The body data.
|
|
std::string body;
|
|
/// The string output stream.
|
|
llvm::raw_string_ostream stringOs;
|
|
/// An indented output stream for formatting input.
|
|
raw_indented_ostream os;
|
|
};
|
|
|
|
/// A class declaration is a class element that appears as part of its
|
|
/// declaration.
|
|
class ClassDeclaration {
|
|
public:
|
|
virtual ~ClassDeclaration() = default;
|
|
|
|
/// Kinds for LLVM-style RTTI.
|
|
enum Kind {
|
|
Method,
|
|
UsingDeclaration,
|
|
VisibilityDeclaration,
|
|
Field,
|
|
ExtraClassDeclaration
|
|
};
|
|
/// Create a class declaration with a given kind.
|
|
ClassDeclaration(Kind kind) : kind(kind) {}
|
|
|
|
/// Get the class declaration kind.
|
|
Kind getKind() const { return kind; }
|
|
|
|
/// Write the declaration.
|
|
virtual void writeDeclTo(raw_indented_ostream &os) const = 0;
|
|
|
|
/// Write the definition, if any. `namePrefix` is the namespace prefix, which
|
|
/// may contains a class name.
|
|
virtual void writeDefTo(raw_indented_ostream &os,
|
|
StringRef namePrefix) const {}
|
|
|
|
private:
|
|
/// The class declaration kind.
|
|
Kind kind;
|
|
};
|
|
|
|
/// Base class for class declarations.
|
|
template <ClassDeclaration::Kind DeclKind>
|
|
class ClassDeclarationBase : public ClassDeclaration {
|
|
public:
|
|
using Base = ClassDeclarationBase<DeclKind>;
|
|
ClassDeclarationBase() : ClassDeclaration(DeclKind) {}
|
|
|
|
static bool classof(const ClassDeclaration *other) {
|
|
return other->getKind() == DeclKind;
|
|
}
|
|
};
|
|
|
|
/// Class for holding an op's method for C++ code emission
|
|
class Method : public ClassDeclarationBase<ClassDeclaration::Method> {
|
|
public:
|
|
/// Properties (qualifiers) of class methods. Bitfield is used here to help
|
|
/// querying properties.
|
|
enum Properties {
|
|
None = 0x0,
|
|
Static = 0x1,
|
|
Constructor = 0x2,
|
|
Private = 0x4,
|
|
Declaration = 0x8,
|
|
Inline = 0x10,
|
|
ConstexprValue = 0x20,
|
|
Const = 0x40,
|
|
|
|
Constexpr = ConstexprValue | Inline,
|
|
StaticDeclaration = Static | Declaration,
|
|
StaticInline = Static | Inline,
|
|
ConstInline = Const | Inline,
|
|
ConstDeclaration = Const | Declaration
|
|
};
|
|
|
|
/// Create a method with a return type, a name, method properties, and a some
|
|
/// parameters. The parameteres may be passed as a list or as a variadic pack.
|
|
template <typename RetTypeT, typename NameT, typename... Args>
|
|
Method(RetTypeT &&retType, NameT &&name, Properties properties,
|
|
Args &&...args)
|
|
: properties(properties),
|
|
methodSignature(std::forward<RetTypeT>(retType),
|
|
std::forward<NameT>(name), std::forward<Args>(args)...),
|
|
methodBody(properties & Declaration) {
|
|
if (!methodPropertiesAreCompatible(properties)) {
|
|
llvm::report_fatal_error(
|
|
"Invalid combination of method properties specified");
|
|
}
|
|
}
|
|
/// Create a method with a return type, a name, method properties, and a list
|
|
/// of parameters.
|
|
Method(StringRef retType, StringRef name, Properties properties,
|
|
std::initializer_list<MethodParameter> params)
|
|
: properties(properties), methodSignature(retType, name, params),
|
|
methodBody(properties & Declaration) {
|
|
if (!methodPropertiesAreCompatible(properties)) {
|
|
llvm::report_fatal_error(
|
|
"Invalid combination of method properties specified");
|
|
}
|
|
}
|
|
|
|
// Define move constructor and assignment operator to prevent copying.
|
|
Method(Method &&) = default;
|
|
Method &operator=(Method &&) = default;
|
|
|
|
/// Get the method body.
|
|
MethodBody &body() { return methodBody; }
|
|
|
|
/// Sets or removes the deprecation message of the method.
|
|
void setDeprecated(std::optional<StringRef> message) {
|
|
this->deprecationMessage = message;
|
|
}
|
|
|
|
/// Returns true if this is a static method.
|
|
bool isStatic() const { return properties & Static; }
|
|
|
|
/// Returns true if this is a private method.
|
|
bool isPrivate() const { return properties & Private; }
|
|
|
|
/// Returns true if this is an inline method.
|
|
bool isInline() const { return properties & Inline; }
|
|
|
|
/// Returns true if this is a constructor.
|
|
bool isConstructor() const { return properties & Constructor; }
|
|
|
|
/// Returns true if this class method is const.
|
|
bool isConst() const { return properties & Const; }
|
|
|
|
/// Returns the name of this method.
|
|
StringRef getName() const { return methodSignature.getName(); }
|
|
|
|
/// Returns the return type of this method
|
|
StringRef getReturnType() const { return methodSignature.getReturnType(); }
|
|
|
|
/// Returns if this method makes the `other` method redundant.
|
|
bool makesRedundant(const Method &other) const {
|
|
return methodSignature.makesRedundant(other.methodSignature);
|
|
}
|
|
|
|
/// Write the method declaration, including the definition if inline.
|
|
void writeDeclTo(raw_indented_ostream &os) const override;
|
|
|
|
/// Write the method definition. This is a no-op for inline methods.
|
|
void writeDefTo(raw_indented_ostream &os,
|
|
StringRef namePrefix) const override;
|
|
|
|
/// Add a template parameter.
|
|
template <typename ParamT>
|
|
void addTemplateParam(ParamT param);
|
|
|
|
/// Add a list of template parameters.
|
|
template <typename ContainerT>
|
|
void addTemplateParams(ContainerT &&container);
|
|
|
|
protected:
|
|
/// A collection of method properties.
|
|
Properties properties;
|
|
/// The signature of the method.
|
|
MethodSignature methodSignature;
|
|
/// The body of the method, if it has one.
|
|
MethodBody methodBody;
|
|
/// Deprecation message if the method is deprecated.
|
|
std::optional<std::string> deprecationMessage;
|
|
|
|
/// Utility method to verify method properties correctness.
|
|
[[maybe_unused]] static bool
|
|
methodPropertiesAreCompatible(Properties properties);
|
|
};
|
|
|
|
/// This enum describes C++ inheritance visibility.
|
|
enum class Visibility { Public, Protected, Private };
|
|
|
|
/// Write "public", "protected", or "private".
|
|
llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
|
|
mlir::tblgen::Visibility visibility);
|
|
|
|
// Class for holding an op's constructor method for C++ code emission.
|
|
class Constructor : public Method {
|
|
public:
|
|
/// Create a constructor for a given class, with method properties, and
|
|
/// parameters specified either as a list of a variadic pack.
|
|
template <typename NameT, typename... Args>
|
|
Constructor(NameT &&className, Properties properties, Args &&...args)
|
|
: Method("", std::forward<NameT>(className), properties,
|
|
std::forward<Args>(args)...) {}
|
|
|
|
/// Add member initializer to constructor initializing `name` with `value`.
|
|
template <typename NameT, typename ValueT>
|
|
void addMemberInitializer(NameT &&name, ValueT &&value) {
|
|
initializers.emplace_back(stringify(std::forward<NameT>(name)),
|
|
stringify(std::forward<ValueT>(value)));
|
|
}
|
|
|
|
/// Write the declaration of the constructor, and its definition if inline.
|
|
void writeDeclTo(raw_indented_ostream &os) const override;
|
|
|
|
/// Write the definition of the constructor if it is not inline.
|
|
void writeDefTo(raw_indented_ostream &os,
|
|
StringRef namePrefix) const override;
|
|
|
|
/// Return true if a method is a constructor.
|
|
static bool classof(const ClassDeclaration *other) {
|
|
return isa<Method>(other) && cast<Method>(other)->isConstructor();
|
|
}
|
|
|
|
/// Initialization of a class field in a constructor.
|
|
class MemberInitializer {
|
|
public:
|
|
/// Create a member initializer in a constructor that initializes the class
|
|
/// field `name` with `value`.
|
|
MemberInitializer(std::string name, std::string value)
|
|
: name(std::move(name)), value(std::move(value)) {}
|
|
|
|
/// Write the member initializer.
|
|
void writeTo(raw_indented_ostream &os) const;
|
|
|
|
private:
|
|
/// The name of the class field.
|
|
std::string name;
|
|
/// The value with which to initialize it.
|
|
std::string value;
|
|
};
|
|
|
|
private:
|
|
/// The list of member initializers.
|
|
SmallVector<MemberInitializer> initializers;
|
|
};
|
|
|
|
} // namespace tblgen
|
|
} // namespace mlir
|
|
|
|
/// The OR of two method properties should return method properties. Ensure that
|
|
/// this function is visible to `Class`.
|
|
inline constexpr mlir::tblgen::Method::Properties
|
|
operator|(mlir::tblgen::Method::Properties lhs,
|
|
mlir::tblgen::Method::Properties rhs) {
|
|
return mlir::tblgen::Method::Properties(static_cast<unsigned>(lhs) |
|
|
static_cast<unsigned>(rhs));
|
|
}
|
|
|
|
inline constexpr mlir::tblgen::Method::Properties &
|
|
operator|=(mlir::tblgen::Method::Properties &lhs,
|
|
mlir::tblgen::Method::Properties rhs) {
|
|
return lhs = mlir::tblgen::Method::Properties(static_cast<unsigned>(lhs) |
|
|
static_cast<unsigned>(rhs));
|
|
}
|
|
|
|
namespace mlir {
|
|
namespace tblgen {
|
|
|
|
template <typename ParamT>
|
|
void Method::addTemplateParam(ParamT param) {
|
|
// Templates imply inline.
|
|
properties |= Method::Inline;
|
|
methodSignature.addTemplateParam(param);
|
|
}
|
|
|
|
template <typename ContainerT>
|
|
void Method::addTemplateParams(ContainerT &&container) {
|
|
// Templates imply inline.
|
|
properties |= Method::Inline;
|
|
methodSignature.addTemplateParam(std::forward<ContainerT>(container));
|
|
}
|
|
|
|
/// This class describes a C++ parent class declaration.
|
|
class ParentClass {
|
|
public:
|
|
/// Create a parent class with a class name and visibility.
|
|
template <typename NameT>
|
|
ParentClass(NameT &&name, Visibility visibility = Visibility::Public)
|
|
: name(stringify(std::forward<NameT>(name))), visibility(visibility) {}
|
|
|
|
/// Add a template parameter.
|
|
template <typename ParamT>
|
|
void addTemplateParam(ParamT param) {
|
|
templateParams.insert(stringify(param));
|
|
}
|
|
/// Add a list of template parameters.
|
|
template <typename ContainerT>
|
|
void addTemplateParams(ContainerT &&container) {
|
|
templateParams.insert(std::begin(container), std::end(container));
|
|
}
|
|
|
|
/// Write the parent class declaration.
|
|
void writeTo(raw_indented_ostream &os) const;
|
|
|
|
private:
|
|
/// The fully resolved C++ name of the parent class.
|
|
std::string name;
|
|
/// The visibility of the parent class.
|
|
Visibility visibility;
|
|
/// An optional list of class template parameters.
|
|
SetVector<std::string, SmallVector<std::string>, StringSet<>> templateParams;
|
|
};
|
|
|
|
/// This class describes a using-declaration for a class. E.g.
|
|
///
|
|
/// using Op::Op;
|
|
/// using Adaptor = OpAdaptor;
|
|
///
|
|
class UsingDeclaration
|
|
: public ClassDeclarationBase<ClassDeclaration::UsingDeclaration> {
|
|
public:
|
|
/// Create a using declaration that either aliases `name` to `value` or
|
|
/// inherits the parent methods `name.
|
|
template <typename NameT, typename ValueT = std::string>
|
|
UsingDeclaration(NameT &&name, ValueT &&value = "")
|
|
: name(stringify(std::forward<NameT>(name))),
|
|
value(stringify(std::forward<ValueT>(value))) {}
|
|
|
|
/// Write the using declaration.
|
|
void writeDeclTo(raw_indented_ostream &os) const override;
|
|
|
|
/// Add a template parameter.
|
|
template <typename ParamT>
|
|
void addTemplateParam(ParamT param) {
|
|
templateParams.insert(stringify(param));
|
|
}
|
|
|
|
/// Add a list of template parameters.
|
|
template <typename ContainerT>
|
|
void addTemplateParams(ContainerT &&container) {
|
|
templateParams.insert(std::begin(container), std::end(container));
|
|
}
|
|
|
|
private:
|
|
/// The name of the declaration, or a resolved name to an inherited function.
|
|
std::string name;
|
|
/// The type that is being aliased. Leave empty for inheriting functions.
|
|
std::string value;
|
|
/// An optional list of class template parameters.
|
|
/// This is simply a ordered list of parameter names that are then added as
|
|
/// template type parameters when the using declaration is emitted.
|
|
SetVector<std::string, SmallVector<std::string>, StringSet<>> templateParams;
|
|
};
|
|
|
|
/// This class describes a class field.
|
|
class Field : public ClassDeclarationBase<ClassDeclaration::Field> {
|
|
public:
|
|
/// Create a class field with a type and variable name.
|
|
template <typename TypeT, typename NameT>
|
|
Field(TypeT &&type, NameT &&name)
|
|
: type(stringify(std::forward<TypeT>(type))),
|
|
name(stringify(std::forward<NameT>(name))) {}
|
|
|
|
/// Write the declaration of the field.
|
|
void writeDeclTo(raw_indented_ostream &os) const override;
|
|
|
|
private:
|
|
/// The C++ type of the field.
|
|
std::string type;
|
|
/// The variable name of the class whether.
|
|
std::string name;
|
|
};
|
|
|
|
/// A declaration for the visibility of subsequent declarations.
|
|
class VisibilityDeclaration
|
|
: public ClassDeclarationBase<ClassDeclaration::VisibilityDeclaration> {
|
|
public:
|
|
/// Create a declaration for the given visibility.
|
|
VisibilityDeclaration(Visibility visibility) : visibility(visibility) {}
|
|
|
|
/// Get the visibility.
|
|
Visibility getVisibility() const { return visibility; }
|
|
|
|
/// Write the visibility declaration.
|
|
void writeDeclTo(raw_indented_ostream &os) const override;
|
|
|
|
private:
|
|
/// The visibility of subsequent class declarations.
|
|
Visibility visibility;
|
|
};
|
|
|
|
/// Unstructured extra class declarations and definitions, from TableGen
|
|
/// definitions. The default visibility of extra class declarations is up to the
|
|
/// owning class.
|
|
class ExtraClassDeclaration
|
|
: public ClassDeclarationBase<ClassDeclaration::ExtraClassDeclaration> {
|
|
public:
|
|
/// Create an extra class declaration.
|
|
ExtraClassDeclaration(StringRef extraClassDeclaration,
|
|
std::string extraClassDefinition = "")
|
|
: ExtraClassDeclaration(extraClassDeclaration.str(),
|
|
std::move(extraClassDefinition)) {}
|
|
|
|
ExtraClassDeclaration(std::string extraClassDeclaration,
|
|
std::string extraClassDefinition = "")
|
|
: extraClassDeclaration(extraClassDeclaration),
|
|
extraClassDefinition(extraClassDefinition) {}
|
|
|
|
/// Write the extra class declarations.
|
|
void writeDeclTo(raw_indented_ostream &os) const override;
|
|
|
|
/// Write the extra class definitions.
|
|
void writeDefTo(raw_indented_ostream &os,
|
|
StringRef namePrefix) const override;
|
|
|
|
private:
|
|
/// The string of the extra class declarations. It is re-indented before
|
|
/// printed.
|
|
std::string extraClassDeclaration;
|
|
/// The string of the extra class definitions. It is re-indented before
|
|
/// printed.
|
|
std::string extraClassDefinition;
|
|
};
|
|
|
|
/// A class used to emit C++ classes from Tablegen. Contains a list of public
|
|
/// methods and a list of private fields to be emitted.
|
|
class Class {
|
|
public:
|
|
virtual ~Class() = default;
|
|
|
|
/// Explicitly delete the copy constructor. This is to work around a gcc-5 bug
|
|
/// with std::is_trivially_move_constructible.
|
|
Class(const Class &) = delete;
|
|
|
|
/// Create a class with a name, and whether it should be declared as a `class`
|
|
/// or `struct`. Also, prevent this from being mistaken as a move constructor
|
|
/// candidate.
|
|
template <typename NameT,
|
|
typename = std::enable_if_t<!std::is_same<NameT, Class>::value>>
|
|
Class(NameT &&name, bool isStruct = false)
|
|
: className(stringify(std::forward<NameT>(name))), isStruct(isStruct) {}
|
|
|
|
/// Add a new constructor to this class and prune and constructors made
|
|
/// redundant by it. Returns null if the constructor was not added. Else,
|
|
/// returns a pointer to the new constructor.
|
|
template <Method::Properties Properties = Method::None, typename... Args>
|
|
Constructor *addConstructor(Args &&...args) {
|
|
Method::Properties defaultProperties = Method::Constructor;
|
|
// If the class has template parameters, the constructor has to be defined
|
|
// inline.
|
|
if (!templateParams.empty())
|
|
defaultProperties |= Method::Inline;
|
|
return addConstructorAndPrune(Constructor(getClassName(),
|
|
Properties | defaultProperties,
|
|
std::forward<Args>(args)...));
|
|
}
|
|
|
|
/// Add a new method to this class and prune any methods made redundant by it.
|
|
/// Returns null if the method was not added (because an existing method would
|
|
/// make it redundant). Else, returns a pointer to the new method.
|
|
template <Method::Properties Properties = Method::None, typename RetTypeT,
|
|
typename NameT>
|
|
Method *addMethod(RetTypeT &&retType, NameT &&name,
|
|
Method::Properties properties,
|
|
ArrayRef<MethodParameter> parameters) {
|
|
// If the class has template parameters, then it has to be defined inline.
|
|
if (!templateParams.empty())
|
|
properties |= Method::Inline;
|
|
return addMethodAndPrune(Method(std::forward<RetTypeT>(retType),
|
|
std::forward<NameT>(name),
|
|
Properties | properties, parameters));
|
|
}
|
|
|
|
/// Add a method with statically-known properties.
|
|
template <Method::Properties Properties = Method::None, typename RetTypeT,
|
|
typename NameT>
|
|
Method *addMethod(RetTypeT &&retType, NameT &&name,
|
|
ArrayRef<MethodParameter> parameters) {
|
|
return addMethod(std::forward<RetTypeT>(retType), std::forward<NameT>(name),
|
|
Properties, parameters);
|
|
}
|
|
|
|
template <Method::Properties Properties = Method::None, typename RetTypeT,
|
|
typename NameT, typename... Args>
|
|
Method *addMethod(RetTypeT &&retType, NameT &&name,
|
|
Method::Properties properties, Args &&...args) {
|
|
return addMethod(std::forward<RetTypeT>(retType), std::forward<NameT>(name),
|
|
properties | Properties, {std::forward<Args>(args)...});
|
|
}
|
|
|
|
/// Add a method with statically-known properties.
|
|
template <Method::Properties Properties = Method::None, typename RetTypeT,
|
|
typename NameT, typename... Args>
|
|
Method *addMethod(RetTypeT &&retType, NameT &&name, Args &&...args) {
|
|
return addMethod(std::forward<RetTypeT>(retType), std::forward<NameT>(name),
|
|
Properties, std::forward<Args>(args)...);
|
|
}
|
|
|
|
/// Add a static method.
|
|
template <Method::Properties Properties = Method::None, typename RetTypeT,
|
|
typename NameT, typename... Args>
|
|
Method *addStaticMethod(RetTypeT &&retType, NameT &&name, Args &&...args) {
|
|
return addMethod<Properties | Method::Static>(
|
|
std::forward<RetTypeT>(retType), std::forward<NameT>(name),
|
|
std::forward<Args>(args)...);
|
|
}
|
|
|
|
/// Add an inline static method.
|
|
template <Method::Properties Properties = Method::None, typename RetTypeT,
|
|
typename NameT, typename... Args>
|
|
Method *addStaticInlineMethod(RetTypeT &&retType, NameT &&name,
|
|
Args &&...args) {
|
|
return addMethod<Properties | Method::StaticInline>(
|
|
std::forward<RetTypeT>(retType), std::forward<NameT>(name),
|
|
std::forward<Args>(args)...);
|
|
}
|
|
|
|
/// Add an inline method.
|
|
template <Method::Properties Properties = Method::None, typename RetTypeT,
|
|
typename NameT, typename... Args>
|
|
Method *addInlineMethod(RetTypeT &&retType, NameT &&name, Args &&...args) {
|
|
return addMethod<Properties | Method::Inline>(
|
|
std::forward<RetTypeT>(retType), std::forward<NameT>(name),
|
|
std::forward<Args>(args)...);
|
|
}
|
|
|
|
/// Add a const method.
|
|
template <Method::Properties Properties = Method::None, typename RetTypeT,
|
|
typename NameT, typename... Args>
|
|
Method *addConstMethod(RetTypeT &&retType, NameT &&name, Args &&...args) {
|
|
return addMethod<Properties | Method::Const>(
|
|
std::forward<RetTypeT>(retType), std::forward<NameT>(name),
|
|
std::forward<Args>(args)...);
|
|
}
|
|
|
|
/// Add a declaration for a method.
|
|
template <Method::Properties Properties = Method::None, typename RetTypeT,
|
|
typename NameT, typename... Args>
|
|
Method *declareMethod(RetTypeT &&retType, NameT &&name, Args &&...args) {
|
|
return addMethod<Properties | Method::Declaration>(
|
|
std::forward<RetTypeT>(retType), std::forward<NameT>(name),
|
|
std::forward<Args>(args)...);
|
|
}
|
|
|
|
/// Add a declaration for a static method.
|
|
template <Method::Properties Properties = Method::None, typename RetTypeT,
|
|
typename NameT, typename... Args>
|
|
Method *declareStaticMethod(RetTypeT &&retType, NameT &&name,
|
|
Args &&...args) {
|
|
return addMethod<Properties | Method::StaticDeclaration>(
|
|
std::forward<RetTypeT>(retType), std::forward<NameT>(name),
|
|
std::forward<Args>(args)...);
|
|
}
|
|
|
|
const std::vector<std::unique_ptr<Method>> &getMethods() const {
|
|
return methods;
|
|
}
|
|
|
|
/// Add a new field to the class. Class fields added this way are always
|
|
/// private.
|
|
template <typename TypeT, typename NameT>
|
|
void addField(TypeT &&type, NameT &&name) {
|
|
fields.emplace_back(std::forward<TypeT>(type), std::forward<NameT>(name));
|
|
}
|
|
|
|
/// Add a parent class.
|
|
ParentClass &addParent(ParentClass parent);
|
|
|
|
/// Add a template parameter.
|
|
template <typename ParamT>
|
|
void addTemplateParam(ParamT param) {
|
|
templateParams.insert(stringify(param));
|
|
}
|
|
|
|
/// Add a list of template parameters.
|
|
template <typename ContainerT>
|
|
void addTemplateParams(ContainerT &&container) {
|
|
templateParams.insert(std::begin(container), std::end(container));
|
|
}
|
|
|
|
/// Return the C++ name of the class.
|
|
StringRef getClassName() const { return className; }
|
|
|
|
/// Write the declaration of this class, all declarations, and definitions of
|
|
/// inline functions. Wrap the output stream in an indented stream.
|
|
void writeDeclTo(raw_ostream &rawOs) const {
|
|
raw_indented_ostream os(rawOs);
|
|
writeDeclTo(os);
|
|
}
|
|
/// Write the definitions of thiss class's out-of-line constructors and
|
|
/// methods. Wrap the output stream in an indented stream.
|
|
void writeDefTo(raw_ostream &rawOs) const {
|
|
raw_indented_ostream os(rawOs);
|
|
writeDefTo(os);
|
|
}
|
|
|
|
/// Write the declaration of this class, all declarations, and definitions of
|
|
/// inline functions.
|
|
void writeDeclTo(raw_indented_ostream &os) const;
|
|
/// Write the definitions of thiss class's out-of-line constructors and
|
|
/// methods.
|
|
void writeDefTo(raw_indented_ostream &os) const;
|
|
|
|
/// Add a declaration. The declaration is appended directly to the list of
|
|
/// class declarations.
|
|
template <typename DeclT, typename... Args>
|
|
DeclT *declare(Args &&...args) {
|
|
auto decl = std::make_unique<DeclT>(std::forward<Args>(args)...);
|
|
auto *ret = decl.get();
|
|
declarations.push_back(std::move(decl));
|
|
return ret;
|
|
}
|
|
|
|
/// The declaration of a class needs to be "finalized".
|
|
///
|
|
/// Class constructors, methods, and fields can be added in any order,
|
|
/// regardless of whether they are public or private. These are stored in
|
|
/// lists separate from list of declarations `declarations`.
|
|
///
|
|
/// So that the generated C++ code is somewhat organised, public methods are
|
|
/// declared together, and so are private methods and class fields. This
|
|
/// function iterates through all the added methods and fields and organises
|
|
/// them into the list of declarations, adding visibility declarations as
|
|
/// needed, as follows:
|
|
///
|
|
/// 1. public methods and constructors
|
|
/// 2. private methods and constructors
|
|
/// 3. class fields -- all are private
|
|
///
|
|
/// `Class::finalize` clears the lists of pending methods and fields, and can
|
|
/// be called multiple times.
|
|
virtual void finalize();
|
|
|
|
protected:
|
|
/// Add a new constructor if it is not made redundant by any existing
|
|
/// constructors and prune and existing constructors made redundant.
|
|
Constructor *addConstructorAndPrune(Constructor &&newCtor);
|
|
/// Add a new method if it is not made redundant by any existing methods and
|
|
/// prune and existing methods made redundant.
|
|
Method *addMethodAndPrune(Method &&newMethod);
|
|
|
|
/// Get the last visibility declaration.
|
|
Visibility getLastVisibilityDecl() const;
|
|
|
|
/// The C++ class name.
|
|
std::string className;
|
|
/// The list of parent classes.
|
|
SmallVector<ParentClass> parents;
|
|
/// The pending list of methods and constructors.
|
|
std::vector<std::unique_ptr<Method>> methods;
|
|
/// The pending list of private class fields.
|
|
SmallVector<Field> fields;
|
|
/// Whether this is a `class` or a `struct`.
|
|
bool isStruct;
|
|
|
|
/// A list of declarations in the class, emitted in order.
|
|
std::vector<std::unique_ptr<ClassDeclaration>> declarations;
|
|
|
|
/// An optional list of class template parameters.
|
|
SetVector<std::string, SmallVector<std::string>, StringSet<>> templateParams;
|
|
};
|
|
|
|
} // namespace tblgen
|
|
} // namespace mlir
|
|
|
|
#endif // MLIR_TABLEGEN_CLASS_H_
|