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> &¶meters) 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