1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
|
//===- DialectGen.cpp - MLIR dialect definitions generator ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// DialectGen uses the description of dialects to generate C++ definitions.
//
//===----------------------------------------------------------------------===//
#include "mlir/TableGen/Format.h"
#include "mlir/TableGen/GenInfo.h"
#include "mlir/TableGen/Interfaces.h"
#include "mlir/TableGen/OpClass.h"
#include "mlir/TableGen/OpTrait.h"
#include "mlir/TableGen/Operator.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Signals.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#define DEBUG_TYPE "mlir-tblgen-opdefgen"
using namespace mlir;
using namespace mlir::tblgen;
static llvm::cl::OptionCategory dialectGenCat("Options for -gen-dialect-*");
static llvm::cl::opt<std::string>
selectedDialect("dialect", llvm::cl::desc("The dialect to gen for"),
llvm::cl::cat(dialectGenCat), llvm::cl::CommaSeparated);
/// Utility iterator used for filtering records for a specific dialect.
namespace {
using DialectFilterIterator =
llvm::filter_iterator<ArrayRef<llvm::Record *>::iterator,
std::function<bool(const llvm::Record *)>>;
} // end anonymous namespace
/// Given a set of records for a T, filter the ones that correspond to
/// the given dialect.
template <typename T>
static iterator_range<DialectFilterIterator>
filterForDialect(ArrayRef<llvm::Record *> records, Dialect &dialect) {
auto filterFn = [&](const llvm::Record *record) {
return T(record).getDialect() == dialect;
};
return {DialectFilterIterator(records.begin(), records.end(), filterFn),
DialectFilterIterator(records.end(), records.end(), filterFn)};
}
//===----------------------------------------------------------------------===//
// GEN: Dialect declarations
//===----------------------------------------------------------------------===//
/// The code block for the start of a dialect class declaration.
///
/// {0}: The name of the dialect class.
/// {1}: The dialect namespace.
static const char *const dialectDeclBeginStr = R"(
class {0} : public ::mlir::Dialect {
public:
explicit {0}(::mlir::MLIRContext *context);
static ::llvm::StringRef getDialectNamespace() { return "{1}"; }
)";
/// The code block for the attribute parser/printer hooks.
static const char *const attrParserDecl = R"(
/// Parse an attribute registered to this dialect.
::mlir::Attribute parseAttribute(::mlir::DialectAsmParser &parser,
::mlir::Type type) const override;
/// Print an attribute registered to this dialect.
void printAttribute(::mlir::Attribute attr,
::mlir::DialectAsmPrinter &os) const override;
)";
/// The code block for the type parser/printer hooks.
static const char *const typeParserDecl = R"(
/// Parse a type registered to this dialect.
::mlir::Type parseType(::mlir::DialectAsmParser &parser) const override;
/// Print a type registered to this dialect.
void printType(::mlir::Type type,
::mlir::DialectAsmPrinter &os) const override;
)";
/// The code block for the constant materializer hook.
static const char *const constantMaterializerDecl = R"(
/// Materialize a single constant operation from a given attribute value with
/// the desired resultant type.
::mlir::Operation *materializeConstant(::mlir::OpBuilder &builder,
::mlir::Attribute value,
::mlir::Type type,
::mlir::Location loc) override;
)";
/// The code block for the operation attribute verifier hook.
static const char *const opAttrVerifierDecl = R"(
/// Provides a hook for verifying dialect attributes attached to the given
/// op.
::mlir::LogicalResult verifyOperationAttribute(
::mlir::Operation *op, ::mlir::NamedAttribute attribute) override;
)";
/// The code block for the region argument attribute verifier hook.
static const char *const regionArgAttrVerifierDecl = R"(
/// Provides a hook for verifying dialect attributes attached to the given
/// op's region argument.
::mlir::LogicalResult verifyRegionArgAttribute(
::mlir::Operation *op, unsigned regionIndex, unsigned argIndex,
::mlir::NamedAttribute attribute) override;
)";
/// The code block for the region result attribute verifier hook.
static const char *const regionResultAttrVerifierDecl = R"(
/// Provides a hook for verifying dialect attributes attached to the given
/// op's region result.
::mlir::LogicalResult verifyRegionResultAttribute(
::mlir::Operation *op, unsigned regionIndex, unsigned resultIndex,
::mlir::NamedAttribute attribute) override;
)";
/// Generate the declaration for the given dialect class.
static void emitDialectDecl(Dialect &dialect,
iterator_range<DialectFilterIterator> dialectAttrs,
iterator_range<DialectFilterIterator> dialectTypes,
raw_ostream &os) {
// Emit the start of the decl.
std::string cppName = dialect.getCppClassName();
os << llvm::formatv(dialectDeclBeginStr, cppName, dialect.getName());
// Check for any attributes/types registered to this dialect. If there are,
// add the hooks for parsing/printing.
if (!dialectAttrs.empty())
os << attrParserDecl;
if (!dialectTypes.empty())
os << typeParserDecl;
// Add the decls for the various features of the dialect.
if (dialect.hasConstantMaterializer())
os << constantMaterializerDecl;
if (dialect.hasOperationAttrVerify())
os << opAttrVerifierDecl;
if (dialect.hasRegionArgAttrVerify())
os << regionArgAttrVerifierDecl;
if (dialect.hasRegionResultAttrVerify())
os << regionResultAttrVerifierDecl;
if (llvm::Optional<StringRef> extraDecl = dialect.getExtraClassDeclaration())
os << *extraDecl;
// End the dialect decl.
os << "};\n";
}
static bool emitDialectDecls(const llvm::RecordKeeper &recordKeeper,
raw_ostream &os) {
emitSourceFileHeader("Dialect Declarations", os);
auto defs = recordKeeper.getAllDerivedDefinitions("Dialect");
if (defs.empty())
return false;
// Select the dialect to gen for.
const llvm::Record *dialectDef = nullptr;
if (defs.size() == 1 && selectedDialect.getNumOccurrences() == 0) {
dialectDef = defs.front();
} else if (selectedDialect.getNumOccurrences() == 0) {
llvm::errs() << "when more than 1 dialect is present, one must be selected "
"via '-dialect'";
return true;
} else {
auto dialectIt = llvm::find_if(defs, [](const llvm::Record *def) {
return Dialect(def).getName() == selectedDialect;
});
if (dialectIt == defs.end()) {
llvm::errs() << "selected dialect with '-dialect' does not exist";
return true;
}
dialectDef = *dialectIt;
}
auto attrDefs = recordKeeper.getAllDerivedDefinitions("DialectAttr");
auto typeDefs = recordKeeper.getAllDerivedDefinitions("DialectType");
Dialect dialect(dialectDef);
emitDialectDecl(dialect, filterForDialect<Attribute>(attrDefs, dialect),
filterForDialect<Type>(typeDefs, dialect), os);
return false;
}
//===----------------------------------------------------------------------===//
// GEN: Dialect registration hooks
//===----------------------------------------------------------------------===//
static mlir::GenRegistration
genDialectDecls("gen-dialect-decls", "Generate dialect declarations",
[](const llvm::RecordKeeper &records, raw_ostream &os) {
return emitDialectDecls(records, os);
});
|