brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.7 KiB · f4b8eb4 Raw
498 lines · cpp
1//===- Pass.cpp - MLIR pass registration generator ------------------------===//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// PassGen uses the description of passes to generate base classes for passes10// and command line registration.11//12//===----------------------------------------------------------------------===//13 14#include "mlir/TableGen/GenInfo.h"15#include "mlir/TableGen/Pass.h"16#include "llvm/ADT/StringExtras.h"17#include "llvm/Support/CommandLine.h"18#include "llvm/Support/FormatVariadic.h"19#include "llvm/TableGen/Error.h"20#include "llvm/TableGen/Record.h"21 22using namespace mlir;23using namespace mlir::tblgen;24using llvm::formatv;25using llvm::RecordKeeper;26 27static llvm::cl::OptionCategory passGenCat("Options for -gen-pass-decls");28static llvm::cl::opt<std::string>29    groupName("name", llvm::cl::desc("The name of this group of passes"),30              llvm::cl::cat(passGenCat));31 32/// Extract the list of passes from the TableGen records.33static std::vector<Pass> getPasses(const RecordKeeper &records) {34  std::vector<Pass> passes;35 36  for (const auto *def : records.getAllDerivedDefinitions("PassBase"))37    passes.emplace_back(def);38 39  return passes;40}41 42const char *const passHeader = R"(43//===----------------------------------------------------------------------===//44// {0}45//===----------------------------------------------------------------------===//46)";47 48//===----------------------------------------------------------------------===//49// GEN: Pass registration generation50//===----------------------------------------------------------------------===//51 52/// The code snippet used to generate a pass registration.53///54/// {0}: The def name of the pass record.55/// {1}: The pass constructor call.56const char *const passRegistrationCode = R"(57//===----------------------------------------------------------------------===//58// {0} Registration59//===----------------------------------------------------------------------===//60#ifdef {1}61 62inline void register{0}() {{63  ::mlir::registerPass([]() -> std::unique_ptr<::mlir::Pass> {{64    return {2};65  });66}67 68// Old registration code, kept for temporary backwards compatibility.69inline void register{0}Pass() {{70  ::mlir::registerPass([]() -> std::unique_ptr<::mlir::Pass> {{71    return {2};72  });73}74 75#undef {1}76#endif // {1}77)";78 79/// The code snippet used to generate a function to register all passes in a80/// group.81///82/// {0}: The name of the pass group.83const char *const passGroupRegistrationCode = R"(84//===----------------------------------------------------------------------===//85// {0} Registration86//===----------------------------------------------------------------------===//87 88inline void register{0}Passes() {{89)";90 91/// Emits the definition of the struct to be used to control the pass options.92static void emitPassOptionsStruct(const Pass &pass, raw_ostream &os) {93  StringRef passName = pass.getDef()->getName();94  ArrayRef<PassOption> options = pass.getOptions();95 96  // Emit the struct only if the pass has at least one option.97  if (options.empty())98    return;99 100  os << formatv("struct {0}Options {{\n", passName);101 102  for (const PassOption &opt : options) {103    std::string type = opt.getType().str();104 105    if (opt.isListOption())106      type = "::llvm::SmallVector<" + type + ">";107 108    os.indent(2) << formatv("{0} {1}", type, opt.getCppVariableName());109 110    if (std::optional<StringRef> defaultVal = opt.getDefaultValue())111      os << " = " << defaultVal;112 113    os << ";\n";114  }115 116  os << "};\n";117}118 119static std::string getPassDeclVarName(const Pass &pass) {120  return "GEN_PASS_DECL_" + pass.getDef()->getName().upper();121}122 123static std::string getPassRegistrationVarName(const Pass &pass) {124  return "GEN_PASS_REGISTRATION_" + pass.getDef()->getName().upper();125}126 127/// Emit the code to be included in the public header of the pass.128static void emitPassDecls(const Pass &pass, raw_ostream &os) {129  StringRef passName = pass.getDef()->getName();130  std::string enableVarName = getPassDeclVarName(pass);131 132  os << "#ifdef " << enableVarName << "\n";133  emitPassOptionsStruct(pass, os);134 135  if (StringRef constructor = pass.getConstructor(); constructor.empty()) {136    // Default constructor declaration.137    os << "std::unique_ptr<::mlir::Pass> create" << passName << "();\n";138 139    // Declaration of the constructor with options.140    if (ArrayRef<PassOption> options = pass.getOptions(); !options.empty())141      os << formatv("std::unique_ptr<::mlir::Pass> create{0}("142                    "{0}Options options);\n",143                    passName);144  }145 146  os << "#undef " << enableVarName << "\n";147  os << "#endif // " << enableVarName << "\n";148}149 150/// Emit the code for registering each of the given passes with the global151/// PassRegistry.152static void emitRegistrations(llvm::ArrayRef<Pass> passes, raw_ostream &os) {153  os << "#ifdef GEN_PASS_REGISTRATION\n";154  os << "// Generate registrations for all passes.\n";155  for (const Pass &pass : passes)156    os << "#define " << getPassRegistrationVarName(pass) << "\n";157  os << "#endif // GEN_PASS_REGISTRATION\n";158 159  for (const Pass &pass : passes) {160    std::string passName = pass.getDef()->getName().str();161    std::string passEnableVarName = getPassRegistrationVarName(pass);162 163    std::string constructorCall;164    if (StringRef constructor = pass.getConstructor(); !constructor.empty())165      constructorCall = constructor.str();166    else167      constructorCall = formatv("create{0}()", passName).str();168    os << formatv(passRegistrationCode, passName, passEnableVarName,169                  constructorCall);170  }171 172  os << "#ifdef GEN_PASS_REGISTRATION\n";173  os << formatv(passGroupRegistrationCode, groupName);174 175  for (const Pass &pass : passes)176    os << "  register" << pass.getDef()->getName() << "();\n";177 178  os << "}\n";179  os << "#undef GEN_PASS_REGISTRATION\n";180  os << "#endif // GEN_PASS_REGISTRATION\n";181}182 183//===----------------------------------------------------------------------===//184// GEN: Pass base class generation185//===----------------------------------------------------------------------===//186 187/// The code snippet used to generate the start of a pass base class.188///189/// {0}: The def name of the pass record.190/// {1}: The base class for the pass.191/// {2): The command line argument for the pass.192/// {3}: The summary for the pass.193/// {4}: The dependent dialects registration.194const char *const baseClassBegin = R"(195template <typename DerivedT>196class {0}Base : public {1} {197public:198  using Base = {0}Base;199 200  {0}Base() : {1}(::mlir::TypeID::get<DerivedT>()) {{}201  {0}Base(const {0}Base &other) : {1}(other) {{}202  {0}Base& operator=(const {0}Base &) = delete;203  {0}Base({0}Base &&) = delete;204  {0}Base& operator=({0}Base &&) = delete;205  ~{0}Base() = default;206 207  /// Returns the command-line argument attached to this pass.208  static constexpr ::llvm::StringLiteral getArgumentName() {209    return ::llvm::StringLiteral("{2}");210  }211  ::llvm::StringRef getArgument() const override { return "{2}"; }212 213  ::llvm::StringRef getDescription() const override { return R"PD({3})PD"; }214 215  /// Returns the derived pass name.216  static constexpr ::llvm::StringLiteral getPassName() {217    return ::llvm::StringLiteral("{0}");218  }219  ::llvm::StringRef getName() const override { return "{0}"; }220 221  /// Support isa/dyn_cast functionality for the derived pass class.222  static bool classof(const ::mlir::Pass *pass) {{223    return pass->getTypeID() == ::mlir::TypeID::get<DerivedT>();224  }225 226  /// A clone method to create a copy of this pass.227  std::unique_ptr<::mlir::Pass> clonePass() const override {{228    return std::make_unique<DerivedT>(*static_cast<const DerivedT *>(this));229  }230 231  /// Return the dialect that must be loaded in the context before this pass.232  void getDependentDialects(::mlir::DialectRegistry &registry) const override {233    {4}234  }235 236  /// Explicitly declare the TypeID for this class. We declare an explicit private237  /// instantiation because Pass classes should only be visible by the current238  /// library.239  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID({0}Base<DerivedT>)240 241)";242 243/// Registration for a single dependent dialect, to be inserted for each244/// dependent dialect in the `getDependentDialects` above.245const char *const dialectRegistrationTemplate = "registry.insert<{0}>();";246 247const char *const friendDefaultConstructorDeclTemplate = R"(248namespace impl {{249  std::unique_ptr<::mlir::Pass> create{0}();250} // namespace impl251)";252 253const char *const friendDefaultConstructorWithOptionsDeclTemplate = R"(254namespace impl {{255  std::unique_ptr<::mlir::Pass> create{0}({0}Options options);256} // namespace impl257)";258 259const char *const friendDefaultConstructorDefTemplate = R"(260  friend std::unique_ptr<::mlir::Pass> create{0}() {{261    return std::make_unique<DerivedT>();262  }263)";264 265const char *const friendDefaultConstructorWithOptionsDefTemplate = R"(266  friend std::unique_ptr<::mlir::Pass> create{0}({0}Options options) {{267    return std::make_unique<DerivedT>(std::move(options));268  }269)";270 271const char *const defaultConstructorDefTemplate = R"(272std::unique_ptr<::mlir::Pass> create{0}() {{273  return impl::create{0}();274}275)";276 277const char *const defaultConstructorWithOptionsDefTemplate = R"(278std::unique_ptr<::mlir::Pass> create{0}({0}Options options) {{279  return impl::create{0}(std::move(options));280}281)";282 283/// Emit the declarations for each of the pass options.284static void emitPassOptionDecls(const Pass &pass, raw_ostream &os) {285  for (const PassOption &opt : pass.getOptions()) {286    os.indent(2) << "::mlir::Pass::"287                 << (opt.isListOption() ? "ListOption" : "Option");288 289    os << formatv(R"(<{0}> {1}{{*this, "{2}", ::llvm::cl::desc(R"PO({3})PO"))",290                  opt.getType(), opt.getCppVariableName(), opt.getArgument(),291                  opt.getDescription().trim());292    if (std::optional<StringRef> defaultVal = opt.getDefaultValue())293      os << ", ::llvm::cl::init(" << defaultVal << ")";294    if (std::optional<StringRef> additionalFlags = opt.getAdditionalFlags())295      os << ", " << *additionalFlags;296    os << "};\n";297  }298}299 300/// Emit the declarations for each of the pass statistics.301static void emitPassStatisticDecls(const Pass &pass, raw_ostream &os) {302  for (const PassStatistic &stat : pass.getStatistics()) {303    os << formatv(304        "  ::mlir::Pass::Statistic {0}{{this, \"{1}\", R\"PS({2})PS\"};\n",305        stat.getCppVariableName(), stat.getName(),306        stat.getDescription().trim());307  }308}309 310/// Emit the code to be used in the implementation of the pass.311static void emitPassDefs(const Pass &pass, raw_ostream &os) {312  StringRef passName = pass.getDef()->getName();313  std::string enableVarName = "GEN_PASS_DEF_" + passName.upper();314  bool emitDefaultConstructors = pass.getConstructor().empty();315  bool emitDefaultConstructorWithOptions = !pass.getOptions().empty();316 317  os << "#ifdef " << enableVarName << "\n";318 319  if (emitDefaultConstructors) {320    os << formatv(friendDefaultConstructorDeclTemplate, passName);321 322    if (emitDefaultConstructorWithOptions)323      os << formatv(friendDefaultConstructorWithOptionsDeclTemplate, passName);324  }325 326  std::string dependentDialectRegistrations;327  {328    llvm::raw_string_ostream dialectsOs(dependentDialectRegistrations);329    llvm::interleave(330        pass.getDependentDialects(), dialectsOs,331        [&](StringRef dependentDialect) {332          dialectsOs << formatv(dialectRegistrationTemplate, dependentDialect);333        },334        "\n    ");335  }336 337  os << "namespace impl {\n";338  os << formatv(baseClassBegin, passName, pass.getBaseClass(),339                pass.getArgument(), pass.getSummary().trim(),340                dependentDialectRegistrations);341 342  if (ArrayRef<PassOption> options = pass.getOptions(); !options.empty()) {343    os.indent(2) << formatv("{0}Base({0}Options options) : {0}Base() {{\n",344                            passName);345 346    for (const PassOption &opt : pass.getOptions())347      os.indent(4) << formatv("{0} = std::move(options.{0});\n",348                              opt.getCppVariableName());349 350    os.indent(2) << "}\n";351  }352 353  // Protected content354  os << "protected:\n";355  emitPassOptionDecls(pass, os);356  emitPassStatisticDecls(pass, os);357 358  // Private content359  os << "private:\n";360 361  if (emitDefaultConstructors) {362    os << formatv(friendDefaultConstructorDefTemplate, passName);363 364    if (!pass.getOptions().empty())365      os << formatv(friendDefaultConstructorWithOptionsDefTemplate, passName);366  }367 368  os << "};\n";369  os << "} // namespace impl\n";370 371  if (emitDefaultConstructors) {372    os << formatv(defaultConstructorDefTemplate, passName);373 374    if (emitDefaultConstructorWithOptions)375      os << formatv(defaultConstructorWithOptionsDefTemplate, passName);376  }377 378  os << "#undef " << enableVarName << "\n";379  os << "#endif // " << enableVarName << "\n";380}381 382static void emitPass(const Pass &pass, raw_ostream &os) {383  StringRef passName = pass.getDef()->getName();384  os << formatv(passHeader, passName);385 386  emitPassDecls(pass, os);387  emitPassDefs(pass, os);388}389 390// TODO: Drop old pass declarations.391// The old pass base class is being kept until all the passes have switched to392// the new decls/defs design.393const char *const oldPassDeclBegin = R"(394template <typename DerivedT>395class {0}Base : public {1} {396public:397  using Base = {0}Base;398 399  {0}Base() : {1}(::mlir::TypeID::get<DerivedT>()) {{}400  {0}Base(const {0}Base &other) : {1}(other) {{}401  {0}Base& operator=(const {0}Base &) = delete;402  {0}Base({0}Base &&) = delete;403  {0}Base& operator=({0}Base &&) = delete;404  ~{0}Base() = default;405 406  /// Returns the command-line argument attached to this pass.407  static constexpr ::llvm::StringLiteral getArgumentName() {408    return ::llvm::StringLiteral("{2}");409  }410  ::llvm::StringRef getArgument() const override { return "{2}"; }411 412  ::llvm::StringRef getDescription() const override { return R"PD({3})PD"; }413 414  /// Returns the derived pass name.415  static constexpr ::llvm::StringLiteral getPassName() {416    return ::llvm::StringLiteral("{0}");417  }418  ::llvm::StringRef getName() const override { return "{0}"; }419 420  /// Support isa/dyn_cast functionality for the derived pass class.421  static bool classof(const ::mlir::Pass *pass) {{422    return pass->getTypeID() == ::mlir::TypeID::get<DerivedT>();423  }424 425  /// A clone method to create a copy of this pass.426  std::unique_ptr<::mlir::Pass> clonePass() const override {{427    return std::make_unique<DerivedT>(*static_cast<const DerivedT *>(this));428  }429 430  /// Register the dialects that must be loaded in the context before this pass.431  void getDependentDialects(::mlir::DialectRegistry &registry) const override {432    {4}433  }434 435  /// Explicitly declare the TypeID for this class. We declare an explicit private436  /// instantiation because Pass classes should only be visible by the current437  /// library.438  MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID({0}Base<DerivedT>)439 440protected:441)";442 443// TODO: Drop old pass declarations.444/// Emit a backward-compatible declaration of the pass base class.445static void emitOldPassDecl(const Pass &pass, raw_ostream &os) {446  StringRef defName = pass.getDef()->getName();447  std::string dependentDialectRegistrations;448  {449    llvm::raw_string_ostream dialectsOs(dependentDialectRegistrations);450    llvm::interleave(451        pass.getDependentDialects(), dialectsOs,452        [&](StringRef dependentDialect) {453          dialectsOs << formatv(dialectRegistrationTemplate, dependentDialect);454        },455        "\n    ");456  }457  os << formatv(oldPassDeclBegin, defName, pass.getBaseClass(),458                pass.getArgument(), pass.getSummary().trim(),459                dependentDialectRegistrations);460  emitPassOptionDecls(pass, os);461  emitPassStatisticDecls(pass, os);462  os << "};\n";463}464 465static void emitPasses(const RecordKeeper &records, raw_ostream &os) {466  std::vector<Pass> passes = getPasses(records);467  os << "/* Autogenerated by mlir-tblgen; don't manually edit */\n";468 469  os << "\n";470  os << "#ifdef GEN_PASS_DECL\n";471  os << "// Generate declarations for all passes.\n";472  for (const Pass &pass : passes)473    os << "#define " << getPassDeclVarName(pass) << "\n";474  os << "#undef GEN_PASS_DECL\n";475  os << "#endif // GEN_PASS_DECL\n";476 477  for (const Pass &pass : passes)478    emitPass(pass, os);479 480  emitRegistrations(passes, os);481 482  // TODO: Drop old pass declarations.483  // Emit the old code until all the passes have switched to the new design.484  os << "// Deprecated. Please use the new per-pass macros.\n";485  os << "#ifdef GEN_PASS_CLASSES\n";486  for (const Pass &pass : passes)487    emitOldPassDecl(pass, os);488  os << "#undef GEN_PASS_CLASSES\n";489  os << "#endif // GEN_PASS_CLASSES\n";490}491 492static mlir::GenRegistration493    genPassDecls("gen-pass-decls", "Generate pass declarations",494                 [](const RecordKeeper &records, raw_ostream &os) {495                   emitPasses(records, os);496                   return false;497                 });498