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