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 ®istry) 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 ®istry) 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