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