[Mlir-commits] [mlir] [mlir][wasmssa] Fix if/else round-trip and verify return types (PR #227828)

Ferdinand Lemaire llvmlistbot at llvm.org
Sat Oct 3 19:42:44 PDT 2026


https://github.com/flemairen6 updated https://github.com/llvm/llvm-project/pull/227828

>From a52cafc0cc096953ce492d92a1777f88261d3f58 Mon Sep 17 00:00:00 2001
From: Saqib Khan <11544614+saqibkh at users.noreply.github.com>
Date: Wed, 30 Sep 2026 12:41:48 -0500
Subject: [PATCH] [mlir][wasmssa] Fix if/else round-trip and verify return
 types

`wasmssa.if` printed its else keyword with printKeywordOrString("else "),
which emits the quoted string "else " because of the trailing space.
The parser only accepts the `else` keyword, so printed IR with an else
region failed to parse back (#226072). Print the keyword directly.

`wasmssa.return` had no verifier, so a function could return values
whose number or types differ from its declared results (#226073). Add a
verifier that checks the operands against the enclosing `wasmssa.func`,
which also covers returns nested in block, loop and if regions.

Update the tests that captured the broken `"else "` output, fix
`@func_0` in custom_parser/if.mlir, which returned f32 from an i32
function, and run it through a print/parse round trip.

Fixes #226072
Fixes #226073

Assisted-by: Claude Code (Claude Opus 5.5)
---
 .../mlir/Dialect/WasmSSA/IR/WasmSSAOps.td     |  1 +
 mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp    | 20 ++++++++++-
 .../Dialect/WasmSSA/custom_parser/if.mlir     |  7 ++--
 mlir/test/Dialect/WasmSSA/return-invalid.mlir | 36 +++++++++++++++++++
 mlir/test/Target/Wasm/if.mlir                 |  4 +--
 5 files changed, 62 insertions(+), 6 deletions(-)
 create mode 100644 mlir/test/Dialect/WasmSSA/return-invalid.mlir

diff --git a/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td b/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td
index 2df567c393e59..050877fb78507 100644
--- a/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td
+++ b/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td
@@ -685,6 +685,7 @@ def WasmSSA_ReturnOp : WasmSSA_Op<"return", [Terminator]> {
   let builders = [
     OpBuilder<(ins)>
   ];
+  let hasVerifier = 1;
 }
 
 def WasmSSA_SelectOp : WasmSSA_Op<"select", [
diff --git a/mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp b/mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp
index e0e4b085bc21e..e04201863b107 100644
--- a/mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp
+++ b/mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp
@@ -37,7 +37,7 @@ void printElseRegion(OpAsmPrinter &opPrinter, Operation *op,
                      Region &elseRegion) {
   if (elseRegion.empty())
     return;
-  opPrinter.printKeywordOrString("else ");
+  opPrinter << "else ";
   opPrinter.printRegion(elseRegion);
 }
 } // namespace
@@ -493,3 +493,21 @@ LogicalResult ReinterpretOp::verify() {
 //===----------------------------------------------------------------------===//
 
 void ReturnOp::build(OpBuilder &odsBuilder, OperationState &odsState) {}
+
+LogicalResult ReturnOp::verify() {
+  auto funcOp = (*this)->getParentOfType<FuncOp>();
+  if (!funcOp)
+    return success();
+  ArrayRef<Type> resultTypes = funcOp.getFunctionType().getResults();
+  if (getOperands().size() != resultTypes.size())
+    return emitOpError("has ") << getOperands().size()
+                               << " operands, but enclosing function returns "
+                               << resultTypes.size();
+  for (auto [idx, resultType, operandType] :
+       llvm::enumerate(resultTypes, getOperands().getTypes()))
+    if (resultType != operandType)
+      return emitOpError("type of return operand #")
+             << idx << " (" << operandType
+             << ") doesn't match function result type (" << resultType << ")";
+  return success();
+}
diff --git a/mlir/test/Dialect/WasmSSA/custom_parser/if.mlir b/mlir/test/Dialect/WasmSSA/custom_parser/if.mlir
index cee3c695af2f0..e0f39651a5728 100644
--- a/mlir/test/Dialect/WasmSSA/custom_parser/if.mlir
+++ b/mlir/test/Dialect/WasmSSA/custom_parser/if.mlir
@@ -1,18 +1,19 @@
 // RUN: mlir-opt %s | FileCheck %s
+// RUN: mlir-opt %s | mlir-opt | FileCheck %s
 
 // CHECK-LABEL:   wasmssa.func @func_0(
-// CHECK-SAME:      %[[ARG0:.*]]: !wasmssa<local ref to i32>) -> i32 {
+// CHECK-SAME:      %[[ARG0:.*]]: !wasmssa<local ref to i32>) -> f32 {
 // CHECK:           %[[VAL_0:.*]] = wasmssa.local_get %[[ARG0]] :  ref to i32
 // CHECK:           wasmssa.if %[[VAL_0]] : {
 // CHECK:             %[[VAL_1:.*]] = wasmssa.const 5.000000e-01 : f32
 // CHECK:             wasmssa.block_return %[[VAL_1]] : f32
-// CHECK:           } "else "{
+// CHECK:           } else {
 // CHECK:             %[[VAL_2:.*]] = wasmssa.const 2.500000e-01 : f32
 // CHECK:             wasmssa.block_return %[[VAL_2]] : f32
 // CHECK:           }> ^bb1
 // CHECK:         ^bb1(%[[VAL_3:.*]]: f32):
 // CHECK:           wasmssa.return %[[VAL_3]] : f32
-wasmssa.func @func_0(%arg0 : !wasmssa<local ref to i32>) -> i32 {
+wasmssa.func @func_0(%arg0 : !wasmssa<local ref to i32>) -> f32 {
   %cond = wasmssa.local_get %arg0 : ref to i32
   wasmssa.if %cond : {
     %c0 = wasmssa.const 0.5 : f32
diff --git a/mlir/test/Dialect/WasmSSA/return-invalid.mlir b/mlir/test/Dialect/WasmSSA/return-invalid.mlir
new file mode 100644
index 0000000000000..6d0c673ce35a8
--- /dev/null
+++ b/mlir/test/Dialect/WasmSSA/return-invalid.mlir
@@ -0,0 +1,36 @@
+// RUN: mlir-opt %s -split-input-file -verify-diagnostics
+
+wasmssa.func @return_type_mismatch() -> i32 {
+  %0 = wasmssa.const 0.5 : f32
+  // expected-error at +1 {{type of return operand #0 ('f32') doesn't match function result type ('i32')}}
+  wasmssa.return %0 : f32
+}
+
+// -----
+
+wasmssa.func @return_too_few_operands() -> i32 {
+  // expected-error at +1 {{has 0 operands, but enclosing function returns 1}}
+  wasmssa.return
+}
+
+// -----
+
+wasmssa.func @return_too_many_operands() {
+  %0 = wasmssa.const 1 : i32
+  // expected-error at +1 {{has 1 operands, but enclosing function returns 0}}
+  wasmssa.return %0 : i32
+}
+
+// -----
+
+wasmssa.func @return_in_nested_region(%arg0 : !wasmssa<local ref to i32>) -> i64 {
+  %cond = wasmssa.local_get %arg0 : ref to i32
+  wasmssa.if %cond : {
+    %c0 = wasmssa.const 1 : i32
+    // expected-error at +1 {{type of return operand #0 ('i32') doesn't match function result type ('i64')}}
+    wasmssa.return %c0 : i32
+  } >^bb1
+ ^bb1:
+  %c1 = wasmssa.const 2 : i64
+  wasmssa.return %c1 : i64
+}
diff --git a/mlir/test/Target/Wasm/if.mlir b/mlir/test/Target/Wasm/if.mlir
index 2d7bfbed6f754..a7acc3d836e64 100644
--- a/mlir/test/Target/Wasm/if.mlir
+++ b/mlir/test/Target/Wasm/if.mlir
@@ -62,7 +62,7 @@
 // CHECK:             %[[VAL_6:.*]] = wasmssa.const 1 : i32
 // CHECK:             %[[VAL_7:.*]] = wasmssa.add %[[VAL_5]] %[[VAL_6]] : i32
 // CHECK:             wasmssa.block_return %[[VAL_7]] : i32
-// CHECK:           } "else "{
+// CHECK:           } else {
 // CHECK:             %[[VAL_8:.*]] = wasmssa.local_get %[[ARG0]] :  ref to i32
 // CHECK:             %[[VAL_9:.*]] = wasmssa.const 1 : i32
 // CHECK:             %[[VAL_10:.*]] = wasmssa.shr_u %[[VAL_8]] by %[[VAL_9]] bits : i32
@@ -104,7 +104,7 @@
 // CHECK:             } > ^bb1
 // CHECK:           ^bb1(%[[VAL_10:.*]]: i32):
 // CHECK:             wasmssa.block_return %[[VAL_10]] : i32
-// CHECK:           } "else "{
+// CHECK:           } else {
 // CHECK:             %[[VAL_11:.*]] = wasmssa.const 1 : i32
 // CHECK:             wasmssa.block_return %[[VAL_11]] : i32
 // CHECK:           }> ^bb1



More information about the Mlir-commits mailing list