[Mlir-commits] [mlir] Reland [mlir][tools] Introduce tblgen-to-irdl tool (PR #70121)

Kunwar Grover llvmlistbot at llvm.org
Fri Oct 27 02:18:35 PDT 2023


https://github.com/Groverkss updated https://github.com/llvm/llvm-project/pull/70121

>From ec44f7452c612e30b74bdae8f398dbb979d4ebd1 Mon Sep 17 00:00:00 2001
From: Groverkss <groverkss at gmail.com>
Date: Mon, 24 Jul 2023 01:18:32 +0530
Subject: [PATCH 1/5] Add tblgen-to-irdl tool

---
 mlir/test/CMakeLists.txt                      |   1 +
 mlir/test/tblgen-to-irdl/CMathDialect.td      |  56 +++++++
 mlir/tools/CMakeLists.txt                     |   1 +
 mlir/tools/tblgen-to-irdl/CMakeLists.txt      |  20 +++
 .../tools/tblgen-to-irdl/OpDefinitionsGen.cpp | 141 ++++++++++++++++++
 mlir/tools/tblgen-to-irdl/tblgen-to-irdl.cpp  |  27 ++++
 6 files changed, 246 insertions(+)
 create mode 100644 mlir/test/tblgen-to-irdl/CMathDialect.td
 create mode 100644 mlir/tools/tblgen-to-irdl/CMakeLists.txt
 create mode 100644 mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp
 create mode 100644 mlir/tools/tblgen-to-irdl/tblgen-to-irdl.cpp

diff --git a/mlir/test/CMakeLists.txt b/mlir/test/CMakeLists.txt
index bf143d036c2f66f..04bfa1ade655e04 100644
--- a/mlir/test/CMakeLists.txt
+++ b/mlir/test/CMakeLists.txt
@@ -108,6 +108,7 @@ set(MLIR_TEST_DEPENDS
   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
index 000000000000000..57ae8afbba5eeb3
--- /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<string name, string typeMnemonic, list<Trait> traits = []>
+: TypeDef<CMath_Dialect, name, traits> {
+  let mnemonic = typeMnemonic;
+}
+
+class CMath_Op<string mnemonic, list<Trait> traits = []>
+    : Op<CMath_Dialect, mnemonic, traits>;
+
+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<cmath::ComplexTypeType>($_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<cmath::ComplexTypeType>($_self))" 
+// CHECK-NEXT:   %1 = irdl.c_pred "(::llvm::isa<cmath::ComplexTypeType>($_self))" 
+// CHECK-NEXT:   %2 = irdl.c_pred "(::llvm::isa<cmath::ComplexTypeType>($_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<cmath::ComplexTypeType>($_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
index e9a1e4d6251722e..895a103061d3052 100644
--- a/mlir/tools/CMakeLists.txt
+++ b/mlir/tools/CMakeLists.txt
@@ -8,6 +8,7 @@ add_subdirectory(mlir-spirv-cpu-runner)
 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
index 000000000000000..a6621cb98ac6bdc
--- /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
index 000000000000000..af342947bb28eae
--- /dev/null
+++ b/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp
@@ -0,0 +1,141 @@
+//===- 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<std::string>
+    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<irdl::CPredOp>(
+      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<irdl::OperationOp>(
+      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<Value> operands;
+  for (const NamedTypeConstraint &namedCons : tblgenOp.getOperands()) {
+    auto operand = createConstraint(consBuilder, namedCons);
+    operands.push_back(operand);
+  }
+
+  // Extract results of the operation.
+  SmallVector<Value> results;
+  for (const NamedTypeConstraint &namedCons : tblgenOp.getResults()) {
+    auto result = createConstraint(consBuilder, namedCons);
+    results.push_back(result);
+  }
+
+  // Create the operands and results operations.
+  consBuilder.create<irdl::OperandsOp>(UnknownLoc::get(ctx), operands);
+  consBuilder.create<irdl::ResultsOp>(UnknownLoc::get(ctx), results);
+
+  return op;
+}
+
+static irdl::DialectOp createIRDLDialect(OpBuilder &builder) {
+  MLIRContext *ctx = builder.getContext();
+  return builder.create<irdl::DialectOp>(UnknownLoc::get(ctx),
+                                         StringAttr::get(ctx, selectedDialect));
+}
+
+static std::vector<llvm::Record *>
+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<irdl::IRDLDialect>();
+  OpBuilder builder(&ctx);
+
+  // Create a module op and set it as the insertion point.
+  ModuleOp module = builder.create<ModuleOp>(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<Record *> 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
index 000000000000000..092ec2ebe81a682
--- /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); }

>From 29ed2c50ed4292420aec1614e764ae646acd0fd2 Mon Sep 17 00:00:00 2001
From: Groverkss <groverkss at gmail.com>
Date: Thu, 27 Jul 2023 23:08:43 +0530
Subject: [PATCH 2/5] [mlir][tools] Introduce tblgen-to-irdl tool

This patch adds a new tool, tblgen-to-irdl, which is an IRDL backend to MLIR
ODS.

Currently, the tool only covers operation and dialect definitions and
generates verifiers constraints as "irdl::CPred", which is the constraint as a
C++ string. The tool currently does not support
traits/interfaces/regions/variadics as they are not added in IRDL yet, so the
generated definitions would not be correct for operations using them. Support
for these things will be added as they are implemented in IRDL.

This tool acts as a bridge to convert TableGen-defined dialects into IRDL
definitions, making operation definitions more easily introspectable. This
introspectablility allows for tools like fuzzers, mutators, and reducers to
work on ODS definitions as a MLIR dialect instead of trying to navigate through
TableGen.

Differential Revision: https://reviews.llvm.org/D156469
---
 mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp b/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp
index af342947bb28eae..5f899ee242c04fe 100644
--- a/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp
+++ b/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp
@@ -73,6 +73,8 @@ irdl::OperationOp createIRDLOperation(OpBuilder &builder,
   // Extract operands of the operation.
   SmallVector<Value> 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);
   }
@@ -80,6 +82,8 @@ irdl::OperationOp createIRDLOperation(OpBuilder &builder,
   // Extract results of the operation.
   SmallVector<Value> 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);
   }

