brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.6 KiB · c2c0c1f Raw
428 lines · cpp
1//===- DialectGen.cpp - MLIR dialect definitions 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// DialectGen uses the description of dialects to generate C++ definitions.10//11//===----------------------------------------------------------------------===//12 13#include "CppGenUtilities.h"14#include "DialectGenUtilities.h"15#include "mlir/TableGen/Class.h"16#include "mlir/TableGen/CodeGenHelpers.h"17#include "mlir/TableGen/Format.h"18#include "mlir/TableGen/GenInfo.h"19#include "mlir/TableGen/Interfaces.h"20#include "mlir/TableGen/Operator.h"21#include "mlir/TableGen/Trait.h"22#include "llvm/ADT/Sequence.h"23#include "llvm/ADT/StringExtras.h"24#include "llvm/Support/CommandLine.h"25#include "llvm/Support/Signals.h"26#include "llvm/TableGen/Error.h"27#include "llvm/TableGen/Record.h"28#include "llvm/TableGen/TableGenBackend.h"29 30#define DEBUG_TYPE "mlir-tblgen-opdefgen"31 32using namespace mlir;33using namespace mlir::tblgen;34using llvm::Record;35using llvm::RecordKeeper;36 37static llvm::cl::OptionCategory dialectGenCat("Options for -gen-dialect-*");38static llvm::cl::opt<std::string>39    selectedDialect("dialect", llvm::cl::desc("The dialect to gen for"),40                    llvm::cl::cat(dialectGenCat), llvm::cl::CommaSeparated);41 42/// Utility iterator used for filtering records for a specific dialect.43namespace {44using DialectFilterIterator =45    llvm::filter_iterator<ArrayRef<Record *>::iterator,46                          std::function<bool(const Record *)>>;47} // namespace48 49static void populateDiscardableAttributes(50    Dialect &dialect, const llvm::DagInit *discardableAttrDag,51    SmallVector<std::pair<std::string, std::string>> &discardableAttributes) {52  for (int i : llvm::seq<int>(0, discardableAttrDag->getNumArgs())) {53    const llvm::Init *arg = discardableAttrDag->getArg(i);54 55    StringRef givenName = discardableAttrDag->getArgNameStr(i);56    if (givenName.empty())57      PrintFatalError(dialect.getDef()->getLoc(),58                      "discardable attributes must be named");59    discardableAttributes.push_back(60        {givenName.str(), arg->getAsUnquotedString()});61  }62}63 64/// Given a set of records for a T, filter the ones that correspond to65/// the given dialect.66template <typename T>67static iterator_range<DialectFilterIterator>68filterForDialect(ArrayRef<Record *> records, Dialect &dialect) {69  auto filterFn = [&](const Record *record) {70    return T(record).getDialect() == dialect;71  };72  return {DialectFilterIterator(records.begin(), records.end(), filterFn),73          DialectFilterIterator(records.end(), records.end(), filterFn)};74}75 76std::optional<Dialect>77tblgen::findDialectToGenerate(ArrayRef<Dialect> dialects) {78  if (dialects.empty()) {79    llvm::errs() << "no dialect was found\n";80    return std::nullopt;81  }82 83  // Select the dialect to gen for.84  if (dialects.size() == 1 && selectedDialect.getNumOccurrences() == 0)85    return dialects.front();86 87  if (selectedDialect.getNumOccurrences() == 0) {88    llvm::errs() << "when more than 1 dialect is present, one must be selected "89                    "via '-dialect'\n";90    return std::nullopt;91  }92 93  const auto *dialectIt = llvm::find_if(dialects, [](const Dialect &dialect) {94    return dialect.getName() == selectedDialect;95  });96  if (dialectIt == dialects.end()) {97    llvm::errs() << "selected dialect with '-dialect' does not exist\n";98    return std::nullopt;99  }100  return *dialectIt;101}102 103//===----------------------------------------------------------------------===//104// GEN: Dialect declarations105//===----------------------------------------------------------------------===//106 107/// The code block for the start of a dialect class declaration.108///109/// {0}: The name of the dialect class.110/// {1}: The dialect namespace.111/// {2}: The dialect parent class.112static const char *const dialectDeclBeginStr = R"(113class {0} : public ::mlir::{2} {114  explicit {0}(::mlir::MLIRContext *context);115 116  void initialize();117  friend class ::mlir::MLIRContext;118public:119  ~{0}() override;120  static constexpr ::llvm::StringLiteral getDialectNamespace() {121    return ::llvm::StringLiteral("{1}");122  }123)";124 125/// Registration for a single dependent dialect: to be inserted in the ctor126/// above for each dependent dialect.127const char *const dialectRegistrationTemplate =128    "getContext()->loadDialect<{0}>();";129 130/// The code block for the attribute parser/printer hooks.131static const char *const attrParserDecl = R"(132  /// Parse an attribute registered to this dialect.133  ::mlir::Attribute parseAttribute(::mlir::DialectAsmParser &parser,134                                   ::mlir::Type type) const override;135 136  /// Print an attribute registered to this dialect.137  void printAttribute(::mlir::Attribute attr,138                      ::mlir::DialectAsmPrinter &os) const override;139)";140 141/// The code block for the type parser/printer hooks.142static const char *const typeParserDecl = R"(143  /// Parse a type registered to this dialect.144  ::mlir::Type parseType(::mlir::DialectAsmParser &parser) const override;145 146  /// Print a type registered to this dialect.147  void printType(::mlir::Type type,148                 ::mlir::DialectAsmPrinter &os) const override;149)";150 151/// The code block for the canonicalization pattern registration hook.152static const char *const canonicalizerDecl = R"(153  /// Register canonicalization patterns.154  void getCanonicalizationPatterns(155      ::mlir::RewritePatternSet &results) const override;156)";157 158/// The code block for the constant materializer hook.159static const char *const constantMaterializerDecl = R"(160  /// Materialize a single constant operation from a given attribute value with161  /// the desired resultant type.162  ::mlir::Operation *materializeConstant(::mlir::OpBuilder &builder,163                                         ::mlir::Attribute value,164                                         ::mlir::Type type,165                                         ::mlir::Location loc) override;166)";167 168/// The code block for the operation attribute verifier hook.169static const char *const opAttrVerifierDecl = R"(170    /// Provides a hook for verifying dialect attributes attached to the given171    /// op.172    ::llvm::LogicalResult verifyOperationAttribute(173        ::mlir::Operation *op, ::mlir::NamedAttribute attribute) override;174)";175 176/// The code block for the region argument attribute verifier hook.177static const char *const regionArgAttrVerifierDecl = R"(178    /// Provides a hook for verifying dialect attributes attached to the given179    /// op's region argument.180    ::llvm::LogicalResult verifyRegionArgAttribute(181        ::mlir::Operation *op, unsigned regionIndex, unsigned argIndex,182        ::mlir::NamedAttribute attribute) override;183)";184 185/// The code block for the region result attribute verifier hook.186static const char *const regionResultAttrVerifierDecl = R"(187    /// Provides a hook for verifying dialect attributes attached to the given188    /// op's region result.189    ::llvm::LogicalResult verifyRegionResultAttribute(190        ::mlir::Operation *op, unsigned regionIndex, unsigned resultIndex,191        ::mlir::NamedAttribute attribute) override;192)";193 194/// The code block for the op interface fallback hook.195static const char *const operationInterfaceFallbackDecl = R"(196    /// Provides a hook for op interface.197    void *getRegisteredInterfaceForOp(mlir::TypeID interfaceID,198                                      mlir::OperationName opName) override;199)";200 201/// The code block for the discardable attribute helper.202static const char *const discardableAttrHelperDecl = R"(203    /// Helper to manage the discardable attribute `{1}`.204    class {0}AttrHelper {{205      ::mlir::StringAttr name;206    public:207      static constexpr ::llvm::StringLiteral getNameStr() {{208        return "{4}.{1}";209      }210      constexpr ::mlir::StringAttr getName() {{211        return name;212      }213 214      {0}AttrHelper(::mlir::MLIRContext *ctx)215        : name(::mlir::StringAttr::get(ctx, getNameStr())) {{}216 217     {2} getAttr(::mlir::Operation *op) {{218       return op->getAttrOfType<{2}>(name);219     }220     void setAttr(::mlir::Operation *op, {2} val) {{221       op->setAttr(name, val);222     }223     bool isAttrPresent(::mlir::Operation *op) {{224       return op->hasAttrOfType<{2}>(name);225     }226     void removeAttr(::mlir::Operation *op) {{227       assert(op->hasAttrOfType<{2}>(name));228       op->removeAttr(name);229     }230   };231   {0}AttrHelper get{0}AttrHelper() {232     return {3}AttrName;233   }234 private:235   {0}AttrHelper {3}AttrName;236 public:237)";238 239/// Generate the declaration for the given dialect class.240static void emitDialectDecl(Dialect &dialect, raw_ostream &os) {241  // Emit all nested namespaces.242  {243    DialectNamespaceEmitter nsEmitter(os, dialect);244 245    // Emit the start of the decl.246    std::string cppName = dialect.getCppClassName();247    StringRef superClassName =248        dialect.isExtensible() ? "ExtensibleDialect" : "Dialect";249 250    tblgen::emitSummaryAndDescComments(os, dialect.getSummary(),251                                       dialect.getDescription(),252                                       /*terminateCmment=*/false);253    os << llvm::formatv(dialectDeclBeginStr, cppName, dialect.getName(),254                        superClassName);255 256    // If the dialect requested the default attribute printer and parser, emit257    // the declarations for the hooks.258    if (dialect.useDefaultAttributePrinterParser())259      os << attrParserDecl;260    // If the dialect requested the default type printer and parser, emit the261    // delcarations for the hooks.262    if (dialect.useDefaultTypePrinterParser())263      os << typeParserDecl;264 265    // Add the decls for the various features of the dialect.266    if (dialect.hasCanonicalizer())267      os << canonicalizerDecl;268    if (dialect.hasConstantMaterializer())269      os << constantMaterializerDecl;270    if (dialect.hasOperationAttrVerify())271      os << opAttrVerifierDecl;272    if (dialect.hasRegionArgAttrVerify())273      os << regionArgAttrVerifierDecl;274    if (dialect.hasRegionResultAttrVerify())275      os << regionResultAttrVerifierDecl;276    if (dialect.hasOperationInterfaceFallback())277      os << operationInterfaceFallbackDecl;278 279    const llvm::DagInit *discardableAttrDag =280        dialect.getDiscardableAttributes();281    SmallVector<std::pair<std::string, std::string>> discardableAttributes;282    populateDiscardableAttributes(dialect, discardableAttrDag,283                                  discardableAttributes);284 285    for (const auto &attrPair : discardableAttributes) {286      std::string camelNameUpper = llvm::convertToCamelFromSnakeCase(287          attrPair.first, /*capitalizeFirst=*/true);288      std::string camelName = llvm::convertToCamelFromSnakeCase(289          attrPair.first, /*capitalizeFirst=*/false);290      os << llvm::formatv(discardableAttrHelperDecl, camelNameUpper,291                          attrPair.first, attrPair.second, camelName,292                          dialect.getName());293    }294 295    if (std::optional<StringRef> extraDecl = dialect.getExtraClassDeclaration())296      os << *extraDecl;297 298    // End the dialect decl.299    os << "};\n";300  }301  if (!dialect.getCppNamespace().empty())302    os << "MLIR_DECLARE_EXPLICIT_TYPE_ID(" << dialect.getCppNamespace()303       << "::" << dialect.getCppClassName() << ")\n";304}305 306static bool emitDialectDecls(const RecordKeeper &records, raw_ostream &os) {307  emitSourceFileHeader("Dialect Declarations", os, records);308 309  auto dialectDefs = records.getAllDerivedDefinitions("Dialect");310  if (dialectDefs.empty())311    return false;312 313  SmallVector<Dialect> dialects(dialectDefs.begin(), dialectDefs.end());314  std::optional<Dialect> dialect = findDialectToGenerate(dialects);315  if (!dialect)316    return true;317  emitDialectDecl(*dialect, os);318  return false;319}320 321//===----------------------------------------------------------------------===//322// GEN: Dialect definitions323//===----------------------------------------------------------------------===//324 325/// The code block to generate a dialect constructor definition.326///327/// {0}: The name of the dialect class.328/// {1}: Initialization code that is emitted in the ctor body before calling329///      initialize(), such as dependent dialect registration.330/// {2}: The dialect parent class.331/// {3}: Extra members to initialize332static const char *const dialectConstructorStr = R"(333{0}::{0}(::mlir::MLIRContext *context)334    : ::mlir::{2}(getDialectNamespace(), context, ::mlir::TypeID::get<{0}>())335    {3}336     {{337  {1}338  initialize();339}340)";341 342/// The code block to generate a default destructor definition.343///344/// {0}: The name of the dialect class.345static const char *const dialectDestructorStr = R"(346{0}::~{0}() = default;347 348)";349 350static void emitDialectDef(Dialect &dialect, const RecordKeeper &records,351                           raw_ostream &os) {352  std::string cppClassName = dialect.getCppClassName();353 354  // Emit the TypeID explicit specializations to have a single symbol def.355  if (!dialect.getCppNamespace().empty())356    os << "MLIR_DEFINE_EXPLICIT_TYPE_ID(" << dialect.getCppNamespace()357       << "::" << cppClassName << ")\n";358 359  // Emit all nested namespaces.360  DialectNamespaceEmitter nsEmitter(os, dialect);361 362  /// Build the list of dependent dialects.363  std::string dependentDialectRegistrations;364  {365    llvm::raw_string_ostream dialectsOs(dependentDialectRegistrations);366    llvm::interleave(367        dialect.getDependentDialects(), dialectsOs,368        [&](StringRef dependentDialect) {369          dialectsOs << llvm::formatv(dialectRegistrationTemplate,370                                      dependentDialect);371        },372        "\n  ");373  }374 375  // Emit the constructor and destructor.376  StringRef superClassName =377      dialect.isExtensible() ? "ExtensibleDialect" : "Dialect";378 379  const llvm::DagInit *discardableAttrDag = dialect.getDiscardableAttributes();380  SmallVector<std::pair<std::string, std::string>> discardableAttributes;381  populateDiscardableAttributes(dialect, discardableAttrDag,382                                discardableAttributes);383  std::string discardableAttributesInit;384  for (const auto &attrPair : discardableAttributes) {385    std::string camelName = llvm::convertToCamelFromSnakeCase(386        attrPair.first, /*capitalizeFirst=*/false);387    llvm::raw_string_ostream os(discardableAttributesInit);388    os << ", " << camelName << "AttrName(context)";389  }390 391  os << llvm::formatv(dialectConstructorStr, cppClassName,392                      dependentDialectRegistrations, superClassName,393                      discardableAttributesInit);394  if (!dialect.hasNonDefaultDestructor())395    os << llvm::formatv(dialectDestructorStr, cppClassName);396}397 398static bool emitDialectDefs(const RecordKeeper &records, raw_ostream &os) {399  emitSourceFileHeader("Dialect Definitions", os, records);400 401  auto dialectDefs = records.getAllDerivedDefinitions("Dialect");402  if (dialectDefs.empty())403    return false;404 405  SmallVector<Dialect> dialects(dialectDefs.begin(), dialectDefs.end());406  std::optional<Dialect> dialect = findDialectToGenerate(dialects);407  if (!dialect)408    return true;409  emitDialectDef(*dialect, records, os);410  return false;411}412 413//===----------------------------------------------------------------------===//414// GEN: Dialect registration hooks415//===----------------------------------------------------------------------===//416 417static mlir::GenRegistration418    genDialectDecls("gen-dialect-decls", "Generate dialect declarations",419                    [](const RecordKeeper &records, raw_ostream &os) {420                      return emitDialectDecls(records, os);421                    });422 423static mlir::GenRegistration424    genDialectDefs("gen-dialect-defs", "Generate dialect definitions",425                   [](const RecordKeeper &records, raw_ostream &os) {426                     return emitDialectDefs(records, os);427                   });428