Skip to content

[mlir][irdl] Introduce names in IRDL value lists #123525

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 19, 2025

Conversation

Moxinilian
Copy link
Member

In order to meaningfully generate getters and setters from IRDL, it makes sense to embed the names of operands, results, etc. in the IR definition. This PR introduces this feature. Names are constrained similarly to TableGen names.

@llvmbot llvmbot added the mlir:core MLIR Core Infrastructure label Jan 19, 2025
@llvmbot
Copy link
Member

llvmbot commented Jan 19, 2025

@llvm/pr-subscribers-mlir-core
@llvm/pr-subscribers-mlir-irdl

@llvm/pr-subscribers-mlir

Author: Théo Degioanni (Moxinilian)

Changes

In order to meaningfully generate getters and setters from IRDL, it makes sense to embed the names of operands, results, etc. in the IR definition. This PR introduces this feature. Names are constrained similarly to TableGen names.


Patch is 53.73 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/123525.diff

16 Files Affected:

  • (modified) mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td (+45-35)
  • (modified) mlir/lib/Dialect/IRDL/IR/IRDL.cpp (+169-33)
  • (modified) mlir/test/CAPI/irdl.c (+2-2)
  • (modified) mlir/test/Dialect/IRDL/cmath.irdl.mlir (+10-10)
  • (modified) mlir/test/Dialect/IRDL/cpred.irdl.mlir (+2-2)
  • (modified) mlir/test/Dialect/IRDL/cyclic-types.irdl.mlir (+6-6)
  • (modified) mlir/test/Dialect/IRDL/invalid.irdl.mlir (+120-5)
  • (modified) mlir/test/Dialect/IRDL/regions-ops.irdl.mlir (+31-1)
  • (modified) mlir/test/Dialect/IRDL/test-type.irdl.mlir (+4-4)
  • (modified) mlir/test/Dialect/IRDL/testd.irdl.mlir (+28-28)
  • (modified) mlir/test/Dialect/IRDL/variadics-error.irdl.mlir (+6-6)
  • (modified) mlir/test/Dialect/IRDL/variadics.irdl.mlir (+16-16)
  • (modified) mlir/test/Dialect/Transform/irdl.mlir (+1-1)
  • (modified) mlir/test/tblgen-to-irdl/CMathDialect.td (+5-5)
  • (modified) mlir/test/tblgen-to-irdl/TestDialect.td (+28-7)
  • (modified) mlir/tools/tblgen-to-irdl/OpDefinitionsGen.cpp (+41-4)
diff --git a/mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td b/mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td
index c7fcb55120c827..54d25099a68e2f 100644
--- a/mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td
+++ b/mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td
@@ -20,6 +20,7 @@ include "IRDLInterfaces.td"
 include "mlir/Interfaces/SideEffectInterfaces.td"
 include "mlir/Interfaces/InferTypeOpInterface.td"
 include "mlir/IR/SymbolInterfaces.td"
+include "mlir/IR/BuiltinAttributes.td"
 
 class IRDL_Op<string mnemonic, list<Trait> traits = []>
     : Op<IRDL_Dialect, mnemonic, traits>;
