[Mlir-commits] [mlir] [MLIR] Guard optional operand resolution in generated op parsers (PR #180796)

Henrich Lauko llvmlistbot at llvm.org
Tue Feb 10 09:58:18 PST 2026


https://github.com/xlauko created https://github.com/llvm/llvm-project/pull/180796

Skip resolveOperands for optional operands when they are absent to
avoid out-of-bounds access on the empty types vector.

>From 05bb31f6b9ed3c8b87a250ce5d740da4415aab76 Mon Sep 17 00:00:00 2001
From: xlauko <xlauko at mail.muni.cz>
Date: Tue, 10 Feb 2026 18:56:44 +0100
Subject: [PATCH] [MLIR] Guard optional operand resolution in generated op
 parsers

Skip resolveOperands for optional operands when they are absent to
avoid out-of-bounds access on the empty types vector.
---
 mlir/test/lib/Dialect/Test/TestOpsSyntax.td | 11 +++++++++++
 mlir/test/mlir-tblgen/op-format.mlir        |  6 ++++++
 mlir/tools/mlir-tblgen/OpFormatGen.cpp      |  6 ++++++
 3 files changed, 23 insertions(+)

diff --git a/mlir/test/lib/Dialect/Test/TestOpsSyntax.td b/mlir/test/lib/Dialect/Test/TestOpsSyntax.td
index 73de8295380a6..6b10ec6173a50 100644
--- a/mlir/test/lib/Dialect/Test/TestOpsSyntax.td
+++ b/mlir/test/lib/Dialect/Test/TestOpsSyntax.td
@@ -667,6 +667,17 @@ def FormatTypesMatchContextOp : TEST_Op<"format_types_match_context", [
   let assemblyFormat = "attr-dict $value `:` type($value)";
 }
 
+def FormatTypesMatchOptionalOp : TEST_Op<"format_types_match_optional", [
+    OptionalTypesMatchWith<"optional type matches result", 
+                           "result", "optional", "$_self">
+  ]> {
+  let arguments = (ins Optional<AnyType>:$optional);
+  let results = (outs Optional<AnyType>:$result);
+  let assemblyFormat = [{
+    (`(` $optional^ `:` type($result) `)`)? attr-dict
+  }];
+}
+
 //===----------------------------------------------------------------------===//
 // InferTypeOpInterface type inference in assembly format
 //===----------------------------------------------------------------------===//
diff --git a/mlir/test/mlir-tblgen/op-format.mlir b/mlir/test/mlir-tblgen/op-format.mlir
index ac0931f18f042..7ff9091d5500d 100644
--- a/mlir/test/mlir-tblgen/op-format.mlir
+++ b/mlir/test/mlir-tblgen/op-format.mlir
@@ -488,6 +488,12 @@ test.format_infer_variadic_type_from_non_variadic %i64, %i64 : i64
 // CHECK: test.format_types_match_context %[[I64]] : i64
 %ignored_res6 = test.format_types_match_context %i64 : i64
 
+// CHECK: test.format_types_match_optional(%[[I64]] : i64)
+%ignored_res7 = test.format_types_match_optional(%i64 : i64)
+
+// CHECK: test.format_types_match_optional
+test.format_types_match_optional
+
 //===----------------------------------------------------------------------===//
 // InferTypeOpInterface type inference
 //===----------------------------------------------------------------------===//
diff --git a/mlir/tools/mlir-tblgen/OpFormatGen.cpp b/mlir/tools/mlir-tblgen/OpFormatGen.cpp
index ccf21d16005af..b834c6f8d3aaf 100644
--- a/mlir/tools/mlir-tblgen/OpFormatGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpFormatGen.cpp
@@ -1848,6 +1848,10 @@ void OperationFormat::genParserOperandTypeResolution(
   // separately.
   for (unsigned i = 0, e = op.getNumOperands(); i != e; ++i) {
     NamedTypeConstraint &operand = op.getOperand(i);
+    // Optional operands may not be present; guard resolution to avoid
+    // out-of-bounds access on the (potentially empty) types vector.
+    if (operand.isOptional())
+      body << "  if (!" << operand.name << "Operands.empty()) {\n";
     body << "  if (parser.resolveOperands(" << operand.name << "Operands, ";
 
     // Resolve the type of this operand.
@@ -1856,6 +1860,8 @@ void OperationFormat::genParserOperandTypeResolution(
 
     body << ", " << operand.name
          << "OperandsLoc, result.operands))\n    return ::mlir::failure();\n";
+    if (operand.isOptional())
+      body << "  }\n";
   }
 }
 



More information about the Mlir-commits mailing list