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

llvmlistbot at llvm.org llvmlistbot at llvm.org
Sat Oct 3 20:23:29 PDT 2026


Author: Saqib Khan
Date: 2026-10-04T03:23:20Z
New Revision: c93bad65aa654f507ea768610d003c42ba31ab7b

URL: https://github.com/llvm/llvm-project/commit/c93bad65aa654f507ea768610d003c42ba31ab7b
DIFF: https://github.com/llvm/llvm-project/commit/c93bad65aa654f507ea768610d003c42ba31ab7b.diff

LOG: [mlir][wasmssa] Fix if/else round-trip and verify return types (#227828)

Fixes two WasmSSA dialect bugs:

**#226072: `wasmssa.if` does not round-trip.** The else region was
printed with `printKeywordOrString("else ")`. Because of the trailing
space, `"else "` is not a valid bare keyword, so it was printed as a
quoted string (`} "else "{`), which `parseElseRegion` does not accept.
The else keyword is now printed directly, giving `} else {`.

**#226073: `wasmssa.return` is not checked against the function's
results.** `wasmssa.return` had no verifier, so a function could return
a different number or type of values than its signature declares. This
adds a `ReturnOp` verifier that checks the operands against the
enclosing `wasmssa.func`. Checking in the return op rather than in
`FuncOp::verifyBody` also covers returns nested inside
`block`/`loop`/`if` regions.

Tests:
- `custom_parser/if.mlir` expected the broken `"else "` output; it now
expects `} else {` and gains a second RUN line piping through `mlir-opt`
again to check the round trip. Its `@func_0` returned `f32` from an
`i32` function, which the new verifier rejects, so the signature is now
`-> f32`.
- `Target/Wasm/if.mlir` also expected the quoted `"else "` and is
updated. The Wasm importer's output passes the new verifier.
- New `return-invalid.mlir` covers type mismatch, too few / too many
operands, and a mismatched return inside a nested `if` region.

`llvm-lit mlir/test/Dialect/WasmSSA mlir/test/Target/Wasm
mlir/test/Conversion/RaiseWasm`: 112/112 pass. The new and updated
dialect tests fail without the fix.

Assisted-by: Claude Code (Claude Opus 5.5)

Co-authored-by: Ferdinand Lemaire <flscminecraft at gmail.com>

Added: 
    mlir/test/Dialect/WasmSSA/return-invalid.mlir

Modified: 
    mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td
    mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp
    mlir/test/Dialect/WasmSSA/custom_parser/if.mlir
    mlir/test/Target/Wasm/if.mlir

Removed: 
    


################################################################################
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