[Mlir-commits] [mlir] [MLIR][IRDL] Instantiate "." in IRDL-defined names as nested namespaces (PR #207035)

Ivan Ho llvmlistbot at llvm.org
Thu Jul 2 09:41:27 PDT 2026


https://github.com/hhkit updated https://github.com/llvm/llvm-project/pull/207035

>From 01d8081c6fd6155074c7874733fb703931fbcad0 Mon Sep 17 00:00:00 2001
From: Ivan Ho <38537881+hhkit at users.noreply.github.com>
Date: Wed, 1 Jul 2026 18:02:15 +0100
Subject: [PATCH 1/2] unit tests for the changes we want to make

---
 .../TestIRDLToCpp/test_irdl_to_cpp.irdl.mlir  | 44 +++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/mlir/test/lib/Dialect/TestIRDLToCpp/test_irdl_to_cpp.irdl.mlir b/mlir/test/lib/Dialect/TestIRDLToCpp/test_irdl_to_cpp.irdl.mlir
index 770cd36cdee33..2a37cfaa3557c 100644
--- a/mlir/test/lib/Dialect/TestIRDLToCpp/test_irdl_to_cpp.irdl.mlir
+++ b/mlir/test/lib/Dialect/TestIRDLToCpp/test_irdl_to_cpp.irdl.mlir
@@ -18,6 +18,32 @@ irdl.dialect @test_irdl_to_cpp {
         irdl.results(res: %0)
     }
 
+    // CHECK: // ::mlir::test_irdl_to_cpp::nested::NamespacedOp declarations
+    // CHECK: namespace nested {
+    // CHECK: class NamespacedOp : public ::mlir::Op<NamespacedOp
+    // CHECK: static constexpr ::llvm::StringLiteral getOperationName()
+    // CHECK-NEXT: return ::llvm::StringLiteral("test_irdl_to_cpp.nested.namespaced");
+    // CHECK: } // namespace nested
+    // CHECK: MLIR_DECLARE_EXPLICIT_TYPE_ID(::mlir::test_irdl_to_cpp::nested::NamespacedOp)
+    irdl.operation @nested.namespaced {
+        %0 = irdl.any
+        irdl.results(res: %0)
+    }
+
+    // CHECK: // ::mlir::test_irdl_to_cpp::nested::namespaced::MoreOp declarations
+    // CHECK: namespace nested {
+    // CHECK: namespace namespaced {
+    // CHECK: class MoreOp : public ::mlir::Op<MoreOp
+    // CHECK: static constexpr ::llvm::StringLiteral getOperationName()
+    // CHECK-NEXT: return ::llvm::StringLiteral("test_irdl_to_cpp.nested.namespaced.more");
+    // CHECK: } // namespace namespaced
+    // CHECK: } // namespace nested
+    // CHECK: MLIR_DECLARE_EXPLICIT_TYPE_ID(::mlir::test_irdl_to_cpp::nested::namespaced::MoreOp)
+    irdl.operation @nested.namespaced.more {
+        %0 = irdl.any
+        irdl.results(res: %0)
+    }
+
     // CHECK: class BeefOp
     // CHECK: ::mlir::Value getLhs()
     // CHECK: ::mlir::Value getRhs()
@@ -49,6 +75,20 @@ irdl.dialect @test_irdl_to_cpp {
     // CHECK:  ::mlir::Region &getThen() { return (*this)->getRegion(1); }
     // CHECK:  ::mlir::Region &getElse() { return (*this)->getRegion(2); }
 
+    // CHECK: // ::mlir::test_irdl_to_cpp::nested::NamespacedOp definitions
+    // CHECK: namespace nested {
+    // CHECK: NamespacedOp::build
+    // CHECK: } // namespace nested
+    // CHECK: MLIR_DEFINE_EXPLICIT_TYPE_ID(::mlir::test_irdl_to_cpp::nested::NamespacedOp)
+
+    // CHECK: // ::mlir::test_irdl_to_cpp::nested::namespaced::MoreOp definitions
+    // CHECK: namespace nested {
+    // CHECK: namespace namespaced {
+    // CHECK: MoreOp::build
+    // CHECK: } // namespace namespaced
+    // CHECK: } // namespace nested
+    // CHECK: MLIR_DEFINE_EXPLICIT_TYPE_ID(::mlir::test_irdl_to_cpp::nested::namespaced::MoreOp)
+
     // CHECK: ConditionalOp definitions
     // CHECK: __mlir_irdl_local_region_constraint_ConditionalOp_cond
     // CHECK: if (!(region.getNumArguments() == 1)) {
@@ -73,6 +113,10 @@ irdl.dialect @test_irdl_to_cpp {
     // CHECK: __mlir_irdl_local_region_constraint_ConditionalOp_else
     // CHECK: failure
     // CHECK: success
+
+    // CHECK: void TestIrdlToCppDialect::initialize()
+    // CHECK: ::mlir::test_irdl_to_cpp::nested::NamespacedOp
+    // CHECK: ::mlir::test_irdl_to_cpp::nested::namespaced::MoreOp
     irdl.operation @conditional {
         %r0 = irdl.region      // Unconstrained region
         %r1 = irdl.region()    // Region with no entry block arguments

>From f78a519928fc14d49c4daa42dd93c995a0cc54d7 Mon Sep 17 00:00:00 2001
From: Ivan Ho <38537881+hhkit at users.noreply.github.com>
Date: Thu, 2 Jul 2026 17:41:13 +0100
Subject: [PATCH 2/2] fix that works but i don't like it

---
 mlir/lib/Dialect/IRDL/IR/IRDL.cpp       |  9 ++++
 mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp | 61 +++++++++++++++++++------
 2 files changed, 57 insertions(+), 13 deletions(-)

diff --git a/mlir/lib/Dialect/IRDL/IR/IRDL.cpp b/mlir/lib/Dialect/IRDL/IR/IRDL.cpp
index 278113fc6e966..b1005b01af86c 100644
--- a/mlir/lib/Dialect/IRDL/IR/IRDL.cpp
+++ b/mlir/lib/Dialect/IRDL/IR/IRDL.cpp
@@ -78,12 +78,19 @@ static llvm::LogicalResult isValidName(llvm::StringRef in, mlir::Operation *loc,
     return loc->emitError("name of ") << label << " is empty";
 
   bool allowUnderscore = false;
+  auto prev = '\0';
   for (auto &elem : in) {
     if (elem == '_') {
       if (!allowUnderscore)
         return loc->emitError("name of ")
                << label << " should not contain leading or double underscores";
     } else {
+      if (elem == '.') {
+        if (prev == '.')
+          return loc->emitError("empty namespace not allowed");
+      }
+      else
+      {
       if (!isalnum(elem))
         return loc->emitError("name of ")
                << label
@@ -93,9 +100,11 @@ static llvm::LogicalResult isValidName(llvm::StringRef in, mlir::Operation *loc,
       if (llvm::isUpper(elem))
         return loc->emitError("name of ")
                << label << " should not contain uppercase letters";
+      }
     }
 
     allowUnderscore = elem != '_';
+    prev = elem;
   }
 
   return success();
diff --git a/mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp b/mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp
index 046c7dd0fccff..e8773937fc313 100644
--- a/mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp
+++ b/mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp
@@ -13,6 +13,7 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/TypeSwitch.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/raw_ostream.h"
@@ -52,6 +53,8 @@ struct TypeStrings {
 struct OpStrings {
   StringRef opName;
   std::string opCppName;
+  std::string opScopedCppName;
+  SmallVector<std::string> opNameSpaces;
   SmallVector<std::string> opResultNames;
   SmallVector<std::string> opOperandNames;
   SmallVector<std::string> opRegionNames;
@@ -73,8 +76,19 @@ static std::string typeToCppName(irdl::TypeOp type) {
 
 /// Generates the C++ class name for an OperationOp
 static std::string opToCppName(irdl::OperationOp op) {
+  const auto opName = op.getSymName();
+  const auto periodIndex = opName.find_last_of(".");
+  const auto nameSubstr = periodIndex == std::string::npos ? opName : opName.substr(periodIndex + 1);
   return llvm::formatv("{0}Op",
-                       convertToCamelFromSnakeCase(op.getSymName(), true));
+                       convertToCamelFromSnakeCase(nameSubstr, true));
+}
+
+// Generates the C++ class name for an OperationOp, scoped to the namespace
+static std::string opToScopedCppName(irdl::OperationOp op) {
+  auto names = llvm::SmallVector<std::string>(llvm::split(op.getSymName(), "."));
+  names.pop_back();
+  names.push_back(opToCppName(op));
+  return llvm::join(names, "::");
 }
 
 /// Generates TypeStrings from a TypeOp
@@ -92,8 +106,12 @@ static OpStrings getStrings(irdl::OperationOp op) {
   auto regionsOp = op.getOp<irdl::RegionsOp>();
 
   OpStrings strings;
+  auto opNameParts = SmallVector<StringRef>(llvm::split(op.getSymName(), "."));
   strings.opName = op.getSymName();
+  opNameParts.pop_back();
+  strings.opNameSpaces = llvm::map_to_vector(opNameParts, &StringRef::str);
   strings.opCppName = opToCppName(op);
+  strings.opScopedCppName = opToScopedCppName(op);
 
   if (operandOp) {
     strings.opOperandNames = SmallVector<std::string>(
@@ -134,6 +152,7 @@ static void fillDict(irdl::detail::dictionary &dict, const OpStrings &strings) {
 
   dict["OP_NAME"] = strings.opName;
   dict["OP_CPP_NAME"] = strings.opCppName;
+  dict["OP_SCOPED_CPP_NAME"] = strings.opScopedCppName;
   dict["OP_OPERAND_COUNT"] = std::to_string(strings.opOperandNames.size());
   dict["OP_RESULT_COUNT"] = std::to_string(strings.opResultNames.size());
   dict["OP_OPERAND_INITIALIZER_LIST"] =
@@ -141,6 +160,20 @@ static void fillDict(irdl::detail::dictionary &dict, const OpStrings &strings) {
   dict["OP_RESULT_INITIALIZER_LIST"] =
       resultCount ? joinNameList(strings.opResultNames) : "{\"\"}";
   dict["OP_REGION_COUNT"] = std::to_string(regionCount);
+  dict["NAMESPACE_OPEN"] = (dict["NAMESPACE_OPEN"] + llvm::join(llvm::map_range(strings.opNameSpaces, [](llvm::StringRef ref) -> std::string {
+    return llvm::formatv("namespace {0} {{", ref);
+  }), "\n")).str();
+  dict["NAMESPACE_PATH"] =
+      (dict["NAMESPACE_PATH"] +
+       llvm::join(llvm::map_range(strings.opNameSpaces,
+                                  [](llvm::StringRef ref) -> std::string {
+                                    return llvm::formatv("::{0}", ref);
+                                  }),
+                  ""))
+          .str();
+  dict["NAMESPACE_CLOSE"] = (llvm::join(llvm::map_range(llvm::reverse(strings.opNameSpaces), [](llvm::StringRef ref) -> std::string {
+    return llvm::formatv("} // namespace {0}\n", ref);
+  }), "") + dict["NAMESPACE_CLOSE"]).str();
 }
 
 /// Fills a dictionary with values from DialectStrings
@@ -166,7 +199,7 @@ static LogicalResult generateTypedefList(irdl::DialectOp &dialect,
 static LogicalResult generateOpList(irdl::DialectOp &dialect,
                                     SmallVector<std::string> &opNames) {
   auto operationOps = dialect.getOps<irdl::OperationOp>();
-  auto range = llvm::map_range(operationOps, opToCppName);
+  auto range = llvm::map_range(operationOps, opToScopedCppName);
   opNames = SmallVector<std::string>(range);
   return success();
 }
@@ -283,24 +316,25 @@ static SmallVector<std::string> generateTraits(irdl::OperationOp op,
 
 static LogicalResult generateOperationInclude(irdl::OperationOp op,
                                               raw_ostream &output,
-                                              irdl::detail::dictionary &dict) {
+                                              const irdl::detail::dictionary &dict) {
   static const auto perOpDeclTemplate = irdl::detail::Template(
 #include "Templates/PerOperationDecl.txt"
   );
   const auto opStrings = getStrings(op);
-  fillDict(dict, opStrings);
+  auto opDict = dict;
+  fillDict(opDict, opStrings);
 
   SmallVector<std::string> traitNames = generateTraits(op, opStrings);
   if (traitNames.empty())
-    dict["OP_TEMPLATE_ARGS"] = opStrings.opCppName;
+    opDict["OP_TEMPLATE_ARGS"] = opStrings.opCppName;
   else
-    dict["OP_TEMPLATE_ARGS"] = llvm::formatv("{0}, {1}", opStrings.opCppName,
+    opDict["OP_TEMPLATE_ARGS"] = llvm::formatv("{0}, {1}", opStrings.opCppName,
                                              llvm::join(traitNames, ", "));
 
-  generateOpGetterDeclarations(dict, opStrings);
-  generateOpBuilderDeclarations(dict, opStrings);
+  generateOpGetterDeclarations(opDict, opStrings);
+  generateOpBuilderDeclarations(opDict, opStrings);
 
-  perOpDeclTemplate.render(output, dict);
+  perOpDeclTemplate.render(output, opDict);
   return success();
 }
 
@@ -462,7 +496,8 @@ static std::string generateOpDefinition(irdl::detail::dictionary &dict,
   };
 
   auto opStrings = getStrings(op);
-  fillDict(dict, opStrings);
+  auto opDict = dict;
+  fillDict(opDict, opStrings);
 
   auto resultTypes = llvm::join(
       llvm::map_range(opStrings.opResultNames,
@@ -516,13 +551,13 @@ void {0}::build(::mlir::OpBuilder &opBuilder, ::mlir::OperationState &opState, {
       llvm::join(opStrings.opOperandNames, ",") +
           (!opStrings.opOperandNames.empty() ? "," : ""));
 
-  dict["OP_BUILD_DEFS"] = buildDefinition;
+  opDict["OP_BUILD_DEFS"] = buildDefinition;
 
-  generateVerifiers(dict, op, opStrings);
+  generateVerifiers(opDict, op, opStrings);
 
   std::string str;
   llvm::raw_string_ostream stream{str};
-  perOpDefTemplate.render(stream, dict);
+  perOpDefTemplate.render(stream, opDict);
   return str;
 }
 



More information about the Mlir-commits mailing list