//===- 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); auto getValues = [&](tblgen::Operator::const_value_range namedCons) { SmallVector operands; SmallVector variadicity; for (const NamedTypeConstraint &namedCons : namedCons) { auto operand = createConstraint(consBuilder, namedCons); operands.push_back(operand); irdl::VariadicityAttr var; if (namedCons.isOptional()) var = consBuilder.getAttr( irdl::Variadicity::optional); else if (namedCons.isVariadic()) var = consBuilder.getAttr( irdl::Variadicity::variadic); else var = consBuilder.getAttr( irdl::Variadicity::single); variadicity.push_back(var); } return std::make_tuple(operands, variadicity); }; auto [operands, operandVariadicity] = getValues(tblgenOp.getOperands()); auto [results, resultVariadicity] = getValues(tblgenOp.getResults()); // Create the operands and results operations. consBuilder.create(UnknownLoc::get(ctx), operands, operandVariadicity); consBuilder.create(UnknownLoc::get(ctx), results, resultVariadicity); 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. OwningOpRef 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); });