>From 46d317edf479ca33976c5299fe1a10bac968761a Mon Sep 17 00:00:00 2001
From: Groverkss <groverkss at gmail.com>
Date: Thu, 14 Sep 2023 19:45:53 +0530
Subject: [PATCH 3/5] Rebase and account for variadicity

---
 .../tools/tblgen-to-irdl/OpDefinitionsGen.cpp | 48 +++++++++++--------
 1 file changed, 29 insertions(+), 19 deletions(-)

diff --git a/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp b/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp
index 5f899ee242c04fe..2323127d7afd63e 100644
--- a/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp
+++ b/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp
@@ -70,27 +70,37 @@ irdl::OperationOp createIRDLOperation(OpBuilder &builder,
   Block &opBlock = op.getBody().emplaceBlock();
   OpBuilder consBuilder = OpBuilder::atBlockBegin(&opBlock);
 
-  // Extract operands of the operation.
-  SmallVector<Value> 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<Value> 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);
-  }
+  auto getValues = [&](tblgen::Operator::const_value_range namedCons) {
+    SmallVector<Value> operands;
+    SmallVector<irdl::VariadicityAttr> 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::VariadicityAttr>(
+            irdl::Variadicity::optional);
+      else if (namedCons.isVariadic())
+        var = consBuilder.getAttr<irdl::VariadicityAttr>(
+            irdl::Variadicity::variadic);
+      else
+        var = consBuilder.getAttr<irdl::VariadicityAttr>(
+            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<irdl::OperandsOp>(UnknownLoc::get(ctx), operands);
-  consBuilder.create<irdl::ResultsOp>(UnknownLoc::get(ctx), results);
+  consBuilder.create<irdl::OperandsOp>(UnknownLoc::get(ctx), operands,
+                                       operandVariadicity);
+  consBuilder.create<irdl::ResultsOp>(UnknownLoc::get(ctx), results,
+                                      resultVariadicity);
 
   return op;
 }

>From a5e2152fc8f5ab142e76a1b25be09d1485f9abfd Mon Sep 17 00:00:00 2001
From: Kunwar Grover <groverkss at gmail.com>
Date: Wed, 25 Oct 2023 02:08:40 +0530
Subject: [PATCH 4/5] Fix moduleop not deallocated

---
 mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp b/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp
index 2323127d7afd63e..9b732aadfc02440 100644
--- a/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp
+++ b/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp
@@ -126,8 +126,8 @@ static bool emitDialectIRDLDefs(const RecordKeeper &recordKeeper,
   OpBuilder builder(&ctx);
 
   // Create a module op and set it as the insertion point.
-  ModuleOp module = builder.create<ModuleOp>(UnknownLoc::get(&ctx));
-  builder = builder.atBlockBegin(module.getBody());
+  OwningOpRef<ModuleOp> module = builder.create<ModuleOp>(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.
@@ -143,7 +143,7 @@ static bool emitDialectIRDLDefs(const RecordKeeper &recordKeeper,
   }
 
   // Print the module.
-  module.print(os);
+  module->print(os);
 
   return false;
 }

>From 72c889876b6007914825ea0a303ac58134b765b4 Mon Sep 17 00:00:00 2001
From: Kunwar Grover <groverkss at gmail.com>
Date: Fri, 27 Oct 2023 14:47:39 +0530
Subject: [PATCH 5/5] clang-format

---
 mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp b/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp
index 9b732aadfc02440..ba5bf4d9d4abbc8 100644
--- a/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp
+++ b/mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp
@@ -126,7 +126,8 @@ static bool emitDialectIRDLDefs(const RecordKeeper &recordKeeper,
   OpBuilder builder(&ctx);
 
   // Create a module op and set it as the insertion point.
-  OwningOpRef<ModuleOp> module = builder.create<ModuleOp>(UnknownLoc::get(&ctx));
+  OwningOpRef<ModuleOp> module =
+      builder.create<ModuleOp>(UnknownLoc::get(&ctx));
   builder = builder.atBlockBegin(module->getBody());
   // Create the dialect and insert it.
   irdl::DialectOp dialect = createIRDLDialect(builder);



More information about the Mlir-commits mailing list