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