brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.4 KiB · 81f1aee Raw
431 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "mlir/TableGen/Class.h"10#include "llvm/ADT/Twine.h"11#include "llvm/Support/Debug.h"12 13using namespace mlir;14using namespace mlir::tblgen;15 16/// Returns space to be emitted after the given C++ `type`. return "" if the17/// ends with '&' or '*', or is empty, else returns " ".18static StringRef getSpaceAfterType(StringRef type) {19  return (type.empty() || type.ends_with("&") || type.ends_with("*")) ? ""20                                                                      : " ";21}22 23//===----------------------------------------------------------------------===//24// MethodParameter definitions25//===----------------------------------------------------------------------===//26 27void MethodParameter::writeDeclTo(raw_indented_ostream &os) const {28  if (optional)29    os << "/*optional*/";30  os << type << getSpaceAfterType(type) << name;31  if (hasDefaultValue())32    os << " = " << defaultValue;33}34 35void MethodParameter::writeDefTo(raw_indented_ostream &os) const {36  if (optional)37    os << "/*optional*/";38  os << type << getSpaceAfterType(type) << name;39}40 41//===----------------------------------------------------------------------===//42// MethodParameters definitions43//===----------------------------------------------------------------------===//44 45void MethodParameters::writeDeclTo(raw_indented_ostream &os) const {46  llvm::interleaveComma(parameters, os,47                        [&os](auto &param) { param.writeDeclTo(os); });48}49void MethodParameters::writeDefTo(raw_indented_ostream &os) const {50  llvm::interleaveComma(parameters, os,51                        [&os](auto &param) { param.writeDefTo(os); });52}53 54bool MethodParameters::subsumes(const MethodParameters &other) const {55  // These parameters do not subsume the others if there are fewer parameters56  // 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 other65  // method if this method has the same number of parameters as other or if the66  // first paramater after the common parameters has a default value (and, as67  // 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 definitions74//===----------------------------------------------------------------------===//75 76bool MethodSignature::makesRedundant(const MethodSignature &other) const {77  return methodName == other.methodName &&78         parameters.subsumes(other.parameters);79}80 81void MethodSignature::writeDeclTo(raw_indented_ostream &os) const {82  os << returnType << getSpaceAfterType(returnType) << methodName << "(";83  parameters.writeDeclTo(os);84  os << ")";85}86 87void MethodSignature::writeDefTo(raw_indented_ostream &os,88                                 StringRef namePrefix) const {89  os << returnType << getSpaceAfterType(returnType) << namePrefix90     << (namePrefix.empty() ? "" : "::") << methodName << "(";91  parameters.writeDefTo(os);92  os << ")";93}94 95void MethodSignature::writeTemplateParamsTo(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 definitions108//===----------------------------------------------------------------------===//109 110MethodBody::MethodBody(bool declOnly)111    : declOnly(declOnly), stringOs(body), os(stringOs) {}112 113void MethodBody::writeTo(raw_indented_ostream &os) const {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 definitions124//===----------------------------------------------------------------------===//125 126void Method::writeDeclTo(raw_indented_ostream &os) const {127  methodSignature.writeTemplateParamsTo(os);128  if (deprecationMessage) {129    os << "[[deprecated(\"";130    os.write_escaped(*deprecationMessage);131    os << "\")]]\n";132  }133  if (isStatic())134    os << "static ";135  if (properties & ConstexprValue)136    os << "constexpr ";137  methodSignature.writeDeclTo(os);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 149void 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 162bool Method::methodPropertiesAreCompatible(Properties properties) {163  const bool isStatic = (properties & Method::Static);164  const bool isConstructor = (properties & Method::Constructor);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 fine177    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 definitions196//===----------------------------------------------------------------------===//197 198void Constructor::writeDeclTo(raw_indented_ostream &os) const {199  methodSignature.writeTemplateParamsTo(os);200  if (properties & ConstexprValue)201    os << "constexpr ";202  methodSignature.writeDeclTo(os);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 219void Constructor::writeDefTo(raw_indented_ostream &os,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 238void Constructor::MemberInitializer::writeTo(raw_indented_ostream &os) const {239  os << name << '(' << value << ')';240}241 242//===----------------------------------------------------------------------===//243// Visibility definitions244//===----------------------------------------------------------------------===//245 246namespace mlir {247namespace tblgen {248raw_ostream &operator<<(raw_ostream &os, Visibility visibility) {249  switch (visibility) {250  case Visibility::Public:251    return os << "public";252  case Visibility::Protected:253    return os << "protected";254  case Visibility::Private:255    return os << "private";256  }257  return os;258}259} // namespace tblgen260} // namespace mlir261 262//===----------------------------------------------------------------------===//263// ParentClass definitions264//===----------------------------------------------------------------------===//265 266void ParentClass::writeTo(raw_indented_ostream &os) const {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 definitions277//===----------------------------------------------------------------------===//278 279void UsingDeclaration::writeDeclTo(raw_indented_ostream &os) const {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 definitions295//===----------------------------------------------------------------------===//296 297void Field::writeDeclTo(raw_indented_ostream &os) const {298  os << type << ' ' << name << ";\n";299}300 301//===----------------------------------------------------------------------===//302// VisibilityDeclaration definitions303//===----------------------------------------------------------------------===//304 305void VisibilityDeclaration::writeDeclTo(raw_indented_ostream &os) const {306  os.unindent();307  os << visibility << ":\n";308  os.indent();309}310 311//===----------------------------------------------------------------------===//312// ExtraClassDeclaration definitions313//===----------------------------------------------------------------------===//314 315void ExtraClassDeclaration::writeDeclTo(raw_indented_ostream &os) const {316  os.printReindented(extraClassDeclaration);317}318 319void ExtraClassDeclaration::writeDefTo(raw_indented_ostream &os,320                                       StringRef namePrefix) const {321  os.printReindented(extraClassDefinition);322}323 324//===----------------------------------------------------------------------===//325// Class definitions326//===----------------------------------------------------------------------===//327 328ParentClass &Class::addParent(ParentClass parent) {329  parents.push_back(std::move(parent));330  return parents.back();331}332 333void Class::writeDeclTo(raw_indented_ostream &os) const {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 358void Class::writeDefTo(raw_indented_ostream &os) const {359  // Print all the definitions.360  for (auto &decl : declarations)361    decl->writeDefTo(os, className);362}363 364void Class::finalize() {365  // Sort the methods by public and private. Remove them from the pending list366  // 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    else372      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 bottom391  // of the class. If the last visibility declaration wasn't `private`, add one392  // 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 400Visibility Class::getLastVisibilityDecl() const {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 408Method *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 422Method *Class::addMethodAndPrune(Method &&newMethod) {423  return insertAndPruneMethods(methods,424                               std::make_unique<Method>(std::move(newMethod)));425}426 427Constructor *Class::addConstructorAndPrune(Constructor &&newCtor) {428  return dyn_cast_or_null<Constructor>(insertAndPruneMethods(429      methods, std::make_unique<Constructor>(std::move(newCtor))));430}431