MLIR  22.0.0git
Class.cpp
Go to the documentation of this file.
1 //===- Class.cpp - Helper classes for Op C++ code emission --------------===//
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 #include "mlir/TableGen/Class.h"
10 #include "llvm/ADT/Twine.h"
11 #include "llvm/Support/Debug.h"
12 
13 using namespace mlir;
14 using namespace mlir::tblgen;
15 
16 /// Returns space to be emitted after the given C++ `type`. return "" if the
17 /// ends with '&' or '*', or is empty, else returns " ".
18 static StringRef getSpaceAfterType(StringRef type) {
19  return (type.empty() || type.ends_with("&") || type.ends_with("*")) ? ""
20  : " ";
21 }
22 
23 //===----------------------------------------------------------------------===//
24 // MethodParameter definitions
25 //===----------------------------------------------------------------------===//
26 
28  if (optional)
29  os << "/*optional*/";
30  os << type << getSpaceAfterType(type) << name;
31  if (hasDefaultValue())
32  os << " = " << defaultValue;
33 }
34 
36  if (optional)
37  os << "/*optional*/";
38  os << type << getSpaceAfterType(type) << name;
39 }
40 
41 //===----------------------------------------------------------------------===//
42 // MethodParameters definitions
43 //===----------------------------------------------------------------------===//
44 
46  llvm::interleaveComma(parameters, os,
47  [&os](auto &param) { param.writeDeclTo(os); });
48 }
50  llvm::interleaveComma(parameters, os,
51  [&os](auto &param) { param.writeDefTo(os); });
52 }
53 
54 bool MethodParameters::subsumes(const MethodParameters &other) const {
55  // These parameters do not subsume the others if there are fewer parameters
56  // or their types do not match.
57  if (parameters.size() < other.parameters.size())
58  return false;
59  if (!std::equal(
60  other.parameters.begin(), other.parameters.end(), parameters.begin(),
61  [](auto &lhs, auto &rhs) { return lhs.getType() == rhs.getType(); }))
62  return false;
63 
64  // If all the common parameters have the same type, we can elide the other
65  // method if this method has the same number of parameters as other or if the
66  // first paramater after the common parameters has a default value (and, as
67  // required by C++, subsequent parameters will have default values too).
68  return parameters.size() == other.parameters.size() ||
69  parameters[other.parameters.size()].hasDefaultValue();
70 }
71 
72 //===----------------------------------------------------------------------===//
73 // MethodSignature definitions
74 //===----------------------------------------------------------------------===//
75 
77  return methodName == other.methodName &&
78  parameters.subsumes(other.parameters);
79 }
80 
82  os << returnType << getSpaceAfterType(returnType) << methodName << "(";
83  parameters.writeDeclTo(os);
84  os << ")";
85 }
86 
88  StringRef namePrefix) const {
89  os << returnType << getSpaceAfterType(returnType) << namePrefix
90  << (namePrefix.empty() ? "" : "::") << methodName << "(";
91  parameters.writeDefTo(os);
92  os << ")";
93 }
94 
96  mlir::raw_indented_ostream &os) const {
97  if (templateParams.empty())
98  return;
99 
100  os << "template <";
101  llvm::interleaveComma(templateParams, os,
102  [&](StringRef param) { os << "typename " << param; });
103  os << ">\n";
104 }
105 
106 //===----------------------------------------------------------------------===//
107 // MethodBody definitions
108 //===----------------------------------------------------------------------===//
109 
111  : declOnly(declOnly), stringOs(body), os(stringOs) {}
112 
114  auto bodyRef = StringRef(body).ltrim('\n');
115  os << bodyRef;
116  if (bodyRef.empty())
117  return;
118  if (bodyRef.back() != '\n')
119  os << "\n";
120 }
121 
122 //===----------------------------------------------------------------------===//
123 // Method definitions
124 //===----------------------------------------------------------------------===//
125 
128  if (deprecationMessage) {
129  os << "[[deprecated(\"";
130  os.write_escaped(*deprecationMessage);
131  os << "\")]]\n";
132  }
133  if (isStatic())
134  os << "static ";
136  os << "constexpr ";
138  if (isConst())
139  os << " const";
140  if (!isInline()) {
141  os << ";\n";
142  return;
143  }
144  os << " {\n";
145  methodBody.writeTo(os);
146  os << "}\n\n";
147 }
148 
149 void Method::writeDefTo(raw_indented_ostream &os, StringRef namePrefix) const {
150  // The method has no definition to write if it is declaration only or inline.
151  if (properties & Declaration || isInline())
152  return;
153 
154  methodSignature.writeDefTo(os, namePrefix);
155  if (isConst())
156  os << " const";
157  os << " {\n";
158  methodBody.writeTo(os);
159  os << "}\n\n";
160 }
161 
162 bool Method::methodPropertiesAreCompatible(Properties properties) {
163  const bool isStatic = (properties & Method::Static);
165  // const bool isPrivate = (properties & Method::Private);
166  const bool isDeclaration = (properties & Method::Declaration);
167  const bool isInline = (properties & Method::Inline);
168  const bool isConstexprValue = (properties & Method::ConstexprValue);
169  const bool isConst = (properties & Method::Const);
170 
171  // Note: assert to immediately fail and thus simplify debugging.
172  if (isStatic && isConstructor) {
173  assert(false && "constructor cannot be static");
174  return false;
175  }
176  if (isConstructor && isConst) { // albeit constexpr is fine
177  assert(false && "constructor cannot be const");
178  return false;
179  }
180  if (isDeclaration && isInline) {
181  assert(false &&
182  "declaration implies no definition and thus cannot be inline");
183  return false;
184  }
185  if (isDeclaration && isConstexprValue) {
186  assert(false &&
187  "declaration implies no definition and thus cannot be constexpr");
188  return false;
189  }
190 
191  return true;
192 }
193 
194 //===----------------------------------------------------------------------===//
195 // Constructor definitions
196 //===----------------------------------------------------------------------===//
197 
201  os << "constexpr ";
203  if (!isInline()) {
204  os << ";\n\n";
205  return;
206  }
207  os << ' ';
208  if (!initializers.empty())
209  os << ": ";
210  llvm::interleaveComma(initializers, os,
211  [&](auto &initializer) { initializer.writeTo(os); });
212  if (!initializers.empty())
213  os << ' ';
214  os << "{";
215  methodBody.writeTo(os);
216  os << "}\n\n";
217 }
218 
220  StringRef namePrefix) const {
221  // The method has no definition to write if it is declaration only or inline.
222  if (properties & Declaration || isInline())
223  return;
224 
225  methodSignature.writeDefTo(os, namePrefix);
226  os << ' ';
227  if (!initializers.empty())
228  os << ": ";
229  llvm::interleaveComma(initializers, os,
230  [&](auto &initializer) { initializer.writeTo(os); });
231  if (!initializers.empty())
232  os << ' ';
233  os << "{";
234  methodBody.writeTo(os);
235  os << "}\n\n";
236 }
237 
239  os << name << '(' << value << ')';
240 }
241 
242 //===----------------------------------------------------------------------===//
243 // Visibility definitions
244 //===----------------------------------------------------------------------===//
245 
246 namespace mlir {
247 namespace tblgen {
248 raw_ostream &operator<<(raw_ostream &os, Visibility visibility) {
249  switch (visibility) {
250  case Visibility::Public:
251  return os << "public";
253  return os << "protected";
254  case Visibility::Private:
255  return os << "private";
256  }
257  return os;
258 }
259 } // namespace tblgen
260 } // namespace mlir
261 
262 //===----------------------------------------------------------------------===//
263 // ParentClass definitions
264 //===----------------------------------------------------------------------===//
265 
267  os << visibility << ' ' << name;
268  if (!templateParams.empty()) {
269  auto scope = os.scope("<", ">", /*indent=*/false);
270  llvm::interleaveComma(templateParams, os,
271  [&](auto &param) { os << param; });
272  }
273 }
274 
275 //===----------------------------------------------------------------------===//
276 // UsingDeclaration definitions
277 //===----------------------------------------------------------------------===//
278 
280  if (!templateParams.empty()) {
281  os << "template <";
282  llvm::interleaveComma(templateParams, os, [&](StringRef paramName) {
283  os << "typename " << paramName;
284  });
285  os << ">\n";
286  }
287  os << "using " << name;
288  if (!value.empty())
289  os << " = " << value;
290  os << ";\n";
291 }
292 
293 //===----------------------------------------------------------------------===//
294 // Field definitions
295 //===----------------------------------------------------------------------===//
296 
298  os << type << ' ' << name << ";\n";
299 }
300 
301 //===----------------------------------------------------------------------===//
302 // VisibilityDeclaration definitions
303 //===----------------------------------------------------------------------===//
304 
306  os.unindent();
307  os << visibility << ":\n";
308  os.indent();
309 }
310 
311 //===----------------------------------------------------------------------===//
312 // ExtraClassDeclaration definitions
313 //===----------------------------------------------------------------------===//
314 
316  os.printReindented(extraClassDeclaration);
317 }
318 
320  StringRef namePrefix) const {
321  os.printReindented(extraClassDefinition);
322 }
323 
324 //===----------------------------------------------------------------------===//
325 // Class definitions
326 //===----------------------------------------------------------------------===//
327 
329  parents.push_back(std::move(parent));
330  return parents.back();
331 }
332 
334  if (!templateParams.empty()) {
335  os << "template <";
336  llvm::interleaveComma(templateParams, os,
337  [&](StringRef param) { os << "typename " << param; });
338  os << ">\n";
339  }
340 
341  // Declare the class.
342  os << (isStruct ? "struct" : "class") << ' ' << className << ' ';
343 
344  // Declare the parent classes, if any.
345  if (!parents.empty()) {
346  os << ": ";
347  llvm::interleaveComma(parents, os,
348  [&](auto &parent) { parent.writeTo(os); });
349  os << ' ';
350  }
351  auto classScope = os.scope("{\n", "};\n", /*indent=*/true);
352 
353  // Print all the class declarations.
354  for (auto &decl : declarations)
355  decl->writeDeclTo(os);
356 }
357 
358 void Class::writeDefTo(raw_indented_ostream &os) const {
359  // Print all the definitions.
360  for (auto &decl : declarations)
361  decl->writeDefTo(os, className);
362 }
363 
364 void Class::finalize() {
365  // Sort the methods by public and private. Remove them from the pending list
366  // of methods.
367  SmallVector<std::unique_ptr<Method>> publicMethods, privateMethods;
368  for (auto &method : methods) {
369  if (method->isPrivate())
370  privateMethods.push_back(std::move(method));
371  else
372  publicMethods.push_back(std::move(method));
373  }
374  methods.clear();
375 
376  // If the last visibility declaration wasn't `public`, add one that is. Then,
377  // declare the public methods.
378  if (!publicMethods.empty() && getLastVisibilityDecl() != Visibility::Public)
379  declare<VisibilityDeclaration>(Visibility::Public);
380  for (auto &method : publicMethods)
381  declarations.push_back(std::move(method));
382 
383  // If the last visibility declaration wasn't `private`, add one that is. Then,
384  // declare the private methods.
385  if (!privateMethods.empty() && getLastVisibilityDecl() != Visibility::Private)
386  declare<VisibilityDeclaration>(Visibility::Private);
387  for (auto &method : privateMethods)
388  declarations.push_back(std::move(method));
389 
390  // All fields added to the pending list are private and declared at the bottom
391  // of the class. If the last visibility declaration wasn't `private`, add one
392  // that is, then declare the fields.
393  if (!fields.empty() && getLastVisibilityDecl() != Visibility::Private)
394  declare<VisibilityDeclaration>(Visibility::Private);
395  for (auto &field : fields)
396  declare<Field>(std::move(field));
397  fields.clear();
398 }
399 
401  auto reverseDecls = llvm::reverse(declarations);
402  auto it = llvm::find_if(reverseDecls, llvm::IsaPred<VisibilityDeclaration>);
403  return it == reverseDecls.end()
404  ? (isStruct ? Visibility::Public : Visibility::Private)
405  : cast<VisibilityDeclaration>(**it).getVisibility();
406 }
407 
408 Method *insertAndPruneMethods(std::vector<std::unique_ptr<Method>> &methods,
409  std::unique_ptr<Method> newMethod) {
410  if (llvm::any_of(methods, [&](auto &method) {
411  return method->makesRedundant(*newMethod);
412  }))
413  return nullptr;
414 
415  llvm::erase_if(methods, [&](auto &method) {
416  return newMethod->makesRedundant(*method);
417  });
418  methods.push_back(std::move(newMethod));
419  return methods.back().get();
420 }
421 
422 Method *Class::addMethodAndPrune(Method &&newMethod) {
423  return insertAndPruneMethods(methods,
424  std::make_unique<Method>(std::move(newMethod)));
425 }
426 
428  return dyn_cast_or_null<Constructor>(insertAndPruneMethods(
429  methods, std::make_unique<Constructor>(std::move(newCtor))));
430 }
static StringRef getSpaceAfterType(StringRef type)
Returns space to be emitted after the given C++ type.
Definition: Class.cpp:18
raw_ostream subclass that simplifies indention a sequence of code.
raw_indented_ostream & unindent()
Decreases the indent and returning this raw_indented_ostream.
DelimitedScope scope(StringRef open="", StringRef close="", bool indent=true)
Returns DelimitedScope.
raw_indented_ostream & indent()
Increases the indent and returning this raw_indented_ostream.
raw_indented_ostream & printReindented(StringRef str, StringRef extraPrefix="")
Prints a string re-indented to the current indent.
ParentClass & addParent(ParentClass parent)
Add a parent class.
virtual void finalize()
The declaration of a class needs to be "finalized".
void writeDefTo(raw_ostream &rawOs) const
Write the definitions of thiss class's out-of-line constructors and methods.
Definition: Class.h:825
Constructor * addConstructorAndPrune(Constructor &&newCtor)
Add a new constructor if it is not made redundant by any existing constructors and prune and existing...
Visibility getLastVisibilityDecl() const
Get the last visibility declaration.
void writeDeclTo(raw_ostream &rawOs) const
Write the declaration of this class, all declarations, and definitions of inline functions.
Definition: Class.h:819
Method * addMethodAndPrune(Method &&newMethod)
Add a new method if it is not made redundant by any existing methods and prune and existing methods m...
void writeTo(raw_indented_ostream &os) const
Write the member initializer.
void writeDefTo(raw_indented_ostream &os, StringRef namePrefix) const override
Write the definition of the constructor if it is not inline.
void writeDeclTo(raw_indented_ostream &os) const override
Write the declaration of the constructor, and its definition if inline.
void writeDefTo(raw_indented_ostream &os, StringRef namePrefix) const override
Write the extra class definitions.
void writeDeclTo(raw_indented_ostream &os) const override
Write the extra class declarations.
void writeDeclTo(raw_indented_ostream &os) const override
Write the declaration of the field.
void writeTo(raw_indented_ostream &os) const
Write the method body to the output stream.
Definition: Class.cpp:113
MethodBody(bool declOnly)
Create a method body, indicating whether it should be elided for methods that are declaration-only.
Definition: Class.cpp:110
void writeDefTo(raw_indented_ostream &os) const
Write the parameter as part of a method definition.
Definition: Class.cpp:35
bool hasDefaultValue() const
Returns true if the parameter has a default value.
Definition: Class.h:73
void writeDeclTo(raw_indented_ostream &os) const
Write the parameter as part of a method declaration.
Definition: Class.cpp:27
This class contains a list of method parameters for constructor, class methods, and method signatures...
Definition: Class.h:93
void writeDefTo(raw_indented_ostream &os) const
Write the parameters as part of a method definition.
Definition: Class.cpp:49
bool subsumes(const MethodParameters &other) const
Determine whether this list of parameters "subsumes" another, which occurs when this parameter list i...
Definition: Class.cpp:54
void writeDeclTo(raw_indented_ostream &os) const
Write the parameters as part of a method declaration.
Definition: Class.cpp:45
This class contains the signature of a C++ method, including the return type.
Definition: Class.h:121
bool makesRedundant(const MethodSignature &other) const
Determine whether a method with this signature makes a method with other signature redundant.
Definition: Class.cpp:76
void writeDeclTo(raw_indented_ostream &os) const
Write the signature as part of a method declaration.
Definition: Class.cpp:81
void writeTemplateParamsTo(raw_indented_ostream &os) const
Write the template parameters of the signature.
Definition: Class.cpp:95
void writeDefTo(raw_indented_ostream &os, StringRef namePrefix) const
Write the signature as part of a method definition.
Definition: Class.cpp:87
Class for holding an op's method for C++ code emission.
Definition: Class.h:310
bool isStatic() const
Returns true if this is a static method.
Definition: Class.h:370
MethodBody methodBody
The body of the method, if it has one.
Definition: Class.h:416
static bool methodPropertiesAreCompatible(Properties properties)
Utility method to verify method properties correctness.
MethodSignature methodSignature
The signature of the method.
Definition: Class.h:414
void writeDefTo(raw_indented_ostream &os, StringRef namePrefix) const override
Write the method definition. This is a no-op for inline methods.
void writeDeclTo(raw_indented_ostream &os) const override
Write the method declaration, including the definition if inline.
Definition: Class.cpp:126
Properties properties
A collection of method properties.
Definition: Class.h:412
std::optional< std::string > deprecationMessage
Deprecation message if the method is deprecated.
Definition: Class.h:418
bool isInline() const
Returns true if this is an inline method.
Definition: Class.h:376
bool isConstructor() const
Returns true if this is a constructor.
Definition: Class.h:379
bool isConst() const
Returns true if this class method is const.
Definition: Class.h:382
This class describes a C++ parent class declaration.
Definition: Class.h:521
void writeTo(raw_indented_ostream &os) const
Write the parent class declaration.
void writeDeclTo(raw_indented_ostream &os) const override
Write the using declaration.
void writeDeclTo(raw_indented_ostream &os) const override
Write the visibility declaration.
Visibility
This enum describes C++ inheritance visibility.
Definition: Class.h:426
llvm::raw_ostream & operator<<(llvm::raw_ostream &os, mlir::tblgen::Visibility visibility)
Write "public", "protected", or "private".
Include the generated interface declarations.