1 //===- Class.h - Helper classes for C++ code emission -----------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines several classes for C++ code emission. They are only
10 // expected to be used by MLIR TableGen backends.
11 //
12 // We emit the declarations and definitions into separate files: *.h.inc and
13 // *.cpp.inc. The former is to be included in the dialect *.h and the latter for
14 // dialect *.cpp. This way provides a cleaner interface.
15 //
16 // In order to do this split, we need to track method signature and
17 // implementation logic separately. Signature information is used for both
18 // declaration and definition, while implementation logic is only for
19 // definition. So we have the following classes for C++ code emission.
20 //
21 //===----------------------------------------------------------------------===//
22 
23 #ifndef MLIR_TABLEGEN_CLASS_H_
24 #define MLIR_TABLEGEN_CLASS_H_
25 
26 #include "mlir/Support/IndentedOstream.h"
27 #include "mlir/Support/LLVM.h"
28 #include "mlir/TableGen/CodeGenHelpers.h"
29 #include "llvm/ADT/SetVector.h"
30 #include "llvm/ADT/SmallVector.h"
31 #include "llvm/ADT/StringRef.h"
32 #include "llvm/ADT/StringSet.h"
33 #include "llvm/ADT/Twine.h"
34 
35 #include <set>
36 #include <string>
37 
38 namespace mlir {
39 namespace tblgen {
40 class FmtObjectBase;
41 
42 /// This class contains a single method parameter for a C++ function.
43 class MethodParameter {
44 public:
45   /// Create a method parameter with a C++ type, parameter name, and an optional
46   /// default value. Marking a parameter as "optional" is a cosmetic effect on
47   /// the generated code.
48   template <typename TypeT, typename NameT, typename DefaultT>
49   MethodParameter(TypeT &&type, NameT &&name, DefaultT &&defaultValue,
50                   bool optional = false)
type(stringify (std::forward<TypeT> (type)))51       : type(stringify(std::forward<TypeT>(type))),
52         name(stringify(std::forward<NameT>(name))),
53         defaultValue(stringify(std::forward<DefaultT>(defaultValue))),
54         optional(optional) {}
55 
56   /// Create a method parameter with a C++ type, parameter name, and no default
57   /// value.
58   template <typename TypeT, typename NameT>
59   MethodParameter(TypeT &&type, NameT &&name, bool optional = false)
60       : MethodParameter(std::forward<TypeT>(type), std::forward<NameT>(name),
61                         /*defaultValue=*/"", optional) {}
62 
63   /// Write the parameter as part of a method declaration.
64   void writeDeclTo(raw_indented_ostream &os) const;
65   /// Write the parameter as part of a method definition.
66   void writeDefTo(raw_indented_ostream &os) const;
67 
68   /// Get the C++ type.
getType()69   StringRef getType() const { return type; }
70   /// Returns true if the parameter has a default value.
hasDefaultValue()71   bool hasDefaultValue() const { return !defaultValue.empty(); }
72 
73 private:
74   /// The C++ type.
75   std::string type;
76   /// The variable name.
77   std::string name;
78   /// An optional default value. The default value exists if the string is not
79   /// empty.
80   std::string defaultValue;
81   /// Whether the parameter should be indicated as "optional".
82   bool optional;
83 };
84 
85 /// This class contains a list of method parameters for constructor, class
86 /// methods, and method signatures.
87 class MethodParameters {
88 public:
89   /// Create a list of method parameters.
MethodParameters(std::initializer_list<MethodParameter> parameters)90   MethodParameters(std::initializer_list<MethodParameter> parameters)
91       : parameters(parameters) {}
MethodParameters(SmallVector<MethodParameter> parameters)92   MethodParameters(SmallVector<MethodParameter> parameters)
93       : parameters(std::move(parameters)) {}
94 
95   /// Write the parameters as part of a method declaration.
96   void writeDeclTo(raw_indented_ostream &os) const;
97   /// Write the parameters as part of a method definition.
98   void writeDefTo(raw_indented_ostream &os) const;
99 
100   /// Determine whether this list of parameters "subsumes" another, which occurs
101   /// when this parameter list is identical to the other and has zero or more
102   /// additional default-valued parameters.
103   bool subsumes(const MethodParameters &other) const;
104 
105   /// Return the number of parameters.
getNumParameters()106   unsigned getNumParameters() const { return parameters.size(); }
107 
108 private:
109   /// The list of parameters.
110   SmallVector<MethodParameter> parameters;
111 };
112 
113 /// This class contains the signature of a C++ method, including the return
114 /// type. method name, and method parameters.
115 class MethodSignature {
116 public:
117   /// Create a method signature with a return type, a method name, and a list of
118   /// parameters. Take ownership of the list.
119   template <typename RetTypeT, typename NameT>
MethodSignature(RetTypeT && retType,NameT && name,SmallVector<MethodParameter> && parameters)120   MethodSignature(RetTypeT &&retType, NameT &&name,
121                   SmallVector<MethodParameter> &&parameters)
122       : returnType(stringify(std::forward<RetTypeT>(retType))),
123         methodName(stringify(std::forward<NameT>(name))),
124         parameters(std::move(parameters)) {}
125   /// Create a method signature with a return type, a method name, and a list of
126   /// parameters.
127   template <typename RetTypeT, typename NameT>
MethodSignature(RetTypeT && retType,NameT && name,ArrayRef<MethodParameter> parameters)128   MethodSignature(RetTypeT &&retType, NameT &&name,
129                   ArrayRef<MethodParameter> parameters)
130       : MethodSignature(std::forward<RetTypeT>(retType),
131                         std::forward<NameT>(name),
132                         SmallVector<MethodParameter>(parameters.begin(),
133                                                      parameters.end())) {}
134   /// Create a method signature with a return type, a method name, and a
135   /// variadic list of parameters.
136   template <typename RetTypeT, typename NameT, typename... Parameters>
MethodSignature(RetTypeT && retType,NameT && name,Parameters &&...parameters)137   MethodSignature(RetTypeT &&retType, NameT &&name, Parameters &&...parameters)
138       : MethodSignature(std::forward<RetTypeT>(retType),
139                         std::forward<NameT>(name),
140                         ArrayRef<MethodParameter>(
141                             {std::forward<Parameters>(parameters)...})) {}
142 
143   /// Determine whether a method with this signature makes a method with
144   /// `other` signature redundant. This occurs if the signatures have the same
145   /// name and this signature's parameteres subsume the other's.
146   ///
147   /// A method that makes another method redundant with a different return type
148   /// can replace the other, the assumption being that the subsuming method
149   /// provides a more resolved return type, e.g. IntegerAttr vs. Attribute.
150   bool makesRedundant(const MethodSignature &other) const;
151 
152   /// Get the name of the method.
getName()153   StringRef getName() const { return methodName; }
154 
155   /// Get the number of parameters.
getNumParameters()156   unsigned getNumParameters() const { return parameters.getNumParameters(); }
157 
158   /// Write the signature as part of a method declaration.
159   void writeDeclTo(raw_indented_ostream &os) const;
160 
161   /// Write the signature as part of a method definition. `namePrefix` is to be
162   /// prepended to the method name (typically namespaces for qualifying the
163   /// method definition).
164   void writeDefTo(raw_indented_ostream &os, StringRef namePrefix) const;
165 
166 private:
167   /// The method's C++ return type.
168   std::string returnType;
169   /// The method name.
170   std::string methodName;
171   /// The method's parameter list.
172   MethodParameters parameters;
173 };
174 
175 /// This class contains the body of a C++ method.
176 class MethodBody {
177 public:
178   /// Create a method body, indicating whether it should be elided for methods
179   /// that are declaration-only.
180   MethodBody(bool declOnly);
181 
182   /// Define a move constructor to correctly initialize the streams.
MethodBody(MethodBody && other)183   MethodBody(MethodBody &&other)
184       : declOnly(other.declOnly), body(std::move(other.body)), stringOs(body),
185         os(stringOs) {}
186   /// Define a move assignment operator. `raw_ostream` has deleted assignment
187   /// operators, so reinitialize the whole object.
188   MethodBody &operator=(MethodBody &&body) {
189     this->~MethodBody();
190     new (this) MethodBody(std::move(body));
191     return *this;
192   }
193 
194   /// Write a value to the method body.
195   template <typename ValueT>
196   MethodBody &operator<<(ValueT &&value) {
197     if (!declOnly) {
198       os << std::forward<ValueT>(value);
199       os.flush();
200     }
201     return *this;
202   }
203 
204   /// Write the method body to the output stream. The body can be written as
205   /// part of the declaration of an inline method or just in the definition.
206   void writeTo(raw_indented_ostream &os) const;
207 
208   /// Indent the output stream.
indent()209   MethodBody &indent() {
210     os.indent();
211     return *this;
212   }
213   /// Unindent the output stream.
unindent()214   MethodBody &unindent() {
215     os.unindent();
216     return *this;
217   }
218   /// Create a delimited scope: immediately print `open`, indent if `indent` is
219   /// true, and print `close` on object destruction.
220   raw_indented_ostream::DelimitedScope
221   scope(StringRef open = "", StringRef close = "", bool indent = false) {
222     return os.scope(open, close, indent);
223   }
224 
225   /// Get the underlying indented output stream.
getStream()226   raw_indented_ostream &getStream() { return os; }
227 
228 private:
229   /// Whether the body should be elided.
230   bool declOnly;
231   /// The body data.
232   std::string body;
233   /// The string output stream.
234   llvm::raw_string_ostream stringOs;
235   /// An indented output stream for formatting input.
236   raw_indented_ostream os;
237 };
238 
239 /// A class declaration is a class element that appears as part of its
240 /// declaration.
241 class ClassDeclaration {
242 public:
243   virtual ~ClassDeclaration() = default;
244 
245   /// Kinds for LLVM-style RTTI.
246   enum Kind {
247     Method,
248     UsingDeclaration,
249     VisibilityDeclaration,
250     Field,
251     ExtraClassDeclaration
252   };
253   /// Create a class declaration with a given kind.
ClassDeclaration(Kind kind)254   ClassDeclaration(Kind kind) : kind(kind) {}
255 
256   /// Get the class declaration kind.
getKind()257   Kind getKind() const { return kind; }
258 
259   /// Write the declaration.
260   virtual void writeDeclTo(raw_indented_ostream &os) const = 0;
261 
262   /// Write the definition, if any. `namePrefix` is the namespace prefix, which
263   /// may contains a class name.
writeDefTo(raw_indented_ostream & os,StringRef namePrefix)264   virtual void writeDefTo(raw_indented_ostream &os,
265                           StringRef namePrefix) const {}
266 
267 private:
268   /// The class declaration kind.
269   Kind kind;
270 };
271 
272 /// Base class for class declarations.
273 template <ClassDeclaration::Kind DeclKind>
274 class ClassDeclarationBase : public ClassDeclaration {
275 public:
276   using Base = ClassDeclarationBase<DeclKind>;
ClassDeclarationBase()277   ClassDeclarationBase() : ClassDeclaration(DeclKind) {}
278 
classof(const ClassDeclaration * other)279   static bool classof(const ClassDeclaration *other) {
280     return other->getKind() == DeclKind;
281   }
282 };
283 
284 /// Class for holding an op's method for C++ code emission
285 class Method : public ClassDeclarationBase<ClassDeclaration::Method> {
286 public:
287   /// Properties (qualifiers) of class methods. Bitfield is used here to help
288   /// querying properties.
289   enum Properties {
290     None = 0x0,
291     Static = 0x1,
292     Constructor = 0x2,
293     Private = 0x4,
294     Declaration = 0x8,
295     Inline = 0x10,
296     ConstexprValue = 0x20,
297     Const = 0x40,
298 
299     Constexpr = ConstexprValue | Inline,
300     StaticDeclaration = Static | Declaration,
301     StaticInline = Static | Inline,
302     ConstInline = Const | Inline,
303     ConstDeclaration = Const | Declaration
304   };
305 
306   /// Create a method with a return type, a name, method properties, and a some
307   /// parameters. The parameteres may be passed as a list or as a variadic pack.
308   template <typename RetTypeT, typename NameT, typename... Args>
Method(RetTypeT && retType,NameT && name,Properties properties,Args &&...args)309   Method(RetTypeT &&retType, NameT &&name, Properties properties,
310          Args &&...args)
311       : properties(properties),
312         methodSignature(std::forward<RetTypeT>(retType),
313                         std::forward<NameT>(name), std::forward<Args>(args)...),
314         methodBody(properties & Declaration) {}
315   /// Create a method with a return type, a name, method properties, and a list
316   /// of parameters.
Method(StringRef retType,StringRef name,Properties properties,std::initializer_list<MethodParameter> params)317   Method(StringRef retType, StringRef name, Properties properties,
318          std::initializer_list<MethodParameter> params)
319       : properties(properties), methodSignature(retType, name, params),
320         methodBody(properties & Declaration) {}
321 
322   // Define move constructor and assignment operator to prevent copying.
323   Method(Method &&) = default;
324   Method &operator=(Method &&) = default;
325 
326   /// Get the method body.
body()327   MethodBody &body() { return methodBody; }
328 
329   /// Returns true if this is a static method.
isStatic()330   bool isStatic() const { return properties & Static; }
331 
332   /// Returns true if this is a private method.
isPrivate()333   bool isPrivate() const { return properties & Private; }
334 
335   /// Returns true if this is an inline method.
isInline()336   bool isInline() const { return properties & Inline; }
337 
338   /// Returns true if this is a constructor.
isConstructor()339   bool isConstructor() const { return properties & Constructor; }
340 
341   /// Returns true if this class method is const.
isConst()342   bool isConst() const { return properties & Const; }
343 
344   /// Returns the name of this method.
getName()345   StringRef getName() const { return methodSignature.getName(); }
346 
347   /// Returns if this method makes the `other` method redundant.
makesRedundant(const Method & other)348   bool makesRedundant(const Method &other) const {
349     return methodSignature.makesRedundant(other.methodSignature);
350   }
351 
352   /// Write the method declaration, including the definition if inline.
353   void writeDeclTo(raw_indented_ostream &os) const override;
354 
355   /// Write the method definition. This is a no-op for inline methods.
356   void writeDefTo(raw_indented_ostream &os,
357                   StringRef namePrefix) const override;
358 
359 protected:
360   /// A collection of method properties.
361   Properties properties;
362   /// The signature of the method.
363   MethodSignature methodSignature;
364   /// The body of the method, if it has one.
365   MethodBody methodBody;
366 };
367 
368 /// This enum describes C++ inheritance visibility.
369 enum class Visibility { Public, Protected, Private };
370 
371 /// Write "public", "protected", or "private".
372 llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
373                               mlir::tblgen::Visibility visibility);
374 
375 // Class for holding an op's constructor method for C++ code emission.
376 class Constructor : public Method {
377 public:
378   /// Create a constructor for a given class, with method properties, and
379   /// parameters specified either as a list of a variadic pack.
380   template <typename NameT, typename... Args>
Constructor(NameT && className,Properties properties,Args &&...args)381   Constructor(NameT &&className, Properties properties, Args &&...args)
382       : Method("", std::forward<NameT>(className), properties,
383                std::forward<Args>(args)...) {}
384 
385   /// Add member initializer to constructor initializing `name` with `value`.
386   template <typename NameT, typename ValueT>
addMemberInitializer(NameT && name,ValueT && value)387   void addMemberInitializer(NameT &&name, ValueT &&value) {
388     initializers.emplace_back(stringify(std::forward<NameT>(name)),
389                               stringify(std::forward<ValueT>(value)));
390   }
391 
392   /// Write the declaration of the constructor, and its definition if inline.
393   void writeDeclTo(raw_indented_ostream &os) const override;
394 
395   /// Write the definition of the constructor if it is not inline.
396   void writeDefTo(raw_indented_ostream &os,
397                   StringRef namePrefix) const override;
398 
399   /// Return true if a method is a constructor.
classof(const ClassDeclaration * other)400   static bool classof(const ClassDeclaration *other) {
401     return isa<Method>(other) && cast<Method>(other)->isConstructor();
402   }
403 
404   /// Initialization of a class field in a constructor.
405   class MemberInitializer {
406   public:
407     /// Create a member initializer in a constructor that initializes the class
408     /// field `name` with `value`.
MemberInitializer(std::string name,std::string value)409     MemberInitializer(std::string name, std::string value)
410         : name(std::move(name)), value(std::move(value)) {}
411 
412     /// Write the member initializer.
413     void writeTo(raw_indented_ostream &os) const;
414 
415   private:
416     /// The name of the class field.
417     std::string name;
418     /// The value with which to initialize it.
419     std::string value;
420   };
421 
422 private:
423   /// The list of member initializers.
424   SmallVector<MemberInitializer> initializers;
425 };
426 
427 } // namespace tblgen
428 } // namespace mlir
429 
430 /// The OR of two method properties should return method properties. Ensure that
431 /// this function is visible to `Class`.
432 inline constexpr mlir::tblgen::Method::Properties
433 operator|(mlir::tblgen::Method::Properties lhs,
434           mlir::tblgen::Method::Properties rhs) {
435   return mlir::tblgen::Method::Properties(static_cast<unsigned>(lhs) |
436                                           static_cast<unsigned>(rhs));
437 }
438 
439 namespace mlir {
440 namespace tblgen {
441 
442 /// This class describes a C++ parent class declaration.
443 class ParentClass {
444 public:
445   /// Create a parent class with a class name and visibility.
446   template <typename NameT>
447   ParentClass(NameT &&name, Visibility visibility = Visibility::Public)
name(stringify (std::forward<NameT> (name)))448       : name(stringify(std::forward<NameT>(name))), visibility(visibility) {}
449 
450   /// Add a template parameter.
451   template <typename ParamT>
addTemplateParam(ParamT param)452   void addTemplateParam(ParamT param) {
453     templateParams.insert(stringify(param));
454   }
455   /// Add a list of template parameters.
456   template <typename ContainerT>
addTemplateParams(ContainerT && container)457   void addTemplateParams(ContainerT &&container) {
458     templateParams.insert(std::begin(container), std::end(container));
459   }
460 
461   /// Write the parent class declaration.
462   void writeTo(raw_indented_ostream &os) const;
463 
464 private:
465   /// The fully resolved C++ name of the parent class.
466   std::string name;
467   /// The visibility of the parent class.
468   Visibility visibility;
469   /// An optional list of class template parameters.
470   SetVector<std::string, SmallVector<std::string>, StringSet<>> templateParams;
471 };
472 
473 /// This class describes a using-declaration for a class. E.g.
474 ///
475 ///   using Op::Op;
476 ///   using Adaptor = OpAdaptor;
477 ///
478 class UsingDeclaration
479     : public ClassDeclarationBase<ClassDeclaration::UsingDeclaration> {
480 public:
481   /// Create a using declaration that either aliases `name` to `value` or
482   /// inherits the parent methods `name.
483   template <typename NameT, typename ValueT = std::string>
484   UsingDeclaration(NameT &&name, ValueT &&value = "")
name(stringify (std::forward<NameT> (name)))485       : name(stringify(std::forward<NameT>(name))),
486         value(stringify(std::forward<ValueT>(value))) {}
487 
488   /// Write the using declaration.
489   void writeDeclTo(raw_indented_ostream &os) const override;
490 
491 private:
492   /// The name of the declaration, or a resolved name to an inherited function.
493   std::string name;
494   /// The type that is being aliased. Leave empty for inheriting functions.
495   std::string value;
496 };
497 
498 /// This class describes a class field.
499 class Field : public ClassDeclarationBase<ClassDeclaration::Field> {
500 public:
501   /// Create a class field with a type and variable name.
502   template <typename TypeT, typename NameT>
Field(TypeT && type,NameT && name)503   Field(TypeT &&type, NameT &&name)
504       : type(stringify(std::forward<TypeT>(type))),
505         name(stringify(std::forward<NameT>(name))) {}
506 
507   /// Write the declaration of the field.
508   void writeDeclTo(raw_indented_ostream &os) const override;
509 
510 private:
511   /// The C++ type of the field.
512   std::string type;
513   /// The variable name of the class whether.
514   std::string name;
515 };
516 
517 /// A declaration for the visibility of subsequent declarations.
518 class VisibilityDeclaration
519     : public ClassDeclarationBase<ClassDeclaration::VisibilityDeclaration> {
520 public:
521   /// Create a declaration for the given visibility.
VisibilityDeclaration(Visibility visibility)522   VisibilityDeclaration(Visibility visibility) : visibility(visibility) {}
523 
524   /// Get the visibility.
getVisibility()525   Visibility getVisibility() const { return visibility; }
526 
527   /// Write the visibility declaration.
528   void writeDeclTo(raw_indented_ostream &os) const override;
529 
530 private:
531   /// The visibility of subsequent class declarations.
532   Visibility visibility;
533 };
534 
535 /// Unstructured extra class declarations and definitions, from TableGen
536 /// definitions. The default visibility of extra class declarations is up to the
537 /// owning class.
538 class ExtraClassDeclaration
539     : public ClassDeclarationBase<ClassDeclaration::ExtraClassDeclaration> {
540 public:
541   /// Create an extra class declaration.
542   ExtraClassDeclaration(StringRef extraClassDeclaration,
543                         StringRef extraClassDefinition = "")
extraClassDeclaration(extraClassDeclaration)544       : extraClassDeclaration(extraClassDeclaration),
545         extraClassDefinition(extraClassDefinition) {}
546 
547   /// Write the extra class declarations.
548   void writeDeclTo(raw_indented_ostream &os) const override;
549 
550   /// Write the extra class definitions.
551   void writeDefTo(raw_indented_ostream &os,
552                   StringRef namePrefix) const override;
553 
554 private:
555   /// The string of the extra class declarations. It is re-indented before
556   /// printed.
557   StringRef extraClassDeclaration;
558   /// The string of the extra class definitions. It is re-indented before
559   /// printed.
560   std::string extraClassDefinition;
561 };
562 
563 /// A class used to emit C++ classes from Tablegen.  Contains a list of public
564 /// methods and a list of private fields to be emitted.
565 class Class {
566 public:
567   virtual ~Class() = default;
568 
569   /// Explicitly delete the copy constructor. This is to work around a gcc-5 bug
570   /// with std::is_trivially_move_constructible.
571   Class(const Class &) = delete;
572 
573   /// Create a class with a name, and whether it should be declared as a `class`
574   /// or `struct`. Also, prevent this from being mistaken as a move constructor
575   /// candidate.
576   template <typename NameT, typename = typename std::enable_if_t<
577                                 !std::is_same<NameT, Class>::value>>
578   Class(NameT &&name, bool isStruct = false)
className(stringify (std::forward<NameT> (name)))579       : className(stringify(std::forward<NameT>(name))), isStruct(isStruct) {}
580 
581   /// Add a new constructor to this class and prune and constructors made
582   /// redundant by it. Returns null if the constructor was not added. Else,
583   /// returns a pointer to the new constructor.
584   template <Method::Properties Properties = Method::None, typename... Args>
addConstructor(Args &&...args)585   Constructor *addConstructor(Args &&...args) {
586     return addConstructorAndPrune(Constructor(getClassName(),
587                                               Properties | Method::Constructor,
588                                               std::forward<Args>(args)...));
589   }
590 
591   /// Add a new method to this class and prune any methods made redundant by it.
592   /// Returns null if the method was not added (because an existing method would
593   /// make it redundant). Else, returns a pointer to the new method.
594   template <Method::Properties Properties = Method::None, typename RetTypeT,
595             typename NameT, typename... Args>
addMethod(RetTypeT && retType,NameT && name,Method::Properties properties,Args &&...args)596   Method *addMethod(RetTypeT &&retType, NameT &&name,
597                     Method::Properties properties, Args &&...args) {
598     return addMethodAndPrune(
599         Method(std::forward<RetTypeT>(retType), std::forward<NameT>(name),
600                Properties | properties, std::forward<Args>(args)...));
601   }
602 
603   /// Add a method with statically-known properties.
604   template <Method::Properties Properties = Method::None, typename RetTypeT,
605             typename NameT, typename... Args>
addMethod(RetTypeT && retType,NameT && name,Args &&...args)606   Method *addMethod(RetTypeT &&retType, NameT &&name, Args &&...args) {
607     return addMethod(std::forward<RetTypeT>(retType), std::forward<NameT>(name),
608                      Properties, std::forward<Args>(args)...);
609   }
610 
611   /// Add a static method.
612   template <Method::Properties Properties = Method::None, typename RetTypeT,
613             typename NameT, typename... Args>
addStaticMethod(RetTypeT && retType,NameT && name,Args &&...args)614   Method *addStaticMethod(RetTypeT &&retType, NameT &&name, Args &&...args) {
615     return addMethod<Properties | Method::Static>(
616         std::forward<RetTypeT>(retType), std::forward<NameT>(name),
617         std::forward<Args>(args)...);
618   }
619 
620   /// Add an inline static method.
621   template <Method::Properties Properties = Method::None, typename RetTypeT,
622             typename NameT, typename... Args>
addStaticInlineMethod(RetTypeT && retType,NameT && name,Args &&...args)623   Method *addStaticInlineMethod(RetTypeT &&retType, NameT &&name,
624                                 Args &&...args) {
625     return addMethod<Properties | Method::StaticInline>(
626         std::forward<RetTypeT>(retType), std::forward<NameT>(name),
627         std::forward<Args>(args)...);
628   }
629 
630   /// Add an inline method.
631   template <Method::Properties Properties = Method::None, typename RetTypeT,
632             typename NameT, typename... Args>
addInlineMethod(RetTypeT && retType,NameT && name,Args &&...args)633   Method *addInlineMethod(RetTypeT &&retType, NameT &&name, Args &&...args) {
634     return addMethod<Properties | Method::Inline>(
635         std::forward<RetTypeT>(retType), std::forward<NameT>(name),
636         std::forward<Args>(args)...);
637   }
638 
639   /// Add a const method.
640   template <Method::Properties Properties = Method::None, typename RetTypeT,
641             typename NameT, typename... Args>
addConstMethod(RetTypeT && retType,NameT && name,Args &&...args)642   Method *addConstMethod(RetTypeT &&retType, NameT &&name, Args &&...args) {
643     return addMethod<Properties | Method::Const>(
644         std::forward<RetTypeT>(retType), std::forward<NameT>(name),
645         std::forward<Args>(args)...);
646   }
647 
648   /// Add a declaration for a method.
649   template <Method::Properties Properties = Method::None, typename RetTypeT,
650             typename NameT, typename... Args>
declareMethod(RetTypeT && retType,NameT && name,Args &&...args)651   Method *declareMethod(RetTypeT &&retType, NameT &&name, Args &&...args) {
652     return addMethod<Properties | Method::Declaration>(
653         std::forward<RetTypeT>(retType), std::forward<NameT>(name),
654         std::forward<Args>(args)...);
655   }
656 
657   /// Add a declaration for a static method.
658   template <Method::Properties Properties = Method::None, typename RetTypeT,
659             typename NameT, typename... Args>
declareStaticMethod(RetTypeT && retType,NameT && name,Args &&...args)660   Method *declareStaticMethod(RetTypeT &&retType, NameT &&name,
661                               Args &&...args) {
662     return addMethod<Properties | Method::StaticDeclaration>(
663         std::forward<RetTypeT>(retType), std::forward<NameT>(name),
664         std::forward<Args>(args)...);
665   }
666 
667   /// Add a new field to the class. Class fields added this way are always
668   /// private.
669   template <typename TypeT, typename NameT>
addField(TypeT && type,NameT && name)670   void addField(TypeT &&type, NameT &&name) {
671     fields.emplace_back(std::forward<TypeT>(type), std::forward<NameT>(name));
672   }
673 
674   /// Add a parent class.
675   ParentClass &addParent(ParentClass parent);
676 
677   /// Return the C++ name of the class.
getClassName()678   StringRef getClassName() const { return className; }
679 
680   /// Write the declaration of this class, all declarations, and definitions of
681   /// inline functions. Wrap the output stream in an indented stream.
writeDeclTo(raw_ostream & rawOs)682   void writeDeclTo(raw_ostream &rawOs) const {
683     raw_indented_ostream os(rawOs);
684     writeDeclTo(os);
685   }
686   /// Write the definitions of thiss class's out-of-line constructors and
687   /// methods. Wrap the output stream in an indented stream.
writeDefTo(raw_ostream & rawOs)688   void writeDefTo(raw_ostream &rawOs) const {
689     raw_indented_ostream os(rawOs);
690     writeDefTo(os);
691   }
692 
693   /// Write the declaration of this class, all declarations, and definitions of
694   /// inline functions.
695   void writeDeclTo(raw_indented_ostream &os) const;
696   /// Write the definitions of thiss class's out-of-line constructors and
697   /// methods.
698   void writeDefTo(raw_indented_ostream &os) const;
699 
700   /// Add a declaration. The declaration is appended directly to the list of
701   /// class declarations.
702   template <typename DeclT, typename... Args>
declare(Args &&...args)703   DeclT *declare(Args &&...args) {
704     auto decl = std::make_unique<DeclT>(std::forward<Args>(args)...);
705     auto *ret = decl.get();
706     declarations.push_back(std::move(decl));
707     return ret;
708   }
709 
710   /// The declaration of a class needs to be "finalized".
711   ///
712   /// Class constructors, methods, and fields can be added in any order,
713   /// regardless of whether they are public or private. These are stored in
714   /// lists separate from list of declarations `declarations`.
715   ///
716   /// So that the generated C++ code is somewhat organised, public methods are
717   /// declared together, and so are private methods and class fields. This
718   /// function iterates through all the added methods and fields and organises
719   /// them into the list of declarations, adding visibility declarations as
720   /// needed, as follows:
721   ///
722   ///   1. public methods and constructors
723   ///   2. private methods and constructors
724   ///   3. class fields -- all are private
725   ///
726   /// `Class::finalize` clears the lists of pending methods and fields, and can
727   /// be called multiple times.
728   virtual void finalize();
729 
730 protected:
731   /// Add a new constructor if it is not made redundant by any existing
732   /// constructors and prune and existing constructors made redundant.
733   Constructor *addConstructorAndPrune(Constructor &&newCtor);
734   /// Add a new method if it is not made redundant by any existing methods and
735   /// prune and existing methods made redundant.
736   Method *addMethodAndPrune(Method &&newMethod);
737 
738   /// Get the last visibility declaration.
739   Visibility getLastVisibilityDecl() const;
740 
741   /// The C++ class name.
742   std::string className;
743   /// The list of parent classes.
744   SmallVector<ParentClass> parents;
745   /// The pending list of methods and constructors.
746   std::vector<std::unique_ptr<Method>> methods;
747   /// The pending list of private class fields.
748   SmallVector<Field> fields;
749   /// Whether this is a `class` or a `struct`.
750   bool isStruct;
751 
752   /// A list of declarations in the class, emitted in order.
753   std::vector<std::unique_ptr<ClassDeclaration>> declarations;
754 };
755 
756 } // namespace tblgen
757 } // namespace mlir
758 
759 #endif // MLIR_TABLEGEN_CLASS_H_
760