[Mlir-commits] [mlir] [MLIR][IRDL] Relax the restrictions on IRDL-defined names (PR #187911)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Sat Mar 21 23:10:46 PDT 2026


https://github.com/PragmaTwice updated https://github.com/llvm/llvm-project/pull/187911

>From e44547c3402d066846fca640acbe98e24f0d4f97 Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice at apache.org>
Date: Sun, 22 Mar 2026 13:54:32 +0800
Subject: [PATCH 1/2] [MLIR][IRDL] Relax the restrictions on IRDL-defined names

---
 mlir/lib/Dialect/IRDL/IR/IRDL.cpp             | 36 ++++++------
 mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp       | 57 +++++++++++++------
 mlir/test/Dialect/IRDL/invalid.irdl.mlir      | 12 ++--
 .../test/Dialect/IRDL/invalid_names.irdl.mlir | 51 +++--------------
 mlir/test/Dialect/IRDL/regions-ops.irdl.mlir  |  4 +-
 .../TestIRDLToCpp/test_irdl_to_cpp.irdl.mlir  |  7 +++
 6 files changed, 79 insertions(+), 88 deletions(-)

diff --git a/mlir/lib/Dialect/IRDL/IR/IRDL.cpp b/mlir/lib/Dialect/IRDL/IR/IRDL.cpp
index 278113fc6e966..4d1663932f736 100644
--- a/mlir/lib/Dialect/IRDL/IR/IRDL.cpp
+++ b/mlir/lib/Dialect/IRDL/IR/IRDL.cpp
@@ -77,25 +77,23 @@ static llvm::LogicalResult isValidName(llvm::StringRef in, mlir::Operation *loc,
   if (in.empty())
     return loc->emitError("name of ") << label << " is empty";
 
-  bool allowUnderscore = false;
-  for (auto &elem : in) {
-    if (elem == '_') {
-      if (!allowUnderscore)
-        return loc->emitError("name of ")
-               << label << " should not contain leading or double underscores";
-    } else {
-      if (!isalnum(elem))
-        return loc->emitError("name of ")
-               << label
-               << " must contain only lowercase letters, digits and "
-                  "underscores";
-
-      if (llvm::isUpper(elem))
-        return loc->emitError("name of ")
-               << label << " should not contain uppercase letters";
-    }
-
-    allowUnderscore = elem != '_';
+  // The syntax of a name should follow `bare-id` defined in MLIR LangRef:
+  //   bare-id ::= (letter|[_]) (letter|digit|[_$.])*
+  // For easier handling in irdl-to-cpp, we impose two extra restrictions:
+  // - the first character must be a letter;
+  // - only lowercase letters are allowed.
+
+  if (!llvm::isLower(in.front()))
+    return loc->emitError("name of ")
+           << label << " must start with a lowercase letter";
+
+  for (char c : in.drop_front()) {
+    if (!llvm::isLower(c) && !llvm::isDigit(c) && c != '_' && c != '$' &&
+        c != '.')
+      return loc->emitError("name of ")
+             << label
+             << " must contain only lowercase letters, digits, "
+                "underscores, dollar signs or dots";
   }
 
   return success();
diff --git a/mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp b/mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp
index 046c7dd0fccff..77bf78866520b 100644
--- a/mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp
+++ b/mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp
@@ -65,16 +65,43 @@ static std::string joinNameList(llvm::ArrayRef<std::string> names) {
   return nameArray;
 }
 
+// Convert a operation/type/attribute name to a valid identifier in C++.
+// The conversion is done by removing dots, underscores and dollar signs and
+// capitalizing the following character. For example, `name.with.dots` will be
+// converted to `nameWithDots` with `capitalizeFirst = false`.
+static std::string toCppName(StringRef input, bool capitalizeFirst = false) {
+  if (input.empty())
+    return "";
+
+  std::string output;
+  output.reserve(input.size());
+
+  // Push the first character, capatilizing if necessary.
+  if (capitalizeFirst && std::islower(input.front()))
+    output.push_back(llvm::toUpper(input.front()));
+  else
+    output.push_back(input.front());
+
+  // Walk the input converting any `*[._$][a-z]` snake case into `*[A-Z]`
+  // camelCase.
+  for (size_t pos = 1, e = input.size(); pos < e; ++pos) {
+    if ((input[pos] == '_' || input[pos] == '.' || input[pos] == '$') &&
+        pos != (e - 1) && std::islower(input[pos + 1]))
+      output.push_back(llvm::toUpper(input[++pos]));
+    else
+      output.push_back(input[pos]);
+  }
+  return output;
+}
+
 /// Generates the C++ type name for a TypeOp
 static std::string typeToCppName(irdl::TypeOp type) {
-  return llvm::formatv("{0}Type",
-                       convertToCamelFromSnakeCase(type.getSymName(), true));
+  return llvm::formatv("{0}Type", toCppName(type.getSymName(), true));
 }
 
 /// Generates the C++ class name for an OperationOp
 static std::string opToCppName(irdl::OperationOp op) {
-  return llvm::formatv("{0}Op",
-                       convertToCamelFromSnakeCase(op.getSymName(), true));
+  return llvm::formatv("{0}Op", toCppName(op.getSymName(), true));
 }
 
 /// Generates TypeStrings from a TypeOp
@@ -193,15 +220,13 @@ static void generateOpGetterDeclarations(irdl::detail::dictionary &dict,
   auto regionAdaptorGetters = std::string{};
 
   for (size_t i = 0, end = opStrings.opOperandNames.size(); i < end; ++i) {
-    const auto op =
-        llvm::convertToCamelFromSnakeCase(opStrings.opOperandNames[i], true);
+    const auto op = toCppName(opStrings.opOperandNames[i], true);
     opGetters += llvm::formatv("::mlir::Value get{0}() { return "
                                "getStructuredOperands({1}).front(); }\n  ",
                                op, i);
   }
   for (size_t i = 0, end = opStrings.opResultNames.size(); i < end; ++i) {
-    const auto op =
-        llvm::convertToCamelFromSnakeCase(opStrings.opResultNames[i], true);
+    const auto op = toCppName(opStrings.opResultNames[i], true);
     resGetters += llvm::formatv(
         R"(::mlir::Value get{0}() { return ::llvm::cast<::mlir::Value>(getStructuredResults({1}).front()); }
   )",
@@ -209,8 +234,7 @@ static void generateOpGetterDeclarations(irdl::detail::dictionary &dict,
   }
 
   for (size_t i = 0, end = opStrings.opRegionNames.size(); i < end; ++i) {
-    const auto op =
-        llvm::convertToCamelFromSnakeCase(opStrings.opRegionNames[i], true);
+    const auto op = toCppName(opStrings.opRegionNames[i], true);
     regionAdaptorGetters += llvm::formatv(
         R"(::mlir::Region &get{0}() { return *getRegions()[{1}]; }
   )",
@@ -235,18 +259,16 @@ static void generateOpBuilderDeclarations(irdl::detail::dictionary &dict,
   auto resultParams =
       llvm::join(llvm::map_range(opStrings.opResultNames,
                                  [](StringRef name) -> std::string {
-                                   return llvm::formatv(
-                                       "::mlir::Type {0}, ",
-                                       llvm::convertToCamelFromSnakeCase(name));
+                                   return llvm::formatv("::mlir::Type {0}, ",
+                                                        toCppName(name));
                                  }),
                  "");
 
   auto operandParams =
       llvm::join(llvm::map_range(opStrings.opOperandNames,
                                  [](StringRef name) -> std::string {
-                                   return llvm::formatv(
-                                       "::mlir::Value {0}, ",
-                                       llvm::convertToCamelFromSnakeCase(name));
+                                   return llvm::formatv("::mlir::Value {0}, ",
+                                                        toCppName(name));
                                  }),
                  "");
 
@@ -716,8 +738,7 @@ irdl::translateIRDLDialectToCpp(llvm::ArrayRef<irdl::DialectOp> dialects,
     for (auto &pathElement : llvm::reverse(namespaceAbsolutePath))
       namespaceCloseStream << "} // namespace " << pathElement << "\n";
 
-    std::string cppShortName =
-        llvm::convertToCamelFromSnakeCase(dialectName, true);
+    std::string cppShortName = toCppName(dialectName, true);
     std::string dialectBaseTypeName = llvm::formatv("{0}Type", cppShortName);
     std::string cppName = llvm::formatv("{0}Dialect", cppShortName);
 
diff --git a/mlir/test/Dialect/IRDL/invalid.irdl.mlir b/mlir/test/Dialect/IRDL/invalid.irdl.mlir
index 4ff7445c80de8..f40d2e2a98334 100644
--- a/mlir/test/Dialect/IRDL/invalid.irdl.mlir
+++ b/mlir/test/Dialect/IRDL/invalid.irdl.mlir
@@ -25,8 +25,8 @@ irdl.dialect @testd {
 irdl.dialect @testd {
   irdl.type @type {
     %0 = irdl.any
-    // expected-error at +1 {{name of parameter #0 must contain only lowercase letters, digits and underscores}}
-    irdl.parameters(test$test: %0)
+    // expected-error at +1 {{name of parameter #0 must contain only lowercase letters, digits, underscores, dollar signs or dots}}
+    irdl.parameters(testTest: %0)
   }
 }
 
@@ -35,8 +35,8 @@ irdl.dialect @testd {
 irdl.dialect @testd {
   irdl.operation @op {
     %0 = irdl.any
-    // expected-error at +1 {{name of result #0 must contain only lowercase letters, digits and underscores}}
-    irdl.results(test$test: %0)
+    // expected-error at +1 {{name of result #0 must contain only lowercase letters, digits, underscores, dollar signs or dots}}
+    irdl.results(testTest: %0)
   }
 }
 
@@ -45,8 +45,8 @@ irdl.dialect @testd {
 irdl.dialect @testd {
   irdl.operation @op {
     %0 = irdl.any
-    // expected-error at +1 {{name of operand #0 must contain only lowercase letters, digits and underscores}}
-    irdl.operands(test$test: %0)
+    // expected-error at +1 {{name of operand #0 must contain only lowercase letters, digits, underscores, dollar signs or dots}}
+    irdl.operands(testTest: %0)
   }
 }
 
diff --git a/mlir/test/Dialect/IRDL/invalid_names.irdl.mlir b/mlir/test/Dialect/IRDL/invalid_names.irdl.mlir
index 20729e836866b..5dac7c42f1309 100644
--- a/mlir/test/Dialect/IRDL/invalid_names.irdl.mlir
+++ b/mlir/test/Dialect/IRDL/invalid_names.irdl.mlir
@@ -1,30 +1,18 @@
 // RUN: mlir-irdl-to-cpp %s --verify-diagnostics --split-input-file
-// expected-error at +1 {{name of dialect should not contain leading or double underscores}}
+// expected-error at +1 {{name of dialect must start with a lowercase letter}}
 irdl.dialect @_no_leading_underscore {
 }
 
 // -----
 
-// expected-error at +1 {{name of dialect should not contain leading or double underscores}}
-irdl.dialect @no__double__underscores {
-}
-
-// -----
-
-// expected-error at +1 {{name of dialect should not contain uppercase letters}}
+// expected-error at +1 {{name of dialect must start with a lowercase letter}}
 irdl.dialect @NoUpperCase {
 }
 
 // -----
 
-// expected-error at +1 {{name of dialect must contain only lowercase letters, digits and underscores}}
-irdl.dialect @no_weird_symbol$ {
-}
-
-// -----
-
 irdl.dialect @test_dialect {
-  // expected-error at +1 {{name of operation should not contain leading or double underscores}}
+  // expected-error at +1 {{name of operation must start with a lowercase letter}}
   irdl.operation @_no_leading_underscore {
     %0 = irdl.any
     irdl.results(res: %0)
@@ -34,17 +22,14 @@ irdl.dialect @test_dialect {
 // -----
 
 irdl.dialect @test_dialect {
-  // expected-error at +1 {{name of operation should not contain leading or double underscores}}
-  irdl.operation @no__double__underscores {
-    %0 = irdl.any
-    irdl.results(res: %0)
-  }
+  // expected-error at +1 {{name of operation must contain only lowercase letters, digits, underscores, dollar signs or dots}}
+  irdl.operation @noUpperCase {}
 }
 
 // -----
 
 irdl.dialect @test_dialect {
-    // expected-error at +1 {{name of operation should not contain uppercase letters}}
+    // expected-error at +1 {{name of operation must start with a lowercase letter}}
     irdl.operation @NoUpperCase {
         %0 = irdl.any
         irdl.results(res: %0)
@@ -53,20 +38,10 @@ irdl.dialect @test_dialect {
 
 // -----
 
-irdl.dialect @test_dialect {
-  // expected-error at +1 {{name of operation must contain only lowercase letters, digits and underscores}}
-  irdl.operation @no_weird_symbol$ {
-    %0 = irdl.any
-    irdl.results(res: %0)
-  }
-}
-
-// -----
-
 irdl.dialect @test_dialect {
   irdl.operation @test_op {
     %0 = irdl.any
-    // expected-error at +1 {{name of result #0 should not contain leading or double underscores}}
+    // expected-error at +1 {{name of result #0 must start with a lowercase letter}}
     irdl.results(_no_leading_underscore: %0)
   }
 }
@@ -76,17 +51,7 @@ irdl.dialect @test_dialect {
 irdl.dialect @test_dialect {
   irdl.operation @test_op {
     %0 = irdl.any
-    // expected-error at +1 {{name of result #0 should not contain leading or double underscores}}
-    irdl.results(no__double__underscores: %0)
-  }
-}
-
-// -----
-
-irdl.dialect @test_dialect {
-  irdl.operation @test_op {
-    %0 = irdl.any
-    // expected-error at +1 {{name of result #0 should not contain uppercase letters}}
+    // expected-error at +1 {{name of result #0 must start with a lowercase letter}}
     irdl.results(NoUpperCase: %0)
   }
 }
diff --git a/mlir/test/Dialect/IRDL/regions-ops.irdl.mlir b/mlir/test/Dialect/IRDL/regions-ops.irdl.mlir
index e5f884c99e5f4..d61f76cb1befb 100644
--- a/mlir/test/Dialect/IRDL/regions-ops.irdl.mlir
+++ b/mlir/test/Dialect/IRDL/regions-ops.irdl.mlir
@@ -22,8 +22,8 @@ irdl.dialect @test_regions_op_missing_name {
 irdl.dialect @test_regions_op_wrong_name {
     irdl.operation @op {
         %r1 = irdl.region
-        // expected-error @below {{name of region #0 must contain only lowercase letters, digits and underscores}}
-        irdl.regions(test$test: %r1)
+        // expected-error @below {{name of region #0 must contain only lowercase letters, digits, underscores, dollar signs or dots}}
+        irdl.regions(testTest: %r1)
     }
 }
 
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..5c2f700d56fd0 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
@@ -11,6 +11,13 @@ irdl.dialect @test_irdl_to_cpp {
     // CHECK: class FooType
     irdl.type @foo
 
+    // CHECK: class NameWithDotsType
+    irdl.type @name.with.dots
+    // CHECK: class NameWithDollarsType
+    irdl.type @name$with$dollars
+    // CHECK: class NameWithUnderscoresType
+    irdl.type @name_with_underscores
+
     // CHECK: class BarOp
     // CHECK: ::mlir::Value getRes()
     irdl.operation @bar {

>From a95239e646b419550c3fcd942d3c952ea1900d7f Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice at apache.org>
Date: Sun, 22 Mar 2026 14:10:34 +0800
Subject: [PATCH 2/2] fix comment

---
 mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp b/mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp
index 77bf78866520b..5f089de3abf05 100644
--- a/mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp
+++ b/mlir/lib/Target/IRDLToCpp/IRDLToCpp.cpp
@@ -65,7 +65,7 @@ static std::string joinNameList(llvm::ArrayRef<std::string> names) {
   return nameArray;
 }
 
-// Convert a operation/type/attribute name to a valid identifier in C++.
+// Convert a dialect/operation/type/attribute name to a valid identifier in C++.
 // The conversion is done by removing dots, underscores and dollar signs and
 // capitalizing the following character. For example, `name.with.dots` will be
 // converted to `nameWithDots` with `capitalizeFirst = false`.



More information about the Mlir-commits mailing list