diff --git a/mlir/test/CMakeLists.txt b/mlir/test/CMakeLists.txt --- a/mlir/test/CMakeLists.txt +++ b/mlir/test/CMakeLists.txt @@ -104,6 +104,7 @@ mlir-tblgen mlir-translate tblgen-lsp-server + tblgen-to-irdl ) # The native target may not be enabled, in this case we won't diff --git a/mlir/test/tblgen-to-irdl/CMathDialect.td b/mlir/test/tblgen-to-irdl/CMathDialect.td new file mode 100644 --- /dev/null +++ b/mlir/test/tblgen-to-irdl/CMathDialect.td @@ -0,0 +1,56 @@ +// RUN: tblgen-to-irdl %s -I=%S/../../include --gen-dialect-irdl-defs --dialect=cmath | FileCheck %s + +include "mlir/IR/OpBase.td" +include "mlir/IR/AttrTypeBase.td" + +// CHECK-LABEL: irdl.dialect @cmath { +def CMath_Dialect : Dialect { + let name = "cmath"; +} + +class CMath_Type traits = []> +: TypeDef { + let mnemonic = typeMnemonic; +} + +class CMath_Op traits = []> + : Op; + +def f32Orf64Type : Or<[CPred<"::llvm::isa<::mlir::F32>">, + CPred<"::llvm::isa<::mlir::F64>">]>; + +def CMath_ComplexType : CMath_Type<"ComplexType", "complex"> { + let parameters = (ins f32Orf64Type:$elementType); +} + +// CHECK: irdl.operation @identity { +// CHECK-NEXT: %0 = irdl.c_pred "(::llvm::isa($_self))" +// CHECK-NEXT: irdl.operands() +// CHECK-NEXT: irdl.results(%0) +// CHECK-NEXT: } +def CMath_IdentityOp : CMath_Op<"identity"> { + let results = (outs CMath_ComplexType:$out); +} + +// CHECK: irdl.operation @mul { +// CHECK-NEXT: %0 = irdl.c_pred "(::llvm::isa($_self))" +// CHECK-NEXT: %1 = irdl.c_pred "(::llvm::isa($_self))" +// CHECK-NEXT: %2 = irdl.c_pred "(::llvm::isa($_self))" +// CHECK-NEXT: irdl.operands(%0, %1) +// CHECK-NEXT: irdl.results(%2) +// CHECK-NEXT: } +def CMath_MulOp : CMath_Op<"mul"> { + let arguments = (ins CMath_ComplexType:$in1, CMath_ComplexType:$in2); + let results = (outs CMath_ComplexType:$out); +} + +// CHECK: irdl.operation @norm { +// CHECK-NEXT: %0 = irdl.c_pred "(true)" +// CHECK-NEXT: %1 = irdl.c_pred "(::llvm::isa($_self))" +// CHECK-NEXT: irdl.operands(%0) +// CHECK-NEXT: irdl.results(%1) +// CHECK-NEXT: } +def CMath_NormOp : CMath_Op<"norm"> { + let arguments = (ins AnyType:$in); + let results = (outs CMath_ComplexType:$out); +} diff --git a/mlir/tools/CMakeLists.txt b/mlir/tools/CMakeLists.txt --- a/mlir/tools/CMakeLists.txt +++ b/mlir/tools/CMakeLists.txt @@ -8,6 +8,7 @@ add_subdirectory(mlir-translate) add_subdirectory(mlir-vulkan-runner) add_subdirectory(tblgen-lsp-server) +add_subdirectory(tblgen-to-irdl) # mlir-cpu-runner requires ExecutionEngine. if(MLIR_ENABLE_EXECUTION_ENGINE) diff --git a/mlir/tools/tblgen-to-irdl/CMakeLists.txt b/mlir/tools/tblgen-to-irdl/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/mlir/tools/tblgen-to-irdl/CMakeLists.txt @@ -0,0 +1,20 @@ +set(LLVM_LINK_COMPONENTS + TableGen +) + +add_tablegen(tblgen-to-irdl MLIR + DESTINATION "${MLIR_TOOLS_INSTALL_DIR}" + EXPORT MLIR + tblgen-to-irdl.cpp + OpDefinitionsGen.cpp + ) + +target_link_libraries(tblgen-to-irdl + PRIVATE + MLIRIR + MLIRIRDL + MLIRTblgenLib + MLIRSupport +) + +mlir_check_all_link_libraries(tblgen-to-irdl) diff --git a/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp b/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp new file mode 100644 --- /dev/null +++ b/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp @@ -0,0 +1,145 @@ +//===- OpDefinitionsGen.cpp - IRDL op 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 +// +//===----------------------------------------------------------------------===// +// +// OpDefinitionsGen uses the description of operations to generate IRDL +// definitions for ops. +// +//===----------------------------------------------------------------------===// + +#include "mlir/Dialect/IRDL/IR/IRDL.h" +#include "mlir/IR/Attributes.h" +#include "mlir/IR/Builders.h" +#include "mlir/IR/BuiltinOps.h" +#include "mlir/IR/Diagnostics.h" +#include "mlir/IR/Dialect.h" +#include "mlir/IR/MLIRContext.h" +#include "mlir/TableGen/AttrOrTypeDef.h" +#include "mlir/TableGen/GenInfo.h" +#include "mlir/TableGen/GenNameParser.h" +#include "mlir/TableGen/Interfaces.h" +#include "mlir/TableGen/Operator.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Main.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" + +using namespace llvm; +using namespace mlir; +using tblgen::NamedTypeConstraint; + +static llvm::cl::OptionCategory dialectGenCat("Options for -gen-irdl-dialect"); +llvm::cl::opt + selectedDialect("dialect", llvm::cl::desc("The dialect to gen for"), + llvm::cl::cat(dialectGenCat), llvm::cl::Required); + +irdl::CPredOp createConstraint(OpBuilder &builder, + NamedTypeConstraint namedConstraint) { + MLIRContext *ctx = builder.getContext(); + // Build the constraint as a string. + std::string constraint = + namedConstraint.constraint.getPredicate().getCondition(); + // Build a CPredOp to match the C constraint built. + irdl::CPredOp op = builder.create( + UnknownLoc::get(ctx), StringAttr::get(ctx, constraint)); + return op; +} + +/// Returns the name of the operation without the dialect prefix. +static StringRef getOperatorName(tblgen::Operator &tblgenOp) { + StringRef opName = tblgenOp.getDef().getValueAsString("opName"); + return opName; +} + +/// Extract an operation to IRDL. +irdl::OperationOp createIRDLOperation(OpBuilder &builder, + tblgen::Operator &tblgenOp) { + MLIRContext *ctx = builder.getContext(); + StringRef opName = getOperatorName(tblgenOp); + + irdl::OperationOp op = builder.create( + UnknownLoc::get(ctx), StringAttr::get(ctx, opName)); + + // Add the block in the region. + Block &opBlock = op.getBody().emplaceBlock(); + OpBuilder consBuilder = OpBuilder::atBlockBegin(&opBlock); + + // Extract operands of the operation. + SmallVector operands; + for (const NamedTypeConstraint &namedCons : tblgenOp.getOperands()) { + assert(namedCons.isVariableLength() && + "Variable length operands not supported yet"); + auto operand = createConstraint(consBuilder, namedCons); + operands.push_back(operand); + } + + // Extract results of the operation. + SmallVector results; + for (const NamedTypeConstraint &namedCons : tblgenOp.getResults()) { + assert(namedCons.isVariableLength() && + "Variable length operands not supported yet"); + auto result = createConstraint(consBuilder, namedCons); + results.push_back(result); + } + + // Create the operands and results operations. + consBuilder.create(UnknownLoc::get(ctx), operands); + consBuilder.create(UnknownLoc::get(ctx), results); + + return op; +} + +static irdl::DialectOp createIRDLDialect(OpBuilder &builder) { + MLIRContext *ctx = builder.getContext(); + return builder.create(UnknownLoc::get(ctx), + StringAttr::get(ctx, selectedDialect)); +} + +static std::vector +getOpDefinitions(const RecordKeeper &recordKeeper) { + if (!recordKeeper.getClass("Op")) + return {}; + return recordKeeper.getAllDerivedDefinitions("Op"); +} + +static bool emitDialectIRDLDefs(const RecordKeeper &recordKeeper, + raw_ostream &os) { + // Initialize. + MLIRContext ctx; + ctx.getOrLoadDialect(); + OpBuilder builder(&ctx); + + // Create a module op and set it as the insertion point. + ModuleOp module = builder.create(UnknownLoc::get(&ctx)); + builder = builder.atBlockBegin(module.getBody()); + // Create the dialect and insert it. + irdl::DialectOp dialect = createIRDLDialect(builder); + // Set insertion point to start of DialectOp. + builder = builder.atBlockBegin(&dialect.getBody().emplaceBlock()); + + std::vector defs = getOpDefinitions(recordKeeper); + for (auto *def : defs) { + tblgen::Operator tblgenOp(def); + if (tblgenOp.getDialectName() != selectedDialect) + continue; + + createIRDLOperation(builder, tblgenOp); + } + + // Print the module. + module.print(os); + + return false; +} + +static mlir::GenRegistration + genOpDefs("gen-dialect-irdl-defs", "Generate IRDL dialect definitions", + [](const RecordKeeper &records, raw_ostream &os) { + return emitDialectIRDLDefs(records, os); + }); diff --git a/mlir/tools/tblgen-to-irdl/tblgen-to-irdl.cpp b/mlir/tools/tblgen-to-irdl/tblgen-to-irdl.cpp new file mode 100644 --- /dev/null +++ b/mlir/tools/tblgen-to-irdl/tblgen-to-irdl.cpp @@ -0,0 +1,27 @@ +//===- mlir-tblgen.cpp - Top-Level TableGen implementation for MLIR -------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains the main function for MLIR's TableGen IRDL backend. +// +//===----------------------------------------------------------------------===// + +#include "mlir/TableGen/GenInfo.h" +#include "mlir/Tools/mlir-tblgen/MlirTblgenMain.h" +#include "llvm/TableGen/Record.h" + +using namespace llvm; +using namespace mlir; + +// Generator that prints records. +GenRegistration printRecords("print-records", "Print all records to stdout", + [](const RecordKeeper &records, raw_ostream &os) { + os << records; + return false; + }); + +int main(int argc, char **argv) { return MlirTblgenMain(argc, argv); }