@@ -133,7 +134,7 @@ def IRDL_ParametersOp : IRDL_Op<"parameters",
     "Define the constraints on parameters of a type/attribute definition";
   let description = [{
     `irdl.parameters` defines the constraints on parameters of a type or
-    attribute definition.
+    attribute definition. Each parameter is named after an identifier.
 
     Example:
 
@@ -143,17 +144,19 @@ def IRDL_ParametersOp : IRDL_Op<"parameters",
         %0 = irdl.is i32
         %1 = irdl.is i64
         %2 = irdl.any_of(%0, %1)
-        irdl.parameters(%2)
+        irdl.parameters(elem: %2)
       }
     }
     ```
 
     The above program defines a type `complex` inside the dialect `cmath`. The
-    type has a single parameter that should be either `i32` or `i64`.
+    type has a single parameter `elem` that should be either `i32` or `i64`.
   }];
 
-  let arguments = (ins Variadic<IRDL_AttributeType>:$args);
-  let assemblyFormat = " `(` $args `)` attr-dict ";
+  let arguments = (ins Variadic<IRDL_AttributeType>:$args,
+                        StrArrayAttr:$names);
+  let assemblyFormat = " `` custom<NamedValueList>($args, $names) attr-dict ";
+  let hasVerifier = true;
 }
 
 //===----------------------------------------------------------------------===//
@@ -198,16 +201,17 @@ def IRDL_OperationOp : IRDL_Op<"operation",
   let regions = (region SizedRegion<1>:$body);
   let assemblyFormat =
     "$sym_name attr-dict-with-keyword custom<SingleBlockRegion>($body)";
+  let hasRegionVerifier = true;
 }
 
 def IRDL_OperandsOp : IRDL_Op<"operands", [HasParent<"OperationOp">]> {
   let summary = "Define the operands of an operation";
   let description = [{
     `irdl.operands` define the operands of the `irdl.operation` parent operation
-    definition.
+    definition. Each operand is named after an identifier.
 
     In the following example, `irdl.operands` defines the operands of the
-    `norm` operation:
+    `mul` operation:
 
     ```mlir
     irdl.dialect @cmath {
@@ -217,8 +221,8 @@ def IRDL_OperandsOp : IRDL_Op<"operands", [HasParent<"OperationOp">]> {
       irdl.operation @mul {
         %0 = irdl.any
         %1 = irdl.parametric @cmath::@complex<%0>
-        irdl.results(%1)
-        irdl.operands(%1, %1)
+        irdl.results(res: %1)
+        irdl.operands(lhs: %1, rhs: %1)
       }
     }
     ```
@@ -228,11 +232,11 @@ def IRDL_OperandsOp : IRDL_Op<"operands", [HasParent<"OperationOp">]> {
 
     The operands can also be marked as variadic or optional:
     ```mlir
-    irdl.operands(%0, single %1, optional %2, variadic %3)
+    irdl.operands(foo: %0, bar: single %1, baz: optional %2, qux: variadic %3)
     ```
 
-    Here, %0 and %1 are required single operands, %2 is an optional operand,
-    and %3 is a variadic operand.
+    Here, foo and bar are required single operands, baz is an optional operand,
+    and qux is a variadic operand.
 
     When more than one operand is marked as optional or variadic, the operation
     will expect a 'operandSegmentSizes' attribute that defines the number of
@@ -240,9 +244,10 @@ def IRDL_OperandsOp : IRDL_Op<"operands", [HasParent<"OperationOp">]> {
   }];
 
   let arguments = (ins Variadic<IRDL_AttributeType>:$args,
-                        VariadicityArrayAttr:$variadicity);
+                       StrArrayAttr:$names,
+                       VariadicityArrayAttr:$variadicity);
   let assemblyFormat =
-    "`` custom<ValuesWithVariadicity>($args, $variadicity) attr-dict";
+    " `` custom<NamedValueListWithVariadicity>($args, $names, $variadicity) attr-dict";
   let hasVerifier = true;
 }
 
@@ -250,21 +255,22 @@ def IRDL_ResultsOp : IRDL_Op<"results", [HasParent<"OperationOp">]> {
   let summary = "Define the results of an operation";
   let description = [{
     `irdl.results` define the results of the `irdl.operation` parent operation
-    definition.
+    definition. Each result is named after an identifier.
 
     In the following example, `irdl.results` defines the results of the
-    `norm` operation:
+    `get_values` operation:
 
     ```mlir
     irdl.dialect @cmath {
 
       irdl.type @complex { /* ... */ }
 
+      /// Returns the real and imaginary parts of a complex number.
       irdl.operation @get_values {
         %0 = irdl.any
         %1 = irdl.parametric @cmath::@complex<%0>
-        irdl.results(%0, %0)
-        irdl.operands(%1)
+        irdl.results(re: %0, im: %0)
+        irdl.operands(complex: %1)
       }
     }
     ```
@@ -274,11 +280,11 @@ def IRDL_ResultsOp : IRDL_Op<"results", [HasParent<"OperationOp">]> {
 
     The results can also be marked as variadic or optional:
     ```mlir
-    irdl.results(%0, single %1, optional %2, variadic %3)
+    irdl.results(foo: %0, bar: single %1, baz: optional %2, qux: variadic %3)
     ```
 
-    Here, %0 and %1 are required single results, %2 is an optional result,
-    and %3 is a variadic result.
+    Here, foo and bar are required single results, baz is an optional result,
+    and qux is a variadic result.
 
     When more than one result is marked as optional or variadic, the operation
     will expect a 'resultSegmentSizes' attribute that defines the number of
@@ -286,9 +292,10 @@ def IRDL_ResultsOp : IRDL_Op<"results", [HasParent<"OperationOp">]> {
   }];
 
   let arguments = (ins Variadic<IRDL_AttributeType>:$args,
+                        StrArrayAttr:$names,
                         VariadicityArrayAttr:$variadicity);
   let assemblyFormat =
-    " `` custom<ValuesWithVariadicity>($args, $variadicity) attr-dict";
+    " `` custom<NamedValueListWithVariadicity>($args, $names, $variadicity) attr-dict";
   let hasVerifier = true;
 }
 
@@ -297,7 +304,7 @@ def IRDL_AttributesOp : IRDL_Op<"attributes", [HasParent<"OperationOp">]> {
 
   let description = [{
     `irdl.attributes` defines the attributes of the `irdl.operation` parent
-    operation definition.
+    operation definition. Each attribute is named after an identifier.
 
     In the following example, `irdl.attributes` defines the attributes of the
     `attr_op` operation:
@@ -335,7 +342,8 @@ def IRDL_RegionOp : IRDL_Op<"region",
   let summary = "Define a region of an operation";
   let description = [{
     The irdl.region construct defines a set of characteristics
-    that a region of an operation should satify.
+    that a region of an operation should satify. Each region is named after
+    an identifier.
 
     These characteristics include constraints for the entry block arguments
     of the region and the total number of blocks it contains.
@@ -360,7 +368,7 @@ def IRDL_RegionOp : IRDL_Op<"region",
           %r2 = irdl.region(%v0, %v1)
           %r3 = irdl.region with size 3
 
-          irdl.regions(%r0, %r1, %r2, %r3)
+          irdl.regions(foo: %r0, bar: %r1, baz: %r2, qux: %r3)
       }
     }
     ```
@@ -368,11 +376,11 @@ def IRDL_RegionOp : IRDL_Op<"region",
     The above snippet demonstrates an operation named `@op_with_regions`,
     which is constrained to have four regions.
 
-    * Region `%r0` doesn't have any constraints on the arguments
+    * Region `foo` doesn't have any constraints on the arguments
       or the number of blocks.
-    * Region `%r1` should have an empty set of arguments.
-    * Region `%r2` should have two arguments of types `i32` and `i64`.
-    * Region `%r3` should contain exactly three blocks.
+    * Region `bar` should have an empty set of arguments.
+    * Region `baz` should have two arguments of types `i32` and `i64`.
+    * Region `qux` should contain exactly three blocks.
   }];
   let arguments = (ins Variadic<IRDL_AttributeType>:$entryBlockArgs,
                     OptionalAttr<I32Attr>:$numberOfBlocks,
@@ -391,7 +399,8 @@ def IRDL_RegionsOp : IRDL_Op<"regions", [HasParent<"OperationOp">]> {
   let summary = "Define the regions of an operation";
   let description = [{
     `irdl.regions` defines the regions of an operation by accepting
-    values produced by `irdl.region` operation as arguments.
+    values produced by `irdl.region` operation as arguments. Each
+    region has an identifier as name.
 
     Example:
 
@@ -401,18 +410,19 @@ def IRDL_RegionsOp : IRDL_Op<"regions", [HasParent<"OperationOp">]> {
         %r1 = irdl.region with size 3
         %0 = irdl.any
         %r2 = irdl.region(%0)
-        irdl.regions(%r1, %r2)
+        irdl.regions(foo: %r1, bar: %r2)
       }
     }
     ```
 
     In the snippet above the operation is constrained to have two regions.
-    The first region should contain three blocks.
-    The second region should have one region with one argument.
+    The first region (`foo`) should contain three blocks.
+    The second region (`bar`) should have one region with one argument.
   }];
 
-  let arguments = (ins Variadic<IRDL_RegionType>:$args);
-  let assemblyFormat = " `(` $args `)` attr-dict ";
+  let arguments = (ins Variadic<IRDL_RegionType>:$args, StrArrayAttr:$names);
+  let assemblyFormat = " `` custom<NamedValueList>($args, $names) attr-dict ";
+  let hasVerifier = true;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/IRDL/IR/IRDL.cpp b/mlir/lib/Dialect/IRDL/IR/IRDL.cpp
index c5c44d97ce0911..d1ba53fb797c04 100644
--- a/mlir/lib/Dialect/IRDL/IR/IRDL.cpp
+++ b/mlir/lib/Dialect/IRDL/IR/IRDL.cpp
@@ -18,6 +18,9 @@
 #include "mlir/IR/Operation.h"
 #include "mlir/Support/LLVM.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetOperations.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/TypeSwitch.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/Support/Casting.h"
@@ -49,7 +52,7 @@ void IRDLDialect::initialize() {
 }
 
 //===----------------------------------------------------------------------===//
-// Parsing/Printing
+// Parsing/Printing/Verifying
 //===----------------------------------------------------------------------===//
 
 /// Parse a region, and add a single block if the region is empty.
@@ -78,30 +81,104 @@ LogicalResult DialectOp::verify() {
   return success();
 }
 
-LogicalResult OperandsOp::verify() {
-  size_t numVariadicities = getVariadicity().size();
-  size_t numOperands = getNumOperands();
+LogicalResult OperationOp::verifyRegions() {
+  // Stores pairs of value kinds and the list of names of values of this kind in
+  // the operation.
+  SmallVector<std::tuple<StringRef, llvm::SmallDenseSet<StringRef>>> valueNames;
+
+  auto insertNames = [&](StringRef kind, ArrayAttr names) {
+    llvm::SmallDenseSet<StringRef> nameSet;
+    nameSet.reserve(names.size());
+    for (auto name : names)
+      nameSet.insert(llvm::cast<StringAttr>(name).getValue());
+    valueNames.emplace_back(kind, std::move(nameSet));
+  };
 
-  if (numOperands != numVariadicities)
-    return emitOpError()
-           << "the number of operands and their variadicities must be "
+  getBody().walk([&](Operation *op) {
+    TypeSwitch<Operation *>(op)
+        .Case<OperandsOp>(
+            [&](OperandsOp op) { insertNames("operands", op.getNames()); })
+        .Case<ResultsOp>(
+            [&](ResultsOp op) { insertNames("results", op.getNames()); })
+        .Case<RegionsOp>(
+            [&](RegionsOp op) { insertNames("regions", op.getNames()); });
+  });
+
+  // Verify that no two operand, result or region share the same name.
+  for (size_t i : llvm::seq(valueNames.size())) {
+    for (size_t j : llvm::seq(i + 1, valueNames.size())) {
+      auto &[lhs, lhsSet] = valueNames[i];
+      auto &[rhs, rhsSet] = valueNames[j];
+      llvm::set_intersect(lhsSet, rhsSet);
+      if (!lhsSet.empty())
+        return emitOpError("contains a value named '")
+               << *lhsSet.begin() << "' for both its " << lhs << " and " << rhs;
+    }
+  }
+
+  return success();
+}
+
+static LogicalResult verifyNames(Operation *op, StringRef kindName,
+                                 ArrayAttr names, size_t numOperands) {
+  if (numOperands != names.size())
+    return op->emitOpError()
+           << "the number of " << kindName
+           << "s and their names must be "
               "the same, but got "
-           << numOperands << " and " << numVariadicities << " respectively";
+           << numOperands << " and " << names.size() << " respectively";
+
+  DenseMap<StringRef, size_t> nameMap;
+  for (auto [i, name] : llvm::enumerate(names)) {
+    StringRef nameRef = llvm::cast<StringAttr>(name).getValue();
+    if (nameRef.size() == 0)
+      return op->emitOpError()
+             << "name of " << kindName << " number " << i << " is empty";
+    if (!llvm::isAlpha(nameRef[0]) && nameRef[0] != '_')
+      return op->emitOpError()
+             << "name of " << kindName << " number " << i
+             << " must start with either a letter or an underscore";
+    if (llvm::any_of(nameRef,
+                     [](char c) { return !llvm::isAlnum(c) && c != '_'; }))
+      return op->emitOpError()
+             << "name of " << kindName << " number " << i
+             << " must contain only letters, digits and underscores";
+    if (nameMap.contains(nameRef))
+      return op->emitOpError() << "name of " << kindName << " number " << i
+                               << " is a duplicate of the name of " << kindName
+                               << " number " << nameMap[nameRef];
+    nameMap.insert({nameRef, i});
+  }
 
   return success();
 }
 
-LogicalResult ResultsOp::verify() {
-  size_t numVariadicities = getVariadicity().size();
-  size_t numOperands = this->getNumOperands();
+LogicalResult ParametersOp::verify() {
+  return verifyNames(*this, "parameter", getNames(), getNumOperands());
+}
+
+template <typename ValueListOp>
+static LogicalResult verifyOperandsResultsCommon(ValueListOp op,
+                                                 StringRef kindName) {
+  size_t numVariadicities = op.getVariadicity().size();
+  size_t numOperands = op.getNumOperands();
 
   if (numOperands != numVariadicities)
-    return emitOpError()
-           << "the number of operands and their variadicities must be "
+    return op.emitOpError()
+           << "the number of " << kindName
+           << "s and their variadicities must be "
               "the same, but got "
            << numOperands << " and " << numVariadicities << " respectively";
 
-  return success();
+  return verifyNames(op, kindName, op.getNames(), numOperands);
+}
+
+LogicalResult OperandsOp::verify() {
+  return verifyOperandsResultsCommon(*this, "operand");
+}
+
+LogicalResult ResultsOp::verify() {
+  return verifyOperandsResultsCommon(*this, "result");
 }
 
 LogicalResult AttributesOp::verify() {
@@ -196,56 +273,111 @@ parseValueWithVariadicity(OpAsmParser &p,
   return success();
 }
 
-/// Parse a list of values with their variadicities first. By default, the
-/// variadicity is single.
-///
-/// values-with-variadicity ::=
-///   `(` (value-with-variadicity (`,` value-with-variadicity)*)? `)`
-/// value-with-variadicity ::= ("single" | "optional" | "variadic")? ssa-value
-static ParseResult parseValuesWithVariadicity(
+static ParseResult parseNamedValueListImpl(
     OpAsmParser &p, SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands,
-    VariadicityArrayAttr &variadicityAttr) {
+    ArrayAttr &valueNamesAttr, VariadicityArrayAttr *variadicityAttr) {
   Builder &builder = p.getBuilder();
   MLIRContext *ctx = builder.getContext();
+  SmallVector<Attribute> valueNames;
   SmallVector<VariadicityAttr> variadicities;
 
   // Parse a single value with its variadicity
   auto parseOne = [&] {
+    StringRef name;
     OpAsmParser::UnresolvedOperand operand;
     VariadicityAttr variadicity;
-    if (parseValueWithVariadicity(p, operand, variadicity))
+    if (p.parseKeyword(&name) || p.parseColon())
       return failure();
+
+    if (variadicityAttr) {
+      if (parseValueWithVariadicity(p, operand, variadicity))
+        return failure();
+      variadicities.push_back(variadicity);
+    } else {
+      if (p.parseOperand(operand))
+        return failure();
+    }
+
+    valueNames.push_back(StringAttr::get(ctx, name));
     operands.push_back(operand);
-    variadicities.push_back(variadicity);
     return success();
   };
 
   if (p.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren, parseOne))
     return failure();
-  variadicityAttr = VariadicityArrayAttr::get(ctx, variadicities);
+  valueNamesAttr = ArrayAttr::get(ctx, valueNames);
+  if (variadicityAttr)
+    *variadicityAttr = VariadicityArrayAttr::get(ctx, variadicities);
   return success();
 }
 
-/// Print a list of values with their variadicities first. By default, the
+/// Parse a list of named values.
+///
+/// values ::=
+///   `(` (named-value (`,` named-value)*)? `)`
+/// named-value := bare-id `:` ssa-value
+static ParseResult
+parseNamedValueList(OpAsmParser &p,
+                    SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands,
+                    ArrayAttr &valueNamesAttr) {
+  return parseNamedValueListImpl(p, operands, valueNamesAttr, nullptr);
+}
+
+/// Parse a list of named values with their variadicities first. By default, the
 /// variadicity is single.
 ///
 /// values-with-variadicity ::=
 ///   `(` (value-with-variadicity (`,` value-with-variadicity)*)? `)`
-/// value-with-variadicity ::= ("single" | "optional" | "variadic")? ssa-value
-static void printValuesWithVariadicity(OpAsmPrinter &p, Operation *op,
-                                       OperandRange operands,
-                                       VariadicityArrayAttr variadicityAttr) {
+/// value-with-variadicity
+///   ::= bare-id `:` ("single" | "optional" | "variadic")? ssa-value
+static ParseResult parseNamedValueListWithVariadicity(
+    OpAsmParser &p, SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands,
+    ArrayAttr &valueNamesAttr, VariadicityArrayAttr &variadicityAttr) {
+  return parseNamedValueListImpl(p, operands, valueNamesAttr, &variadicityAttr);
+}
+
+static void printNamedValueListImpl(OpAsmPrinter &p, Operation *op,
+                                    OperandRange operands,
+                                    ArrayAttr valueNamesAttr,
+                                    VariadicityArrayAttr variadicityAttr) {
   p << "(";
   interleaveComma(llvm::seq<int>(0, operands.size()), p, [&](int i) {
-    Variadicity variadicity = variadicityAttr[i].getValue();
-    if (variadicity != Variadicity::single) {
-      p << stringifyVariadicity(variadicity) << " ";
+    p << llvm::cast<StringAttr>(valueNamesAttr[i]).getValue() << ": ";
+    if (variadicityAttr) {
+      Variadicity variadicity = variadicityAttr[i].getValue();
+      if (variadicity != Variadicity::single) {
+        p << stringifyVariadicity(variadicity) << " ";
+      }
     }
     p << operands[i];
   });
   p << ")";
 }
 
+/// Print a list of named values.
+///
+/// values ::=
+///   `(` (named-value (`,` named-value)*)? `)`
+/// named-value := bare-id `:` ssa-value
+static void printNamedValueList(OpAsmPrinter &p, Operation *op,
+                                OperandRange operands,
+                                ArrayAttr valueNamesAttr) {
+  printNamedValueListImpl(p, op, operands, valueNamesAttr, nullptr);
+}
+
+/// Print a list of named values with their variadicities first. By default, the
+/// variadicity is single.
+///
+/// values-with-variadicity ::=
+///   `(` (value-with-variadicity (`,` value-with-variadicity)*)? `)`
+/// value-with-variadicity ::=
+///   bare-id `:` ("single" | "optional" | "variadic")? ssa-value
+static void printNamedValueListWithVariadicity(
+    OpAsmPrinter &p, Operation *op, OperandRange operands,
+    ArrayAttr valueNamesAttr, VariadicityArrayAttr variadicityAttr) {
+  printNamedValueListImpl(p, op, operands, valueNamesAttr, variadicityAttr);
+}
+
 static ParseResult
 parseAttributesOp(OpAsmParser &p,
                   SmallVectorImpl<OpAsmParser::UnresolvedOperand> &attrOperands,
@@ -285,6 +...
[truncated]

@Moxinilian
Copy link
Member Author

Attributes are named differently and I made no change to them. It is going to be trickier to generate getters from attributes but as attribute names are part of the IR, we can't impose arbitrary constraints.

Copy link
Contributor

@math-fehr math-fehr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool! I added some comments, but it was only small stuff.

@math-fehr math-fehr self-requested a review January 19, 2025 20:53
@Moxinilian Moxinilian merged commit 69d3ba3 into llvm:main Jan 19, 2025
8 checks passed
@Moxinilian Moxinilian deleted the irdl-names branch January 19, 2025 20:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mlir:core MLIR Core Infrastructure mlir:irdl mlir
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants