[Mlir-commits] [mlir] [MLIR][WASM] Introduce full support for raising WASM MLIR to other dialects (PR #205990)

Ferdinand Lemaire llvmlistbot at llvm.org
Thu Jun 25 23:48:02 PDT 2026


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

>From f294988d80afcf50d52102adf91aa52dd2e9199e Mon Sep 17 00:00:00 2001
From: Ferdinand Lemaire <ferdinand.lemaire at woven-planet.global>
Date: Thu, 3 Jul 2025 12:48:24 +0900
Subject: [PATCH 1/5] [mlir][wasm] RaiseWasmMLIRPass: Add suport for comparison
 operators

--
 Co-authored-by: Luc Forget <luc.forget at woven-planet.global>
 Co-authored-by: Jessica Paquette <jessica.paquette at woven-planet.global>
---
 .../Conversion/RaiseWasm/RaiseWasmMLIR.cpp    | 139 ++++++
 .../wasm-comparisons-to-arith-cmp.mlir        | 421 ++++++++++++++++++
 .../RaiseWasm/wasm-eqz-to-arith-cmp.mlir      |  28 ++
 3 files changed, 588 insertions(+)
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-comparisons-to-arith-cmp.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-eqz-to-arith-cmp.mlir

diff --git a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
index 83bfde7032ef8..1fb4564032421 100644
--- a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
+++ b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
@@ -124,6 +124,104 @@ using WasmTruncOpConversion = OpMappingConversion<TruncOp, math::TruncOp>;
 using WasmSqrtOpConversion = OpMappingConversion<SqrtOp, math::SqrtOp>;
 using WasmWrapOpConversion = OpMappingConversion<WrapOp, arith::TruncIOp>;
 
+template <typename SourceOp, typename TargetOp, typename AttrType,
+          typename ValType, ValType flag>
+struct ComparisonOpConversion : OpConversionPattern<SourceOp> {
+  using OpConversionPattern<SourceOp>::OpConversionPattern;
+
+  LogicalResult
+  matchAndRewrite(SourceOp srcOp, typename SourceOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    auto cmpRes =
+        rewriter
+            .create<TargetOp>(srcOp.getLoc(), rewriter.getI1Type(),
+                              AttrType::get(rewriter.getContext(), flag),
+                              adaptor.getLhs(), adaptor.getRhs())
+            .getResult();
+    rewriter.replaceOpWithNewOp<arith::ExtUIOp>(srcOp, rewriter.getI32Type(),
+                                                cmpRes);
+
+    return success();
+  }
+};
+
+template <typename SourceOp, arith::CmpFPredicate compFlag>
+using FPComparisonConversion =
+    ComparisonOpConversion<SourceOp, arith::CmpFOp, arith::CmpFPredicateAttr,
+                           arith::CmpFPredicate, compFlag>;
+
+template <typename SourceOp, arith::CmpIPredicate compFlag>
+using IntComparisonConversion =
+    ComparisonOpConversion<SourceOp, arith::CmpIOp, arith::CmpIPredicateAttr,
+                           arith::CmpIPredicate, compFlag>;
+
+using WasmLtSIOpConversion =
+    IntComparisonConversion<LtSIOp, arith::CmpIPredicate::slt>;
+using WasmLeSIOpConversion =
+    IntComparisonConversion<LeSIOp, arith::CmpIPredicate::sle>;
+using WasmGtSIOpConversion =
+    IntComparisonConversion<GtSIOp, arith::CmpIPredicate::sgt>;
+using WasmGeSIOpConversion =
+    IntComparisonConversion<GeSIOp, arith::CmpIPredicate::sge>;
+using WasmLtUIOpConversion =
+    IntComparisonConversion<LtUIOp, arith::CmpIPredicate::ult>;
+using WasmLeUIOpConversion =
+    IntComparisonConversion<LeUIOp, arith::CmpIPredicate::ule>;
+using WasmGtUIOpConversion =
+    IntComparisonConversion<GtUIOp, arith::CmpIPredicate::ugt>;
+using WasmGeUIOpConversion =
+    IntComparisonConversion<GeUIOp, arith::CmpIPredicate::uge>;
+using WasmLtOpConversion =
+    FPComparisonConversion<LtOp, arith::CmpFPredicate::OLT>;
+using WasmLeOpConversion =
+    FPComparisonConversion<LeOp, arith::CmpFPredicate::OLE>;
+using WasmGtOpConversion =
+    FPComparisonConversion<GtOp, arith::CmpFPredicate::OGT>;
+using WasmGeOpConversion =
+    FPComparisonConversion<GeOp, arith::CmpFPredicate::OGE>;
+
+template <typename SourceOp, arith::CmpIPredicate IntFlag,
+          arith::CmpFPredicate FloatFlag>
+struct IntFpComparisonOpConversion : OpConversionPattern<SourceOp> {
+  using OpConversionPattern<SourceOp>::OpConversionPattern;
+
+  LogicalResult
+  matchAndRewrite(SourceOp srcOp, typename SourceOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    Value comparisonResult;
+    if (srcOp.getLhs().getType().isInteger())
+      comparisonResult =
+          rewriter
+              .create<arith::CmpIOp>(
+                  srcOp.getLoc(), rewriter.getI1Type(),
+                  arith::CmpIPredicateAttr::get(rewriter.getContext(), IntFlag),
+                  adaptor.getLhs(), adaptor.getRhs())
+              .getResult();
+    else if (srcOp.getLhs().getType().isFloat())
+      comparisonResult =
+          rewriter
+              .create<arith::CmpFOp>(srcOp.getLoc(), rewriter.getI1Type(),
+                                     arith::CmpFPredicateAttr::get(
+                                         rewriter.getContext(), FloatFlag),
+                                     adaptor.getLhs(), adaptor.getRhs())
+              .getResult();
+    else
+      return rewriter.notifyMatchFailure(
+          srcOp.getLoc(), "Unsupported datatype for comparison OP.");
+
+    rewriter.replaceOpWithNewOp<arith::ExtUIOp>(srcOp, rewriter.getI32Type(),
+                                                comparisonResult);
+    return success();
+  }
+};
+
+using WasmEqOpConversion =
+    IntFpComparisonOpConversion<EqOp, arith::CmpIPredicate::eq,
+                                arith::CmpFPredicate::OEQ>;
+using WasmNeOpConversion =
+    IntFpComparisonOpConversion<NeOp, arith::CmpIPredicate::ne,
+                                arith::CmpFPredicate::ONE>;
+
 struct WasmCallOpConversion : OpConversionPattern<FuncCallOp> {
   using OpConversionPattern::OpConversionPattern;
 
@@ -148,6 +246,32 @@ struct WasmConstOpConversion : OpConversionPattern<ConstOp> {
   }
 };
 
+struct WasmEqzOpConversion : OpConversionPattern<EqzOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  LogicalResult
+  matchAndRewrite(EqzOp eqzOp, EqzOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    auto loc = eqzOp->getLoc();
+    auto zero =
+        rewriter
+            .create<arith::ConstantOp>(
+                loc, rewriter.getIntegerAttr(adaptor.getInput().getType(), 0))
+            .getResult();
+    auto cmpRes = rewriter
+                      .create<arith::CmpIOp>(
+                          loc, rewriter.getI1Type(),
+                          arith::CmpIPredicateAttr::get(
+                              rewriter.getContext(), arith::CmpIPredicate::eq),
+                          adaptor.getInput(), zero)
+                      .getResult();
+    rewriter.replaceOpWithNewOp<arith::ExtUIOp>(eqzOp, rewriter.getI32Type(),
+                                                cmpRes);
+
+    return success();
+  }
+};
+
 struct WasmFuncImportOpConversion : OpConversionPattern<FuncImportOp> {
   using OpConversionPattern::OpConversionPattern;
 
@@ -429,21 +553,36 @@ void mlir::populateRaiseWasmMLIRConversionPatterns(
            WasmDivFPOpConversion,
            WasmDivSIOpConversion,
            WasmDivUIOpConversion,
+           WasmEqOpConversion,
+           WasmEqzOpConversion,
            WasmExtendSOpConversion,
            WasmExtendUOpConversion,
            WasmFloorOpConversion,
            WasmFuncImportOpConversion,
            WasmFuncOpConversion,
+           WasmGeOpConversion,
+           WasmGeSIOpConversion,
+           WasmGeUIOpConversion,
            WasmGlobalImportOpConverter,
            WasmGlobalWithConstInitConversion,
            WasmGlobalWithGetGlobalInitConversion,
+           WasmGtOpConversion,
+           WasmGtSIOpConversion,
+           WasmGtUIOpConversion,
+           WasmLeOpConversion,
+           WasmLeSIOpConversion,
+           WasmLeUIOpConversion,
            WasmLocalConversion,
            WasmLocalGetConversion,
            WasmLocalSetConversion,
            WasmLocalTeeConversion,
+           WasmLtOpConversion,
+           WasmLtSIOpConversion,
+           WasmLtUIOpConversion,
            WasmMaxOpConversion,
            WasmMinOpConversion,
            WasmMulOpConversion,
+           WasmNeOpConversion,
            WasmNegOpConversion,
            WasmOrOpConversion,
            WasmPopCntOpConversion,
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-comparisons-to-arith-cmp.mlir b/mlir/test/Conversion/RaiseWasm/wasm-comparisons-to-arith-cmp.mlir
new file mode 100644
index 0000000000000..bc952b47520ca
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-comparisons-to-arith-cmp.mlir
@@ -0,0 +1,421 @@
+// RUN: mlir-opt %s --raise-wasm-mlir | FileCheck %s
+
+
+module {
+  wasmssa.func nested @func_lt_si32() -> i32 {
+    %0 = wasmssa.const 12 : i32
+    %1 = wasmssa.const 50 : i32
+    %2 = wasmssa.lt_si %0 %1 : i32 -> i32
+    wasmssa.return %2 : i32
+  }
+
+  wasmssa.func nested @func_le_si32() -> i32 {
+    %0 = wasmssa.const 12 : i32
+    %1 = wasmssa.const 50 : i32
+    %2 = wasmssa.le_si %0 %1 : i32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_lt_ui32() -> i32 {
+    %0 = wasmssa.const 12 : i32
+    %1 = wasmssa.const 50 : i32
+    %2 = wasmssa.lt_ui %0 %1 : i32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_le_ui32() -> i32 {
+    %0 = wasmssa.const 12 : i32
+    %1 = wasmssa.const 50 : i32
+    %2 = wasmssa.le_ui %0 %1 : i32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_gt_si32() -> i32 {
+    %0 = wasmssa.const 12 : i32
+    %1 = wasmssa.const 50 : i32
+    %2 = wasmssa.gt_si %0 %1 : i32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_gt_ui32() -> i32 {
+    %0 = wasmssa.const 12 : i32
+    %1 = wasmssa.const 50 : i32
+    %2 = wasmssa.gt_ui %0 %1 : i32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_ge_si32() -> i32 {
+    %0 = wasmssa.const 12 : i32
+    %1 = wasmssa.const 50 : i32
+    %2 = wasmssa.ge_si %0 %1 : i32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_ge_ui32() -> i32 {
+    %0 = wasmssa.const 12 : i32
+    %1 = wasmssa.const 50 : i32
+    %2 = wasmssa.ge_ui %0 %1 : i32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_lt_si64() -> i32 {
+    %0 = wasmssa.const 12 : i64
+    %1 = wasmssa.const 50 : i64
+    %2 = wasmssa.lt_si %0 %1 : i64 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_le_si64() -> i32 {
+    %0 = wasmssa.const 12 : i64
+    %1 = wasmssa.const 50 : i64
+    %2 = wasmssa.le_si %0 %1 : i64 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_lt_ui_i64() -> i32 {
+    %0 = wasmssa.const 12 : i64
+    %1 = wasmssa.const 50 : i64
+    %2 = wasmssa.lt_ui %0 %1 : i64 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_le_ui_i64() -> i32 {
+    %0 = wasmssa.const 12 : i64
+    %1 = wasmssa.const 50 : i64
+    %2 = wasmssa.le_ui %0 %1 : i64 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_gt_si_i64() -> i32 {
+    %0 = wasmssa.const 12 : i64
+    %1 = wasmssa.const 50 : i64
+    %2 = wasmssa.gt_si %0 %1 : i64 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_gt_ui_i64() -> i32 {
+    %0 = wasmssa.const 12 : i64
+    %1 = wasmssa.const 50 : i64
+    %2 = wasmssa.gt_ui %0 %1 : i64 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_ge_si_i64() -> i32 {
+    %0 = wasmssa.const 12 : i64
+    %1 = wasmssa.const 50 : i64
+    %2 = wasmssa.ge_si %0 %1 : i64 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_ge_ui_i64() -> i32 {
+    %0 = wasmssa.const 12 : i64
+    %1 = wasmssa.const 50 : i64
+    %2 = wasmssa.ge_ui %0 %1 : i64 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_lt_f32() -> i32 {
+    %0 = wasmssa.const 5.000000e+00 : f32
+    %1 = wasmssa.const 1.400000e+01 : f32
+    %2 = wasmssa.lt %0 %1 : f32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_le_f32() -> i32 {
+    %0 = wasmssa.const 5.000000e+00 : f32
+    %1 = wasmssa.const 1.400000e+01 : f32
+    %2 = wasmssa.le %0 %1 : f32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_gt_f32() -> i32 {
+    %0 = wasmssa.const 5.000000e+00 : f32
+    %1 = wasmssa.const 1.400000e+01 : f32
+    %2 = wasmssa.gt %0 %1 : f32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_ge_f32() -> i32 {
+    %0 = wasmssa.const 5.000000e+00 : f32
+    %1 = wasmssa.const 1.400000e+01 : f32
+    %2 = wasmssa.ge %0 %1 : f32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_lt_f64() -> i32 {
+    %0 = wasmssa.const 5.000000e+00 : f64
+    %1 = wasmssa.const 1.400000e+01 : f64
+    %2 = wasmssa.lt %0 %1 : f64 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_le_f64() -> i32 {
+    %0 = wasmssa.const 5.000000e+00 : f64
+    %1 = wasmssa.const 1.400000e+01 : f64
+    %2 = wasmssa.le %0 %1 : f64 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_gt_f64() -> i32 {
+    %0 = wasmssa.const 5.000000e+00 : f64
+    %1 = wasmssa.const 1.400000e+01 : f64
+    %2 = wasmssa.gt %0 %1 : f64 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_ge_f64() -> i32 {
+    %0 = wasmssa.const 5.000000e+00 : f64
+    %1 = wasmssa.const 1.400000e+01 : f64
+    %2 = wasmssa.ge %0 %1 : f64 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_eq_i32() -> i32 {
+    %0 = wasmssa.const 12 : i32
+    %1 = wasmssa.const 50 : i32
+    %2 = wasmssa.eq %0 %1 : i32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_eq_i64() -> i32 {
+    %0 = wasmssa.const 20 : i64
+    %1 = wasmssa.const 5 : i64
+    %2 = wasmssa.eq %0 %1 : i64 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_eq_f32() -> i32 {
+    %0 = wasmssa.const 5.000000e+00 : f32
+    %1 = wasmssa.const 1.400000e+01 : f32
+    %2 = wasmssa.eq %0 %1 : f32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_eq_f64() -> i32 {
+    %0 = wasmssa.const 1.700000e+01 : f64
+    %1 = wasmssa.const 0.000000e+00 : f64
+    %2 = wasmssa.eq %0 %1 : f64 -> i32
+    wasmssa.return %2 : i32
+  }
+    wasmssa.func nested @func_ne_i32() -> i32 {
+    %0 = wasmssa.const 12 : i32
+    %1 = wasmssa.const 50 : i32
+    %2 = wasmssa.ne %0 %1 : i32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_ne_i64() -> i32 {
+    %0 = wasmssa.const 20 : i64
+    %1 = wasmssa.const 5 : i64
+    %2 = wasmssa.ne %0 %1 : i64 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_ne_f32() -> i32 {
+    %0 = wasmssa.const 5.000000e+00 : f32
+    %1 = wasmssa.const 1.400000e+01 : f32
+    %2 = wasmssa.ne %0 %1 : f32 -> i32
+    wasmssa.return %2 : i32
+  }
+  wasmssa.func nested @func_ne_f64() -> i32 {
+    %0 = wasmssa.const 1.700000e+01 : f64
+    %1 = wasmssa.const 0.000000e+00 : f64
+    %2 = wasmssa.ne %0 %1 : f64 -> i32
+    wasmssa.return %2 : i32
+  }
+}
+// CHECK-LABEL:   func.func @func_lt_si32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi slt, %[[VAL_0]], %[[VAL_1]] : i32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_le_si32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi sle, %[[VAL_0]], %[[VAL_1]] : i32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_lt_ui32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi ult, %[[VAL_0]], %[[VAL_1]] : i32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_le_ui32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi ule, %[[VAL_0]], %[[VAL_1]] : i32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_gt_si32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi sgt, %[[VAL_0]], %[[VAL_1]] : i32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_gt_ui32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi ugt, %[[VAL_0]], %[[VAL_1]] : i32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_ge_si32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi sge, %[[VAL_0]], %[[VAL_1]] : i32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_ge_ui32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi uge, %[[VAL_0]], %[[VAL_1]] : i32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_lt_si64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi slt, %[[VAL_0]], %[[VAL_1]] : i64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_le_si64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi sle, %[[VAL_0]], %[[VAL_1]] : i64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_lt_ui_i64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi ult, %[[VAL_0]], %[[VAL_1]] : i64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_le_ui_i64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi ule, %[[VAL_0]], %[[VAL_1]] : i64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_gt_si_i64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi sgt, %[[VAL_0]], %[[VAL_1]] : i64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_gt_ui_i64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi ugt, %[[VAL_0]], %[[VAL_1]] : i64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_ge_si_i64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi sge, %[[VAL_0]], %[[VAL_1]] : i64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_ge_ui_i64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi uge, %[[VAL_0]], %[[VAL_1]] : i64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_lt_f32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 5.000000e+00 : f32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 1.400000e+01 : f32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpf olt, %[[VAL_0]], %[[VAL_1]] : f32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_le_f32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 5.000000e+00 : f32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 1.400000e+01 : f32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpf ole, %[[VAL_0]], %[[VAL_1]] : f32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_gt_f32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 5.000000e+00 : f32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 1.400000e+01 : f32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpf ogt, %[[VAL_0]], %[[VAL_1]] : f32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_ge_f32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 5.000000e+00 : f32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 1.400000e+01 : f32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpf oge, %[[VAL_0]], %[[VAL_1]] : f32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_lt_f64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 5.000000e+00 : f64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 1.400000e+01 : f64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpf olt, %[[VAL_0]], %[[VAL_1]] : f64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_le_f64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 5.000000e+00 : f64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 1.400000e+01 : f64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpf ole, %[[VAL_0]], %[[VAL_1]] : f64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_gt_f64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 5.000000e+00 : f64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 1.400000e+01 : f64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpf ogt, %[[VAL_0]], %[[VAL_1]] : f64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_ge_f64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 5.000000e+00 : f64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 1.400000e+01 : f64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpf oge, %[[VAL_0]], %[[VAL_1]] : f64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_eq_i32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi eq, %[[VAL_0]], %[[VAL_1]] : i32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_eq_i64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 20 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 5 : i64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi eq, %[[VAL_0]], %[[VAL_1]] : i64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_eq_f32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 5.000000e+00 : f32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 1.400000e+01 : f32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpf oeq, %[[VAL_0]], %[[VAL_1]] : f32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_eq_f64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 1.700000e+01 : f64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 0.000000e+00 : f64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpf oeq, %[[VAL_0]], %[[VAL_1]] : f64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_ne_i32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 12 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 50 : i32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi ne, %[[VAL_0]], %[[VAL_1]] : i32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_ne_i64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 20 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 5 : i64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi ne, %[[VAL_0]], %[[VAL_1]] : i64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_ne_f32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 5.000000e+00 : f32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 1.400000e+01 : f32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpf one, %[[VAL_0]], %[[VAL_1]] : f32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @func_ne_f64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 1.700000e+01 : f64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 0.000000e+00 : f64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpf one, %[[VAL_0]], %[[VAL_1]] : f64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-eqz-to-arith-cmp.mlir b/mlir/test/Conversion/RaiseWasm/wasm-eqz-to-arith-cmp.mlir
new file mode 100644
index 0000000000000..083a24c5f36a8
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-eqz-to-arith-cmp.mlir
@@ -0,0 +1,28 @@
+// RUN: mlir-opt %s --raise-wasm-mlir | FileCheck %s
+
+module {
+  wasmssa.func @eqz_i32() -> i32 {
+    %0 = wasmssa.const 13 : i32
+    %1 = wasmssa.eqz %0 : i32 -> i32
+    wasmssa.return %1 : i32
+  }
+  wasmssa.func @eqz_i64() -> i32 {
+    %0 = wasmssa.const 13 : i64
+    %1 = wasmssa.eqz %0 : i64 -> i32
+    wasmssa.return %1 : i32
+  }
+}
+
+// CHECK-LABEL:   func.func @eqz_i32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 13 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 0 : i32
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi eq, %[[VAL_0]], %[[VAL_1]] : i32
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK-LABEL:   func.func @eqz_i64() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 13 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.constant 0 : i64
+// CHECK:           %[[VAL_2:.*]] = arith.cmpi eq, %[[VAL_0]], %[[VAL_1]] : i64
+// CHECK:           %[[VAL_3:.*]] = arith.extui %[[VAL_2]] : i1 to i32
+// CHECK:           return %[[VAL_3]] : i32

>From 49944e5c6ec9e356338dfaabbd248fb969ce49b8 Mon Sep 17 00:00:00 2001
From: Ferdinand Lemaire <ferdinand.lemaire at woven-planet.global>
Date: Thu, 3 Jul 2025 13:06:50 +0900
Subject: [PATCH 2/5] [mlir][wasm] RaiseWasmMLIRPass: Add rotl and extend
 support

--
 Co-authored-by: Luc Forget <luc.forget at woven-planet.global>
 Co-authored-by: Jessica Paquette <jessica.paquette at woven-planet.global>
---
 .../Conversion/RaiseWasm/RaiseWasmMLIR.cpp    | 87 +++++++++++++++++++
 .../RaiseWasm/wasm-extend-to-arith-ext.mlir   | 76 ++++++++++++++++
 .../RaiseWasm/wasm-rotl-to-arith.mlir         | 75 ++++++++++++++++
 .../RaiseWasm/wasm-rotr-to-arith.mlir         | 77 ++++++++++++++++
 4 files changed, 315 insertions(+)
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-extend-to-arith-ext.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-rotl-to-arith.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-rotr-to-arith.mlir

diff --git a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
index 1fb4564032421..bf958aad5012b 100644
--- a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
+++ b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
@@ -124,6 +124,72 @@ using WasmTruncOpConversion = OpMappingConversion<TruncOp, math::TruncOp>;
 using WasmSqrtOpConversion = OpMappingConversion<SqrtOp, math::SqrtOp>;
 using WasmWrapOpConversion = OpMappingConversion<WrapOp, arith::TruncIOp>;
 
+/// Lower a rotate to a series of bitwise operations. Intended for us
+/// in dialects that do not natively support rotate operations.
+///
+/// Result stays in the wasm dialect. It will then subsequently be lowered to
+/// the target dialect.
+///
+/// The rotate will be lowered to a pattern like so:
+///
+/// (val LHSShiftOp (bits & (width-1))) | (val RHSShiftOp (-bits & (width-1)))
+///
+/// Where LHSShiftOp and RHSShiftOp are shift operations. Concretely,
+///
+/// rotr = (val >> (bits & (width - 1))) | (val << (-bits & (width - 1)))
+/// rotl = (val << (bits & (width - 1))) | (val >> (-bits & (width - 1)))
+///
+/// Using this variant ensures that our rotate is defined in the target dialect.
+///
+/// \p SourceOp - Rotate operation to replace.
+/// \p LHSShiftOp - Shift operation to use on the left-hand side of the OR.
+/// \p RHSShiftOp - Shift operation to use on the right-hand side of the OR.
+template <typename SourceOp, typename LHSShiftOp, typename RHSShiftOp>
+struct RotateOpConversion : OpConversionPattern<SourceOp> {
+  using OpConversionPattern<SourceOp>::OpConversionPattern;
+
+  LogicalResult
+  matchAndRewrite(SourceOp srcOp, typename SourceOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    const Type ty = srcOp->getResultTypes()[0];
+    const Location loc = srcOp->getLoc();
+    const Value val = adaptor.getVal();
+    const Value bits = adaptor.getBits();
+    const unsigned width = ty.getIntOrFloatBitWidth();
+
+    // Materialize (width - 1) for use in both sides of the expression.
+    auto cstWidthMinusOne =
+        rewriter.create<ConstOp>(loc, IntegerAttr::get(ty, width - 1));
+
+    // Form the left-hand side of the OR:
+    // (val (lhs shift op) (bits & (width - 1)))
+    auto orLHS = rewriter.create<LHSShiftOp>(
+        loc, val, rewriter.create<AndOp>(loc, bits, cstWidthMinusOne));
+
+    // Form the right-hand side of the OR:
+    // (val (rhs shift op) (-bits & (width - 1)))
+    auto orRHS = rewriter.create<RHSShiftOp>(
+        loc, val,
+        // (-bits & (width - 1))
+        rewriter.create<AndOp>(
+            loc,
+            // 0 - bits == -bits
+            rewriter.create<SubOp>(
+                loc,
+                rewriter.create<ConstOp>(loc, IntegerAttr::get(ty, 0)),
+                bits),
+            cstWidthMinusOne));
+
+    // OR together the two shifts and replace the rotate with the new
+    // expression.
+    rewriter.replaceOpWithNewOp<OrOp>(srcOp, orLHS, orRHS);
+    return success();
+  }
+};
+
+using WasmRotrOpConversion = RotateOpConversion<RotrOp, ShRUOp, ShLOp>;
+using WasmRotlOpConversion = RotateOpConversion<RotlOp, ShLOp, ShRUOp>;
+
 template <typename SourceOp, typename TargetOp, typename AttrType,
           typename ValType, ValType flag>
 struct ComparisonOpConversion : OpConversionPattern<SourceOp> {
@@ -272,6 +338,24 @@ struct WasmEqzOpConversion : OpConversionPattern<EqzOp> {
   }
 };
 
+struct WasmExtendLowBitsOpConversion : OpConversionPattern<ExtendLowBitsSOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  LogicalResult
+  matchAndRewrite(ExtendLowBitsSOp extendLowBytesSOp,
+                  ExtendLowBitsSOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    auto truncWidth = extendLowBytesSOp.getBitsToTake().getInt();
+    auto truncation = rewriter.create<arith::TruncIOp>(
+        extendLowBytesSOp->getLoc(), rewriter.getIntegerType(truncWidth),
+        adaptor.getInput());
+    rewriter.replaceOpWithNewOp<arith::ExtSIOp>(
+        extendLowBytesSOp, extendLowBytesSOp.getResult().getType(),
+        truncation.getResult());
+    return success();
+  }
+};
+
 struct WasmFuncImportOpConversion : OpConversionPattern<FuncImportOp> {
   using OpConversionPattern::OpConversionPattern;
 
@@ -555,6 +639,7 @@ void mlir::populateRaiseWasmMLIRConversionPatterns(
            WasmDivUIOpConversion,
            WasmEqOpConversion,
            WasmEqzOpConversion,
+           WasmExtendLowBitsOpConversion,
            WasmExtendSOpConversion,
            WasmExtendUOpConversion,
            WasmFloorOpConversion,
@@ -591,6 +676,8 @@ void mlir::populateRaiseWasmMLIRConversionPatterns(
            WasmRemSIOpConversion,
            WasmRemUIOpConversion,
            WasmReturnOpConversion,
+           WasmRotlOpConversion,
+           WasmRotrOpConversion,
            WasmShLOpConversion,
            WasmShRSOpConversion,
            WasmShRUOpConversion,
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-extend-to-arith-ext.mlir b/mlir/test/Conversion/RaiseWasm/wasm-extend-to-arith-ext.mlir
new file mode 100644
index 0000000000000..90c92001a78d6
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-extend-to-arith-ext.mlir
@@ -0,0 +1,76 @@
+// RUN: mlir-opt %s --raise-wasm-mlir | FileCheck %s
+
+// CHECK-LABEL:   func.func @func_0() -> i64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 10 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.extsi %[[VAL_0]] : i32 to i64
+// CHECK:           return %[[VAL_1]] : i64
+wasmssa.func nested @func_0() -> i64 {
+  %0 = wasmssa.const 10 : i32
+  %1 = wasmssa.extend_i32_s %0 to i64
+  wasmssa.return %1 : i64
+}
+
+// CHECK-LABEL:   func.func @func_1() -> i64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 10 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.extui %[[VAL_0]] : i32 to i64
+// CHECK:           return %[[VAL_1]] : i64
+wasmssa.func nested @func_1() -> i64 {
+  %0 = wasmssa.const 10 : i32
+  %1 = wasmssa.extend_i32_u %0 to i64
+  wasmssa.return %1 : i64
+}
+
+// CHECK-LABEL:   func.func @func_2() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 10 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.trunci %[[VAL_0]] : i32 to i8
+// CHECK:           %[[VAL_2:.*]] = arith.extsi %[[VAL_1]] : i8 to i32
+// CHECK:           return %[[VAL_2]] : i32
+wasmssa.func nested @func_2() -> i32 {
+  %0 = wasmssa.const 10 : i32
+  %1 = wasmssa.extend 8 low bits from %0: i32
+  wasmssa.return %1 : i32
+}
+
+// CHECK-LABEL:   func.func @func_3() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 10 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.trunci %[[VAL_0]] : i32 to i16
+// CHECK:           %[[VAL_2:.*]] = arith.extsi %[[VAL_1]] : i16 to i32
+// CHECK:           return %[[VAL_2]] : i32
+wasmssa.func nested @func_3() -> i32 {
+  %0 = wasmssa.const 10 : i32
+  %1 = wasmssa.extend 16 low bits from %0: i32
+  wasmssa.return %1 : i32
+}
+
+// CHECK-LABEL:   func.func @func_4() -> i64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 10 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.trunci %[[VAL_0]] : i64 to i8
+// CHECK:           %[[VAL_2:.*]] = arith.extsi %[[VAL_1]] : i8 to i64
+// CHECK:           return %[[VAL_2]] : i64
+wasmssa.func nested @func_4() -> i64 {
+  %0 = wasmssa.const 10 : i64
+  %1 = wasmssa.extend 8 low bits from %0: i64
+  wasmssa.return %1 : i64
+}
+
+// CHECK-LABEL:   func.func @func_5() -> i64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 10 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.trunci %[[VAL_0]] : i64 to i16
+// CHECK:           %[[VAL_2:.*]] = arith.extsi %[[VAL_1]] : i16 to i64
+// CHECK:           return %[[VAL_2]] : i64
+wasmssa.func nested @func_5() -> i64 {
+  %0 = wasmssa.const 10 : i64
+  %1 = wasmssa.extend 16 low bits from %0: i64
+  wasmssa.return %1 : i64
+}
+
+// CHECK-LABEL:   func.func @func_6() -> i64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 10 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.trunci %[[VAL_0]] : i64 to i32
+// CHECK:           %[[VAL_2:.*]] = arith.extsi %[[VAL_1]] : i32 to i64
+// CHECK:           return %[[VAL_2]] : i64
+wasmssa.func nested @func_6() -> i64 {
+  %0 = wasmssa.const 10 : i64
+  %1 = wasmssa.extend 32 low bits from %0: i64
+  wasmssa.return %1 : i64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-rotl-to-arith.mlir b/mlir/test/Conversion/RaiseWasm/wasm-rotl-to-arith.mlir
new file mode 100644
index 0000000000000..91e929bd5ff35
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-rotl-to-arith.mlir
@@ -0,0 +1,75 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+// Given:
+// %res = wasmssa.rotl %val by %bits bits : i32
+//
+// Produce:
+// res = (val >> (bits & 31)) | (val << (-bits & 31))
+
+// CHECK-LABEL:   func.func @rotl_i32(
+// CHECK-SAME:      %[[VALREF:.*]]: i32,
+// CHECK-SAME:      %[[BITSREF:.*]]: i32) -> i32 {
+
+// Storage etc
+// CHECK-DAG:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK-DAG:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK-DAG:           memref.store %[[VALREF]], %[[VAL_0]][] : memref<i32>
+// CHECK-DAG:           memref.store %[[BITSREF]], %[[VAL_1]][] : memref<i32>
+// CHECK-DAG:           %[[VAL:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK-DAG:           %[[BITS:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+
+// (val << (bits & 31))
+// CHECK:           %[[THIRTY_ONE:.*]] = arith.constant 31 : i32
+// CHECK:           %[[LHS_AND:.*]] = arith.andi %[[BITS]], %[[THIRTY_ONE]] : i32
+// CHECK:           %[[SHRU:.*]] = arith.shli %[[VAL]], %[[LHS_AND]] : i32
+
+// (val >> (-bits & 31))
+// CHECK:           %[[ZERO:.*]] = arith.constant 0 : i32
+// CHECK:           %[[NEG_BITS:.*]] = arith.subi %[[ZERO]], %[[BITS]] : i32
+// CHECK:           %[[RHS_AND:.*]] = arith.andi %[[NEG_BITS]], %[[THIRTY_ONE]] : i32
+// CHECK:           %[[SHL:.*]] = arith.shrui %[[VAL]], %[[RHS_AND]] : i32
+
+// CHECK:           %[[RES:.*]] = arith.ori %[[SHRU]], %[[SHL]] : i32
+// CHECK:           return %[[RES]] : i32
+wasmssa.func nested @rotl_i32(%arg0: !wasmssa<local ref to i32>, %arg1: !wasmssa<local ref to i32>) -> i32 {
+    %v0 = wasmssa.local_get %arg0 : ref to i32
+    %v1 = wasmssa.local_get %arg1 : ref to i32
+
+    %op = wasmssa.rotl %v0 by %v1 bits : i32
+    wasmssa.return %op : i32
+}
+
+// Same as above, but with 64 bits.
+// CHECK-LABEL:   func.func @rotl_i64(
+// CHECK-SAME:      %[[VALREF:.*]]: i64,
+// CHECK-SAME:      %[[BITSREF:.*]]: i64) -> i64 {
+
+// Storage etc
+// CHECK-DAG:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK-DAG:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK-DAG:           memref.store %[[VALREF]], %[[VAL_0]][] : memref<i64>
+// CHECK-DAG:           memref.store %[[BITSREF]], %[[VAL_1]][] : memref<i64>
+// CHECK-DAG:           %[[VAL:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+// CHECK-DAG:           %[[BITS:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+
+// (val << (bits & 63))
+// CHECK:           %[[SIXTY_THREE:.*]] = arith.constant 63 : i64
+// CHECK:           %[[LHS_AND:.*]] = arith.andi %[[BITS]], %[[SIXTY_THREE]] : i64
+// CHECK:           %[[SHRU:.*]] = arith.shli %[[VAL]], %[[LHS_AND]] : i64
+
+// (val >> (-bits & 63))
+// CHECK:           %[[ZERO:.*]] = arith.constant 0 : i64
+// CHECK:           %[[NEG_BITS:.*]] = arith.subi %[[ZERO]], %[[BITS]] : i64
+// CHECK:           %[[RHS_AND:.*]] = arith.andi %[[NEG_BITS]], %[[SIXTY_THREE]] : i64
+// CHECK:           %[[SHL:.*]] = arith.shrui %[[VAL]], %[[RHS_AND]] : i64
+
+// Form final result.
+// CHECK:           %[[RES:.*]] = arith.ori %[[SHRU]], %[[SHL]] : i64
+// CHECK:           return %[[RES]] : i64
+wasmssa.func nested @rotl_i64(%arg0: !wasmssa<local ref to i64>, %arg1: !wasmssa<local ref to i64>) -> i64 {
+    %v0 = wasmssa.local_get %arg0 : ref to i64
+    %v1 = wasmssa.local_get %arg1 : ref to i64
+
+    %op = wasmssa.rotl %v0 by %v1 bits : i64
+    wasmssa.return %op : i64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-rotr-to-arith.mlir b/mlir/test/Conversion/RaiseWasm/wasm-rotr-to-arith.mlir
new file mode 100644
index 0000000000000..77e301c3221e3
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-rotr-to-arith.mlir
@@ -0,0 +1,77 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+// Given:
+// %res = wasmssa.rotr %val by %bits bits : i32
+//
+// Produce:
+// res = (val >> (bits & 31)) | (val << (-bits & 31))
+
+// CHECK-LABEL:   func.func @rotr_i32(
+// CHECK-SAME:      %[[VALREF:.*]]: i32,
+// CHECK-SAME:      %[[BITSREF:.*]]: i32) -> i32 {
+
+// Storage etc
+// CHECK-DAG:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK-DAG:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK-DAG:           memref.store %[[VALREF]], %[[VAL_0]][] : memref<i32>
+// CHECK-DAG:           memref.store %[[BITSREF]], %[[VAL_1]][] : memref<i32>
+// CHECK-DAG:           %[[VAL:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK-DAG:           %[[BITS:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+
+// (val >> (bits & 31))
+// CHECK:           %[[THIRTY_ONE:.*]] = arith.constant 31 : i32
+// CHECK:           %[[LHS_AND:.*]] = arith.andi %[[BITS]], %[[THIRTY_ONE]] : i32
+// CHECK:           %[[SHRU:.*]] = arith.shrui %[[VAL]], %[[LHS_AND]] : i32
+
+// (val << (-bits & 31))
+// CHECK:           %[[ZERO:.*]] = arith.constant 0 : i32
+// CHECK:           %[[NEG_BITS:.*]] = arith.subi %[[ZERO]], %[[BITS]] : i32
+// CHECK:           %[[RHS_AND:.*]] = arith.andi %[[NEG_BITS]], %[[THIRTY_ONE]] : i32
+// CHECK:           %[[SHL:.*]] = arith.shli %[[VAL]], %[[RHS_AND]] : i32
+
+// CHECK:           %[[RES:.*]] = arith.ori %[[SHRU]], %[[SHL]] : i32
+// CHECK:           return %[[RES]] : i32
+// CHECK:         }
+wasmssa.func nested @rotr_i32(%arg0: !wasmssa<local ref to i32>, %arg1: !wasmssa<local ref to i32>) -> i32 {
+    %v0 = wasmssa.local_get %arg0 : ref to i32
+    %v1 = wasmssa.local_get %arg1 : ref to i32
+
+    %op = wasmssa.rotr %v0 by %v1 bits : i32
+    wasmssa.return %op : i32
+}
+
+// Same as above, but with 64 bits.
+// CHECK-LABEL:   func.func @rotr_i64(
+// CHECK-SAME:      %[[VALREF:.*]]: i64,
+// CHECK-SAME:      %[[BITSREF:.*]]: i64) -> i64 {
+
+// Storage etc
+// CHECK-DAG:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK-DAG:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK-DAG:           memref.store %[[VALREF]], %[[VAL_0]][] : memref<i64>
+// CHECK-DAG:           memref.store %[[BITSREF]], %[[VAL_1]][] : memref<i64>
+// CHECK-DAG:           %[[VAL:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+// CHECK-DAG:           %[[BITS:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+
+// (val >> (bits & 63))
+// CHECK:           %[[SIXTY_THREE:.*]] = arith.constant 63 : i64
+// CHECK:           %[[LHS_AND:.*]] = arith.andi %[[BITS]], %[[SIXTY_THREE]] : i64
+// CHECK:           %[[SHRU:.*]] = arith.shrui %[[VAL]], %[[LHS_AND]] : i64
+
+// (val << (-bits & 63))
+// CHECK:           %[[ZERO:.*]] = arith.constant 0 : i64
+// CHECK:           %[[NEG_BITS:.*]] = arith.subi %[[ZERO]], %[[BITS]] : i64
+// CHECK:           %[[RHS_AND:.*]] = arith.andi %[[NEG_BITS]], %[[SIXTY_THREE]] : i64
+// CHECK:           %[[SHL:.*]] = arith.shli %[[VAL]], %[[RHS_AND]] : i64
+
+// Form final result.
+// CHECK:           %[[RES:.*]] = arith.ori %[[SHRU]], %[[SHL]] : i64
+// CHECK:           return %[[RES]] : i64
+// CHECK:         }
+wasmssa.func nested @rotr_i64(%arg0: !wasmssa<local ref to i64>, %arg1: !wasmssa<local ref to i64>) -> i64 {
+    %v0 = wasmssa.local_get %arg0 : ref to i64
+    %v1 = wasmssa.local_get %arg1 : ref to i64
+
+    %op = wasmssa.rotr %v0 by %v1 bits : i64
+    wasmssa.return %op : i64
+}

>From 6431a7494a5edc89de997962d92b1803d6aed43f Mon Sep 17 00:00:00 2001
From: Ferdinand Lemaire <ferdinand.lemaire at woven-planet.global>
Date: Thu, 3 Jul 2025 13:24:21 +0900
Subject: [PATCH 3/5] [mlir][wasm] RaiseWasmMLIRPass: Add support for control
 flow operations in functions

--
 Co-authored-by: Luc Forget <luc.forget at woven-planet.global>
 Co-authored-by: Jessica Paquette <jessica.paquette at woven-planet.global>
---
 .../Conversion/RaiseWasm/RaiseWasmMLIR.cpp    | 184 ++++++++-
 .../RaiseWasm/wasm-blocks-to-cf.mlir          | 366 ++++++++++++++++++
 .../Conversion/RaiseWasm/wasm-loop-to-cf.mlir | 206 ++++++++++
 3 files changed, 755 insertions(+), 1 deletion(-)
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-blocks-to-cf.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-loop-to-cf.mlir

diff --git a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
index bf958aad5012b..d9dcb756790f8 100644
--- a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
+++ b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
@@ -371,6 +371,187 @@ struct WasmFuncImportOpConversion : OpConversionPattern<FuncImportOp> {
 
 struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
   using OpConversionPattern::OpConversionPattern;
+  ///
+  /// Control flow conversion needs shared state for tracking which block
+  /// corresponds to which operation at which level.
+  ///
+  /// This class handles such tracking and performs the conversion of control
+  /// flow related ops contained in a function.
+  class CFRewriterVisitor {
+  private:
+    using branch_to_dest_t =
+        llvm::DenseMap<WasmSSALabelBranchingInterface, Block *>;
+    Value getCompResultAsI1(Value compResult,
+                            ConversionPatternRewriter &rewriter) {
+      auto testValue = rewriter.create<arith::ConstantOp>(
+          compResult.getLoc(), rewriter.getI32IntegerAttr(0));
+      auto flag = rewriter
+                      .create<arith::CmpIOp>(
+                          compResult.getLoc(), rewriter.getIntegerType(1),
+                          arith::CmpIPredicate::ne, compResult, testValue)
+                      .getResult();
+      return flag;
+    }
+
+    void replaceNestLevelWithBranch(BlockOp blockOp,
+                                    llvm::ArrayRef<Block *> regionsToEntry,
+                                    ConversionPatternRewriter &rewriter) {
+      rewriter.replaceOpWithNewOp<cf::BranchOp>(blockOp, regionsToEntry[0],
+                                                blockOp->getOperands());
+    }
+
+    void replaceNestLevelWithBranch(LoopOp loopOp,
+                                    llvm::ArrayRef<Block *> regionsToEntry,
+                                    ConversionPatternRewriter &rewriter) {
+      rewriter.replaceOpWithNewOp<cf::BranchOp>(loopOp, regionsToEntry[0],
+                                                loopOp->getOperands());
+    }
+
+    void replaceNestLevelWithBranch(IfOp ifOp,
+                                    llvm::ArrayRef<Block *> regionsToEntry,
+                                    ConversionPatternRewriter &rewriter) {
+      Block *falseDest =
+          regionsToEntry.size() == 2 ? regionsToEntry[1] : ifOp.getTarget();
+      auto flag = getCompResultAsI1(ifOp.getCondition(), rewriter);
+      rewriter.replaceOpWithNewOp<cf::CondBranchOp>(
+          ifOp, flag, regionsToEntry[0], ifOp.getInputs(), falseDest,
+          ifOp.getInputs());
+    }
+
+    template <typename LevelType>
+    LogicalResult
+    replaceNestLevelWithBranchWrapper(WasmSSALabelLevelInterface nestingOp,
+                                      llvm::ArrayRef<Block *> regionsToEntry,
+                                      ConversionPatternRewriter &rewriter) {
+      auto cast = dyn_cast<LevelType>(nestingOp.getOperation());
+      if (!cast)
+        return failure();
+      replaceNestLevelWithBranch(cast, regionsToEntry, rewriter);
+      return success();
+    }
+
+    template <typename... LevelTypes>
+    LogicalResult inlineNestDispatcher(WasmSSALabelLevelInterface nestingOp,
+                                       ConversionPatternRewriter &rewriter) {
+      auto sip = rewriter.saveInsertionPoint();
+      Block *blockSuccessor = nestingOp->getSuccessor(0);
+      llvm::SmallVector<Block *, 2> regionEntries;
+      LLVM_DEBUG(llvm::dbgs()
+                     << "Starting inlining blocks for " << nestingOp << "\n";);
+      for (auto &region : nestingOp->getRegions()) {
+        if (region.empty())
+          continue;
+        regionEntries.push_back(&region.front());
+        /// Inline blocks of nested ops
+        llvm::SmallVector<WasmSSALabelLevelInterface> nestedOps{
+            region.getOps<WasmSSALabelLevelInterface>()};
+        for (auto nestedOp : nestedOps) {
+          LLVM_DEBUG(llvm::dbgs() << " Found nested op: " << nestedOp);
+          if (failed(inlineBlocks(nestedOp, rewriter)))
+            return failure();
+        }
+        rewriter.inlineRegionBefore(region, blockSuccessor);
+      }
+      LLVM_DEBUG(llvm::dbgs() << "End of region inlining\n");
+      LLVM_DEBUG(llvm::dbgs() << "Replacing initial op with branching\n");
+      rewriter.setInsertionPoint(nestingOp);
+      auto res = success(
+          (... || succeeded(replaceNestLevelWithBranchWrapper<LevelTypes>(
+                      nestingOp, regionEntries, rewriter))));
+      rewriter.restoreInsertionPoint(sip);
+      if (failed(res))
+        return emitError(nestingOp->getLoc(),
+                         "Unable to inline the operation regions.");
+      return success();
+    }
+
+    /// Take a nesting level defining op and inline it in the parent region.
+    LogicalResult inlineBlocks(WasmSSALabelLevelInterface nestingOp,
+                               ConversionPatternRewriter &rewriter) {
+      return inlineNestDispatcher<BlockOp, IfOp, LoopOp>(nestingOp, rewriter);
+    }
+
+    llvm::FailureOr<Block *> getBlockFor(WasmSSALabelBranchingInterface branchOp) {
+      auto destIter = branchToDest.find(branchOp);
+      if (destIter == branchToDest.end())
+        return branchOp->emitError("No indexed label op for this operation: ")
+               << branchOp;
+      return destIter->second;
+    }
+
+    inline void convertBranch(BranchIfOp brOp, Block *dest,
+                              ConversionPatternRewriter &rewriter) {
+      auto flag = getCompResultAsI1(brOp.getCondition(), rewriter);
+      rewriter.replaceOpWithNewOp<cf::CondBranchOp>(
+          brOp, flag, dest, brOp.getInputs(), brOp.getElseSuccessor(),
+          ValueRange{});
+    }
+
+    inline void convertBranch(BlockReturnOp brOp, Block *dest,
+                              ConversionPatternRewriter &rewriter) {
+      rewriter.replaceOpWithNewOp<cf::BranchOp>(brOp, dest, brOp.getInputs());
+    }
+
+    template <typename LevelInterfaceT>
+    inline LogicalResult
+    convertBranchWrapper(WasmSSALabelBranchingInterface branchOp, Block *dest,
+                         ConversionPatternRewriter &rewriter) {
+      auto cast = dyn_cast<LevelInterfaceT>(branchOp.getOperation());
+      if (!cast)
+        return failure();
+      auto sip = rewriter.saveInsertionPoint();
+      rewriter.setInsertionPoint(branchOp);
+      convertBranch(cast, dest, rewriter);
+      rewriter.restoreInsertionPoint(sip);
+      return success();
+    }
+
+    template <typename... BranchInterfaceT>
+    LogicalResult convertBranchDispatch(WasmSSALabelBranchingInterface branchOp,
+                                        ConversionPatternRewriter &rewriter) {
+      auto dest = getBlockFor(branchOp);
+      if (failed(dest))
+        return failure();
+      auto res =
+          success((... || succeeded(convertBranchWrapper<BranchInterfaceT>(
+                              branchOp, *dest, rewriter))));
+      if (failed(res))
+        return emitError(branchOp->getLoc(), "No known converter for op ")
+               << branchOp;
+      return res;
+    }
+
+    LogicalResult convertBranch(WasmSSALabelBranchingInterface branchOp,
+                                ConversionPatternRewriter &rewriter) {
+      return convertBranchDispatch<BlockReturnOp, BranchIfOp>(branchOp,
+                                                              rewriter);
+    }
+
+    func::FuncOp func;
+    branch_to_dest_t branchToDest;
+
+  public:
+    CFRewriterVisitor(func::FuncOp func) : func{func} {
+      func.walk([this](WasmSSALabelBranchingInterface branchOp) {
+        branchToDest.insert({branchOp, branchOp.getTarget()});
+      });
+    }
+    LogicalResult rewrite(ConversionPatternRewriter &rewriter) {
+      llvm::SmallVector<WasmSSALabelLevelInterface> nestingOps{
+          func.getOps<WasmSSALabelLevelInterface>()};
+      for (auto nestingOp : nestingOps)
+        if (failed(inlineBlocks(nestingOp, rewriter)))
+          return failure();
+
+      auto res =
+          func->walk([this, &rewriter](WasmSSALabelBranchingInterface branchOp) {
+            if (failed(convertBranch(branchOp, rewriter)))
+              return WalkResult::interrupt();
+            return WalkResult::advance();
+          });
+      return failure(res.wasInterrupted());
+    }
+  };
 
   LogicalResult
   matchAndRewrite(FuncOp funcOp, FuncOp::Adaptor adaptor,
@@ -393,7 +574,8 @@ struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
 
     rewriter.applySignatureConversion(oldEntryBlock, sC, getTypeConverter());
     rewriter.replaceOp(funcOp, newFunc);
-    return success();
+    CFRewriterVisitor cfRewriter{newFunc};
+    return cfRewriter.rewrite(rewriter);
   }
 };
 
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-blocks-to-cf.mlir b/mlir/test/Conversion/RaiseWasm/wasm-blocks-to-cf.mlir
new file mode 100644
index 0000000000000..3b275573bcbd3
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-blocks-to-cf.mlir
@@ -0,0 +1,366 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir --canonicalize -o - | FileCheck --check-prefix=CHECK_CANONICALIZED %s
+
+// CHECK-LABEL:   func.func @i_am_a_block(
+// CHECK-SAME:      %[[ARG0:.*]]: i32) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = arith.constant 17 : i32
+// CHECK:           memref.store %[[VAL_1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           cf.br ^bb1
+// CHECK:         ^bb1:
+// CHECK:           %[[VAL_2:.*]] = arith.constant 42 : i32
+// CHECK:           memref.store %[[VAL_2]], %[[VAL_0]][] : memref<i32>
+// CHECK:           cf.br ^bb2
+// CHECK:         ^bb2:
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           return %[[VAL_3]] : i32
+
+// CHECK_CANONICALIZED-LABEL:   func.func @i_am_a_block(
+// CHECK_CANONICALIZED-SAME:      %[[VAL_0:.*]]: i32) -> i32 {
+// CHECK_CANONICALIZED:           %[[VAL_1:.*]] = arith.constant 42 : i32
+// CHECK_CANONICALIZED:           %[[VAL_3:.*]] = memref.alloca() : memref<i32>
+// CHECK_CANONICALIZED:           memref.store %[[VAL_1]], %[[VAL_3]][] : memref<i32>
+// CHECK_CANONICALIZED-NOT:       memref.store
+// CHECK_CANONICALIZED:           %[[VAL_4:.*]] = memref.load %[[VAL_3]][] : memref<i32>
+// CHECK_CANONICALIZED:           return %[[VAL_4]] : i32
+wasmssa.func @i_am_a_block(%arg0 : !wasmssa<local ref to i32>) -> i32 {
+  %1 = wasmssa.const 17 : i32
+  wasmssa.local_set %arg0 : ref to i32 to %1 : i32
+  wasmssa.block : {
+    %2 = wasmssa.const 42 : i32
+    wasmssa.local_set %arg0 : ref to i32 to %2 : i32
+    wasmssa.block_return
+  }> ^bb1
+  ^bb1:
+  %res = wasmssa.local_get %arg0 : ref to i32
+  wasmssa.return %res : i32
+}
+
+
+// CHECK-LABEL:   func.func @func_0(
+// CHECK-SAME:                      %[[ARG0:.*]]: i32) {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 1 : i32
+// CHECK:           cf.br ^bb1
+// CHECK:         ^bb1:
+// CHECK:           %[[VAL_1:.*]] = arith.constant 2 : i32
+// CHECK:           cf.br ^bb2
+// CHECK:         ^bb2:
+// CHECK:           %[[VAL_2:.*]] = arith.constant 3 : i32
+// CHECK:           cf.br ^bb3
+// CHECK:         ^bb3:
+// CHECK:           %[[VAL_3:.*]] = arith.constant 4 : i32
+// CHECK:           cf.br ^bb4
+// CHECK:         ^bb4:
+// CHECK:           %[[VAL_4:.*]] = arith.constant 5 : i32
+// CHECK:           cf.br ^bb5
+// CHECK:         ^bb5:
+// CHECK:           %[[VAL_5:.*]] = arith.constant 6 : i32
+// CHECK:           cf.br ^bb6
+// CHECK:         ^bb6:
+// CHECK:           %[[VAL_6:.*]] = arith.constant 7 : i32
+// CHECK:           return
+wasmssa.func nested @func_0(%arg0: !wasmssa<local ref to i32>) {
+  %1 = wasmssa.const 1: i32
+  wasmssa.block : {
+    %2 = wasmssa.const 2: i32
+    wasmssa.block : {
+      %3 = wasmssa.const 3: i32
+      wasmssa.block : {
+        %4 = wasmssa.const 4: i32
+        wasmssa.block_return
+      }> ^bb1
+    ^bb1:  // pred: ^bb0
+      %5 = wasmssa.const 5: i32
+      wasmssa.block_return
+    }> ^bb1
+  ^bb1:  // pred: ^bb0
+    %6 = wasmssa.const 6: i32
+    wasmssa.block_return
+  }> ^bb1
+^bb1:  // pred: ^bb0
+  %7 = wasmssa.const 7: i32
+  wasmssa.return
+}
+
+// CHECK-LABEL:   func.func @func_1() {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 1 : i32
+// CHECK:           cf.br ^bb1
+// CHECK:         ^bb1:
+// CHECK:           %[[VAL_1:.*]] = arith.constant 2 : i32
+// CHECK:           cf.br ^bb2
+// CHECK:         ^bb2:
+// CHECK:           %[[VAL_2:.*]] = arith.constant 3 : i32
+// CHECK:           cf.br ^bb3
+// CHECK:         ^bb3:
+// CHECK:           %[[VAL_3:.*]] = arith.constant 4 : i32
+// CHECK:           cf.br ^bb4
+// CHECK:         ^bb4:
+// CHECK:           %[[VAL_4:.*]] = arith.constant 5 : i32
+// CHECK:           cf.br ^bb5
+// CHECK:         ^bb5:
+// CHECK:           %[[VAL_5:.*]] = arith.constant 6 : i32
+// CHECK:           cf.br ^bb6
+// CHECK:         ^bb6:
+// CHECK:           %[[VAL_6:.*]] = arith.constant 7 : i32
+// CHECK:           return
+wasmssa.func nested @func_1() {
+  %1 = wasmssa.const 1: i32
+  wasmssa.block : {
+    %2 = wasmssa.const 2: i32
+    wasmssa.block_return
+  }> ^bb1
+^bb1:  // pred: ^bb0
+  %3 = wasmssa.const 3: i32
+  wasmssa.block : {
+    %4 = wasmssa.const 4: i32
+    wasmssa.block_return
+  }> ^bb2
+^bb2:  // pred: ^bb1
+  %5 = wasmssa.const 5: i32
+  wasmssa.block : {
+    %6 = wasmssa.const 6: i32
+    wasmssa.block_return
+  }> ^bb3
+^bb3:  // pred: ^bb2
+  %7 = wasmssa.const 7: i32
+  wasmssa.return
+}
+
+// CHECK-LABEL:   func.func @func_2() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 14 : i32
+// CHECK:           cf.br ^bb1(%[[VAL_0]] : i32)
+// CHECK:         ^bb1(%[[VAL_1:.*]]: i32):
+// CHECK:           %[[VAL_2:.*]] = arith.constant 1 : i32
+// CHECK:           %[[VAL_3:.*]] = arith.addi %[[VAL_1]], %[[VAL_2]] : i32
+// CHECK:           cf.br ^bb2(%[[VAL_3]] : i32)
+// CHECK:         ^bb2(%[[VAL_4:.*]]: i32):
+// CHECK:           return %[[VAL_4]] : i32
+wasmssa.func nested @func_2() -> i32 {
+  %0 = wasmssa.const 14 : i32
+  wasmssa.block(%0) : i32 : {
+  ^bb0(%arg0: i32):
+    %2 = wasmssa.const 1 : i32
+    %3 = wasmssa.add %arg0 %2 : i32
+    wasmssa.block_return %3 : i32
+  }> ^bb1
+^bb1(%arg0: i32):
+  wasmssa.return %arg0 : i32
+}
+
+// CHECK-LABEL:   func.func @func_3() -> i32 {
+// CHECK:           cf.br ^bb1
+// CHECK:         ^bb1:
+// CHECK:           %[[VAL_0:.*]] = arith.constant 17 : i32
+// CHECK:           cf.br ^bb2(%[[VAL_0]] : i32)
+// CHECK:         ^bb2(%[[VAL_1:.*]]: i32):
+// CHECK:           return %[[VAL_1]] : i32
+wasmssa.func nested @func_3() -> i32 {
+  wasmssa.block : {
+    %1 = wasmssa.const 17 : i32
+    wasmssa.block_return %1 : i32
+  }> ^bb1
+^bb1(%arg0: i32):
+  wasmssa.return %arg0 : i32
+}
+
+//// ============= Branch instructions etc ==========
+
+// CHECK-LABEL:   func.func @branch_if_taken() -> i32 {
+// CHECK:           cf.br ^bb1
+// CHECK:         ^bb1:
+// CHECK:           %[[VAL_0:.*]] = arith.constant 1 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 2 : i32
+// CHECK:           %[[VAL_2:.*]] = arith.constant 0 : i32
+// CHECK:           %[[VAL_3:.*]] = arith.cmpi ne, %[[VAL_1]], %[[VAL_2]] : i32
+// CHECK:           cf.cond_br %[[VAL_3]], ^bb3(%[[VAL_0]] : i32), ^bb2
+// CHECK:         ^bb2:
+// CHECK:           %[[VAL_4:.*]] = arith.constant 16 : i32
+// CHECK:           %[[VAL_5:.*]] = arith.addi %[[VAL_0]], %[[VAL_4]] : i32
+// CHECK:           cf.br ^bb3(%[[VAL_5]] : i32)
+// CHECK:         ^bb3(%[[VAL_6:.*]]: i32):
+// CHECK:           return %[[VAL_6]] : i32
+
+// CHECK_CANONICALIZED-LABEL:   func.func @branch_if_taken() -> i32 {
+// CHECK_CANONICALIZED:           %[[VAL_0:.*]] = arith.constant 1 : i32
+// CHECK_CANONICALIZED:           return %[[VAL_0]] : i32
+
+wasmssa.func nested @branch_if_taken() -> i32 {
+  wasmssa.block : {
+    %1 = wasmssa.const 1 : i32
+    %2 = wasmssa.const 2 : i32
+    wasmssa.branch_if %2 to level 0 with args(%1 : i32) else ^bb1
+  ^bb1:  // pred: ^bb0
+    %3 = wasmssa.const 16 : i32
+    %4 = wasmssa.add %1 %3 : i32
+    wasmssa.block_return %4 : i32
+  }> ^bb1
+^bb1(%0: i32):  // pred: ^bb0
+  wasmssa.return %0 : i32
+}
+
+// CHECK-LABEL:   func.func @branch_if_continue() -> i32 {
+// CHECK:           cf.br ^bb1
+// CHECK:         ^bb1:
+// CHECK:           %[[VAL_0:.*]] = arith.constant 1 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.constant 0 : i32
+// CHECK:           %[[VAL_2:.*]] = arith.constant 0 : i32
+// CHECK:           %[[VAL_3:.*]] = arith.cmpi ne, %[[VAL_1]], %[[VAL_2]] : i32
+// CHECK:           cf.cond_br %[[VAL_3]], ^bb3(%[[VAL_0]] : i32), ^bb2
+// CHECK:         ^bb2:
+// CHECK:           %[[VAL_4:.*]] = arith.constant 16 : i32
+// CHECK:           %[[VAL_5:.*]] = arith.addi %[[VAL_0]], %[[VAL_4]] : i32
+// CHECK:           cf.br ^bb3(%[[VAL_5]] : i32)
+// CHECK:         ^bb3(%[[VAL_6:.*]]: i32):
+// CHECK:           return %[[VAL_6]] : i32
+
+// CHECK_CANONICALIZED-LABEL:   func.func @branch_if_continue() -> i32 {
+// CHECK_CANONICALIZED:           %[[VAL_0:.*]] = arith.constant 17 : i32
+// CHECK_CANONICALIZED:           return %[[VAL_0]] : i32
+// CHECK_CANONICALIZED:         }
+wasmssa.func nested @branch_if_continue() -> i32 {
+  wasmssa.block : {
+    %1 = wasmssa.const 1 : i32
+    %2 = wasmssa.const 0 : i32
+    wasmssa.branch_if %2 to level 0 with args(%1 : i32) else ^bb1
+  ^bb1:  // pred: ^bb0
+    %3 = wasmssa.const 16 : i32
+    %4 = wasmssa.add %1 %3 : i32
+    wasmssa.block_return %4 : i32
+  }> ^bb1
+^bb1(%0: i32):  // pred: ^bb0
+  wasmssa.return %0 : i32
+}
+
+// CHECK-LABEL:   func.func @if(
+// CHECK-SAME:                  %[[ARG0:.*]]: i32) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = arith.constant 1 : i32
+// CHECK:           %[[VAL_3:.*]] = arith.andi %[[VAL_1]], %[[VAL_2]] : i32
+// CHECK:           %[[VAL_4:.*]] = arith.constant 0 : i32
+// CHECK:           %[[VAL_5:.*]] = arith.cmpi ne, %[[VAL_3]], %[[VAL_4]] : i32
+// CHECK:           cf.cond_br %[[VAL_5]], ^bb1, ^bb2
+// CHECK:         ^bb1:
+// CHECK:           %[[VAL_6:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_7:.*]] = arith.constant 3 : i32
+// CHECK:           %[[VAL_8:.*]] = arith.muli %[[VAL_6]], %[[VAL_7]] : i32
+// CHECK:           %[[VAL_9:.*]] = arith.constant 1 : i32
+// CHECK:           %[[VAL_10:.*]] = arith.addi %[[VAL_8]], %[[VAL_9]] : i32
+// CHECK:           cf.br ^bb3(%[[VAL_10]] : i32)
+// CHECK:         ^bb2:
+// CHECK:           %[[VAL_11:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_12:.*]] = arith.constant 1 : i32
+// CHECK:           %[[VAL_13:.*]] = arith.shrui %[[VAL_11]], %[[VAL_12]] : i32
+// CHECK:           cf.br ^bb3(%[[VAL_13]] : i32)
+// CHECK:         ^bb3(%[[VAL_14:.*]]: i32):
+// CHECK:           return %[[VAL_14]] : i32
+wasmssa.func nested @if(%arg0: !wasmssa<local ref to i32>) -> i32 {
+  %1 = wasmssa.local_get %arg0 : ref to i32
+  %2 = wasmssa.const 1 : i32
+  %3 = wasmssa.and %1 %2 : i32
+  "wasmssa.if"(%3)[^bb1] ({
+    %5 = wasmssa.local_get %arg0 : ref to i32
+    %6 = wasmssa.const 3 : i32
+    %7 = wasmssa.mul %5 %6 : i32
+    %8 = wasmssa.const 1 : i32
+    %9 = wasmssa.add %7 %8 : i32
+    wasmssa.block_return %9 : i32
+  }, {
+    %5 = wasmssa.local_get %arg0 : ref to i32
+    %6 = wasmssa.const 1 : i32
+    %7 = wasmssa.shr_u %5 by %6 bits : i32
+    wasmssa.block_return %7 : i32
+  }) : (i32) -> ()
+^bb1(%4: i32):  // pred: ^bb0
+  wasmssa.return %4 : i32
+}
+
+// CHECK-LABEL:   func.func @if_else(
+// CHECK-SAME:      %[[ARG0:.*]]: i32) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = arith.constant 1 : i32
+// CHECK:           %[[VAL_4:.*]] = arith.andi %[[VAL_2]], %[[VAL_3]] : i32
+// CHECK:           %[[VAL_5:.*]] = arith.constant 0 : i32
+// CHECK:           %[[VAL_6:.*]] = arith.cmpi ne, %[[VAL_4]], %[[VAL_5]] : i32
+// CHECK:           cf.cond_br %[[VAL_6]], ^bb1(%[[VAL_1]] : i32), ^bb2(%[[VAL_1]] : i32)
+// CHECK:         ^bb1(%[[VAL_7:.*]]: i32):
+// CHECK:           %[[VAL_8:.*]] = arith.constant 1 : i32
+// CHECK:           %[[VAL_9:.*]] = arith.addi %[[VAL_7]], %[[VAL_8]] : i32
+// CHECK:           cf.br ^bb2(%[[VAL_9]] : i32)
+// CHECK:         ^bb2(%[[VAL_10:.*]]: i32):
+// CHECK:           return %[[VAL_10]] : i32
+wasmssa.func nested @if_else(%arg0: !wasmssa<local ref to i32>) -> i32 {
+  %1 = wasmssa.local_get %arg0 : ref to i32
+  %2 = wasmssa.local_get %arg0 : ref to i32
+  %3 = wasmssa.const 1 : i32
+  %4 = wasmssa.and %2 %3 : i32
+  "wasmssa.if"(%4, %1)[^bb1] ({
+  ^bb0(%arg1: i32):
+    %6 = wasmssa.const 1 : i32
+    %7 = wasmssa.add %arg1 %6 : i32
+    wasmssa.block_return %7 : i32
+  }, {
+  }) : (i32, i32) -> ()
+^bb1(%5: i32):  // pred: ^bb0
+  wasmssa.return %5 : i32
+}
+
+// CHECK-LABEL:   func.func @if_if(
+// CHECK-SAME:                     %[[ARG0:.*]]: i32) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = math.cttz %[[VAL_1]] : i32
+// CHECK:           %[[VAL_3:.*]] = arith.constant 0 : i32
+// CHECK:           %[[VAL_4:.*]] = arith.cmpi ne, %[[VAL_2]], %[[VAL_3]] : i32
+// CHECK:           cf.cond_br %[[VAL_4]], ^bb1, ^bb4
+// CHECK:         ^bb1:
+// CHECK:           %[[VAL_5:.*]] = arith.constant 2 : i32
+// CHECK:           %[[VAL_6:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_7:.*]] = arith.constant 1 : i32
+// CHECK:           %[[VAL_8:.*]] = arith.shrui %[[VAL_6]], %[[VAL_7]] : i32
+// CHECK:           %[[VAL_9:.*]] = math.cttz %[[VAL_8]] : i32
+// CHECK:           %[[VAL_10:.*]] = arith.constant 0 : i32
+// CHECK:           %[[VAL_11:.*]] = arith.cmpi ne, %[[VAL_9]], %[[VAL_10]] : i32
+// CHECK:           cf.cond_br %[[VAL_11]], ^bb2(%[[VAL_5]] : i32), ^bb3(%[[VAL_5]] : i32)
+// CHECK:         ^bb2(%[[VAL_12:.*]]: i32):
+// CHECK:           %[[VAL_13:.*]] = arith.constant 2 : i32
+// CHECK:           %[[VAL_14:.*]] = arith.addi %[[VAL_12]], %[[VAL_13]] : i32
+// CHECK:           cf.br ^bb3(%[[VAL_14]] : i32)
+// CHECK:         ^bb3(%[[VAL_15:.*]]: i32):
+// CHECK:           cf.br ^bb5(%[[VAL_15]] : i32)
+// CHECK:         ^bb4:
+// CHECK:           %[[VAL_16:.*]] = arith.constant 1 : i32
+// CHECK:           cf.br ^bb5(%[[VAL_16]] : i32)
+// CHECK:         ^bb5(%[[VAL_17:.*]]: i32):
+// CHECK:           return %[[VAL_17]] : i32
+wasmssa.func nested @if_if(%arg0: !wasmssa<local ref to i32>) -> i32 {
+  %1 = wasmssa.local_get %arg0 : ref to i32
+  %2 = wasmssa.ctz %1 : i32
+  "wasmssa.if"(%2)[^bb1] ({
+    %4 = wasmssa.const 2 : i32
+    %5 = wasmssa.local_get %arg0 : ref to i32
+    %6 = wasmssa.const 1 : i32
+    %7 = wasmssa.shr_u %5 by %6 bits : i32
+    %8 = wasmssa.ctz %7 : i32
+    "wasmssa.if"(%8, %4)[^bb1] ({
+    ^bb0(%arg1: i32):
+      %10 = wasmssa.const 2 : i32
+      %11 = wasmssa.add %arg1 %10 : i32
+      wasmssa.block_return %11 : i32
+    }, {
+    }) : (i32, i32) -> ()
+  ^bb1(%9: i32):  // pred: ^bb0
+    wasmssa.block_return %9 : i32
+  }, {
+    %4 = wasmssa.const 1 : i32
+    wasmssa.block_return %4 : i32
+  }) : (i32) -> ()
+^bb1(%3: i32):  // pred: ^bb0
+  wasmssa.return %3 : i32
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-loop-to-cf.mlir b/mlir/test/Conversion/RaiseWasm/wasm-loop-to-cf.mlir
new file mode 100644
index 0000000000000..e49909cc9417e
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-loop-to-cf.mlir
@@ -0,0 +1,206 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir --canonicalize -o - | FileCheck --check-prefix=CHECK-CANONICAL %s
+
+module {
+  wasmssa.func nested @func_0() {
+    wasmssa.loop : {
+      wasmssa.block_return
+    }> ^bb1
+  ^bb1:  // pred: ^bb0
+    wasmssa.return
+  }
+}
+
+// CHECK-LABEL:   module {
+// CHECK:           func.func @func_0() {
+// CHECK:             cf.br ^bb1
+// CHECK:           ^bb1:
+// CHECK:             cf.br ^bb2
+// CHECK:           ^bb2:
+// CHECK:             return
+// CHECK:           }
+
+// CHECK-CANONICAL-LABEL:  func.func @func_0() {
+// CHECK-CANONICAL:             return
+// CHECK-CANONICAL:           }
+
+// -----
+
+module {
+  wasmssa.func nested @func_0() -> i32 {
+    %0 = wasmssa.local of type i32
+    wasmssa.loop : {
+      %1 = wasmssa.local_get %0 : ref to i32
+      %2 = wasmssa.const 10 : i32
+      %3 = wasmssa.lt_si %1 %2 : i32 -> i32
+      wasmssa.block_return %3 : i32
+    }> ^bb1
+  ^bb1(%1: i32):  // pred: ^bb0
+    wasmssa.return %1 : i32
+  }
+}
+// CHECK-LABEL:   func.func @func_0() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = arith.constant 0 : i32
+// CHECK:           memref.store %[[VAL_1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           cf.br ^bb1
+// CHECK:         ^bb1:
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = arith.constant 10 : i32
+// CHECK:           %[[VAL_4:.*]] = arith.cmpi slt, %[[VAL_2]], %[[VAL_3]] : i32
+// CHECK:           %[[VAL_5:.*]] = arith.extui %[[VAL_4]] : i1 to i32
+// CHECK:           cf.br ^bb2(%[[VAL_5]] : i32)
+// CHECK:         ^bb2(%[[VAL_6:.*]]: i32):
+// CHECK:           return %[[VAL_6]] : i32
+// CHECK:         }
+
+// CHECK-CANONICAL-LABEL:   func.func @func_0() -> i32 {
+// CHECK-CANONICAL:           %[[VAL_0:.*]] = arith.constant 10 : i32
+// CHECK-CANONICAL:           %[[VAL_1:.*]] = arith.constant 0 : i32
+// CHECK-CANONICAL:           %[[VAL_2:.*]] = memref.alloca() : memref<i32>
+// CHECK-CANONICAL:           memref.store %[[VAL_1]], %[[VAL_2]][] : memref<i32>
+// CHECK-CANONICAL:           %[[VAL_3:.*]] = memref.load %[[VAL_2]][] : memref<i32>
+// CHECK-CANONICAL:           %[[VAL_4:.*]] = arith.cmpi slt, %[[VAL_3]], %[[VAL_0]] : i32
+// CHECK-CANONICAL:           %[[VAL_5:.*]] = arith.extui %[[VAL_4]] : i1 to i32
+// CHECK-CANONICAL:           return %[[VAL_5]] : i32
+
+// -----
+
+module {
+  wasmssa.func nested @func_0() {
+    %0 = wasmssa.local of type i32
+    wasmssa.loop : {
+      %1 = wasmssa.local_get %0 : ref to i32
+      %2 = wasmssa.const 10 : i32
+      %3 = wasmssa.lt_si %1 %2 : i32 -> i32
+      wasmssa.branch_if %3 to level 0 else ^bb1
+    ^bb1:  // pred: ^bb0
+      wasmssa.block_return
+    }> ^bb1
+  ^bb1:  // pred: ^bb0
+    wasmssa.return
+  }
+}
+
+// CHECK-LABEL:   func.func @func_0() {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = arith.constant 0 : i32
+// CHECK:           memref.store %[[VAL_1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           cf.br ^bb1
+// CHECK:         ^bb1:
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = arith.constant 10 : i32
+// CHECK:           %[[VAL_4:.*]] = arith.cmpi slt, %[[VAL_2]], %[[VAL_3]] : i32
+// CHECK:           %[[VAL_5:.*]] = arith.extui %[[VAL_4]] : i1 to i32
+// CHECK:           %[[VAL_6:.*]] = arith.constant 0 : i32
+// CHECK:           %[[VAL_7:.*]] = arith.cmpi ne, %[[VAL_5]], %[[VAL_6]] : i32
+// CHECK:           cf.cond_br %[[VAL_7]], ^bb1, ^bb2
+// CHECK:         ^bb2:
+// CHECK:           cf.br ^bb3
+// CHECK:         ^bb3:
+// CHECK:           return
+// CHECK:         }
+
+// CHECK-CANONICAL-LABEL:   func.func @func_0() {
+// CHECK-CANONICAL:           %[[VAL_0:.*]] = arith.constant 10 : i32
+// CHECK-CANONICAL:           %[[VAL_1:.*]] = arith.constant 0 : i32
+// CHECK-CANONICAL:           %[[VAL_2:.*]] = memref.alloca() : memref<i32>
+// CHECK-CANONICAL:           memref.store %[[VAL_1]], %[[VAL_2]][] : memref<i32>
+// CHECK-CANONICAL:           cf.br ^bb1
+// CHECK-CANONICAL:         ^bb1:
+// CHECK-CANONICAL:           %[[VAL_3:.*]] = memref.load %[[VAL_2]][] : memref<i32>
+// CHECK-CANONICAL:           %[[VAL_4:.*]] = arith.cmpi slt, %[[VAL_3]], %[[VAL_0]] : i32
+// CHECK-CANONICAL:           cf.cond_br %[[VAL_4]], ^bb1, ^bb2
+// CHECK-CANONICAL:         ^bb2:
+// CHECK-CANONICAL:           return
+
+// -----
+
+module {
+  wasmssa.func nested @func_0() {
+    %0 = wasmssa.local of type i32
+    %1 = wasmssa.local of type i32
+    wasmssa.loop : {
+      %2 = wasmssa.local_get %0 : ref to i32
+      %3 = wasmssa.const 1 : i32
+      %4 = wasmssa.add %2 %3 : i32
+      wasmssa.local_set %0 : ref to i32 to %4 : i32
+      wasmssa.loop : {
+        %8 = wasmssa.const 12 : i32
+        %9 = wasmssa.local_get %0 : ref to i32
+        %10 = wasmssa.gt_si %8 %9 : i32 -> i32
+        wasmssa.branch_if %10 to level 0 else ^bb1
+      ^bb1:  // pred: ^bb0
+        wasmssa.block_return %8 : i32
+      }> ^bb1
+    ^bb1(%5: i32):  // pred: ^bb0
+      %6 = wasmssa.const 10 : i32
+      %7 = wasmssa.lt_si %5 %6 : i32 -> i32
+      wasmssa.branch_if %7 to level 0 else ^bb2
+    ^bb2:  // pred: ^bb1
+      wasmssa.block_return
+    }> ^bb1
+  ^bb1:  // pred: ^bb0
+    wasmssa.return
+  }
+}
+
+// CHECK-LABEL:   func.func @func_0() {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = arith.constant 0 : i32
+// CHECK:           memref.store %[[VAL_1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.alloca() : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = arith.constant 0 : i32
+// CHECK:           memref.store %[[VAL_3]], %[[VAL_2]][] : memref<i32>
+// CHECK:           cf.br ^bb1
+// CHECK:         ^bb1:
+// CHECK:           %[[VAL_4:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_5:.*]] = arith.constant 1 : i32
+// CHECK:           %[[VAL_6:.*]] = arith.addi %[[VAL_4]], %[[VAL_5]] : i32
+// CHECK:           memref.store %[[VAL_6]], %[[VAL_0]][] : memref<i32>
+// CHECK:           cf.br ^bb2
+// CHECK:         ^bb2:
+// CHECK:           %[[VAL_7:.*]] = arith.constant 12 : i32
+// CHECK:           %[[VAL_8:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_9:.*]] = arith.cmpi sgt, %[[VAL_7]], %[[VAL_8]] : i32
+// CHECK:           %[[VAL_10:.*]] = arith.extui %[[VAL_9]] : i1 to i32
+// CHECK:           %[[VAL_11:.*]] = arith.constant 0 : i32
+// CHECK:           %[[VAL_12:.*]] = arith.cmpi ne, %[[VAL_10]], %[[VAL_11]] : i32
+// CHECK:           cf.cond_br %[[VAL_12]], ^bb2, ^bb3
+// CHECK:         ^bb3:
+// CHECK:           cf.br ^bb4(%[[VAL_7]] : i32)
+// CHECK:         ^bb4(%[[VAL_13:.*]]: i32):
+// CHECK:           %[[VAL_14:.*]] = arith.constant 10 : i32
+// CHECK:           %[[VAL_15:.*]] = arith.cmpi slt, %[[VAL_13]], %[[VAL_14]] : i32
+// CHECK:           %[[VAL_16:.*]] = arith.extui %[[VAL_15]] : i1 to i32
+// CHECK:           %[[VAL_17:.*]] = arith.constant 0 : i32
+// CHECK:           %[[VAL_18:.*]] = arith.cmpi ne, %[[VAL_16]], %[[VAL_17]] : i32
+// CHECK:           cf.cond_br %[[VAL_18]], ^bb1, ^bb5
+// CHECK:         ^bb5:
+// CHECK:           cf.br ^bb6
+// CHECK:         ^bb6:
+// CHECK:           return
+// CHECK:         }
+
+// CHECK-CANONICAL-LABEL:   func.func @func_0() {
+// CHECK-CANONICAL:           %[[VAL_0:.*]] = arith.constant 10 : i32
+// CHECK-CANONICAL:           %[[VAL_1:.*]] = arith.constant 12 : i32
+// CHECK-CANONICAL:           %[[VAL_2:.*]] = arith.constant 1 : i32
+// CHECK-CANONICAL:           %[[VAL_3:.*]] = arith.constant 0 : i32
+// CHECK-CANONICAL:           %[[VAL_4:.*]] = memref.alloca() : memref<i32>
+// CHECK-CANONICAL:           memref.store %[[VAL_3]], %[[VAL_4]][] : memref<i32>
+// CHECK-CANONICAL:           cf.br ^bb1
+// CHECK-CANONICAL:         ^bb1:
+// CHECK-CANONICAL:           %[[VAL_5:.*]] = memref.load %[[VAL_4]][] : memref<i32>
+// CHECK-CANONICAL:           %[[VAL_6:.*]] = arith.addi %[[VAL_5]], %[[VAL_2]] : i32
+// CHECK-CANONICAL:           memref.store %[[VAL_6]], %[[VAL_4]][] : memref<i32>
+// CHECK-CANONICAL:           cf.br ^bb2
+// CHECK-CANONICAL:         ^bb2:
+// CHECK-CANONICAL:           %[[VAL_7:.*]] = memref.load %[[VAL_4]][] : memref<i32>
+// CHECK-CANONICAL:           %[[VAL_8:.*]] = arith.cmpi slt, %[[VAL_7]], %[[VAL_1]] : i32
+// CHECK-CANONICAL:           cf.cond_br %[[VAL_8]], ^bb2, ^bb3(%[[VAL_1]] : i32)
+// CHECK-CANONICAL:         ^bb3(%[[VAL_9:.*]]: i32):
+// CHECK-CANONICAL:           %[[VAL_10:.*]] = arith.cmpi slt, %[[VAL_9]], %[[VAL_0]] : i32
+// CHECK-CANONICAL:           cf.cond_br %[[VAL_10]], ^bb1, ^bb4
+// CHECK-CANONICAL:         ^bb4:
+// CHECK-CANONICAL:           return

>From 2af7f4e6300c16db66abf0ad83efa9e338ca21bd Mon Sep 17 00:00:00 2001
From: Ferdinand Lemaire <ferdinand.lemaire at woven-planet.global>
Date: Thu, 3 Jul 2025 13:36:04 +0900
Subject: [PATCH 4/5] [mlir][wasm] RaiseWasmMLIRPass: Add support for memory

--
 Co-authored-by: Luc Forget <luc.forget at woven-planet.global>
 Co-authored-by: Jessica Paquette <jessica.paquette at woven-planet.global>
---
 .../Conversion/RaiseWasm/RaiseWasmMLIR.cpp    | 41 +++++++++++++++++++
 .../RaiseWasm/wasm-memory-to-memref.mlir      | 14 +++++++
 2 files changed, 55 insertions(+)
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-memory-to-memref.mlir

diff --git a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
index d9dcb756790f8..53a8900b965a3 100644
--- a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
+++ b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
@@ -677,6 +677,46 @@ struct WasmGlobalWithGetGlobalInitConversion
   }
 };
 
+struct WasmMemoryOpConversion : OpConversionPattern<MemOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  LogicalResult
+  matchAndRewrite(MemOp memOp, MemOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    auto loc = memOp.getLoc();
+    auto bufferType =
+        MemRefType::get({ShapedType::kDynamic}, rewriter.getI8Type());
+    auto bufferPtrType = MemRefType::get({1}, bufferType);
+    auto memPtr = rewriter.replaceOpWithNewOp<memref::GlobalOp>(
+        memOp, memOp.getSymNameAttr(), memOp.getSymVisibilityAttr(),
+        TypeAttr::get(bufferPtrType), /*initialValue*/ rewriter.getUnitAttr(),
+        /*constant*/ UnitAttr{}, /*alignment*/ IntegerAttr{});
+    auto initializerName = (memPtr.getSymName() + "::initializer").str();
+    auto memInitializer = rewriter.create<func::FuncOp>(
+        loc, initializerName, FunctionType::get(getContext(), {}, {}));
+    memInitializer->setAttr(rewriter.getStringAttr("initializer"),
+                            rewriter.getUnitAttr());
+    auto *initializerBody = memInitializer.addEntryBlock();
+    auto sip = rewriter.saveInsertionPoint();
+    rewriter.setInsertionPointToStart(initializerBody);
+    auto memRefPtr = rewriter.create<memref::GetGlobalOp>(
+        loc, MemRefType::get({1}, bufferType), memPtr.getSymName());
+    auto alloc = rewriter.create<memref::AllocOp>(
+        loc,
+        MemRefType::get({memOp.getLimits().getMin()}, rewriter.getI8Type()));
+    auto castOp =
+        rewriter.create<memref::CastOp>(loc, bufferType, alloc.getResult());
+    auto idx = rewriter.create<arith::ConstantIndexOp>(loc, 0);
+    rewriter.create<memref::StoreOp>(loc, castOp.getResult(),
+                                     memRefPtr.getResult(),
+                                     ValueRange{idx.getResult()});
+    rewriter.create<func::ReturnOp>(loc);
+    rewriter.restoreInsertionPoint(sip);
+    rewriter.create<func::CallOp>(loc, memInitializer);
+    return success();
+  }
+};
+
 inline TypedAttr getInitializerAttr(Type t) {
   assert(t.isIntOrFloat() &&
          "This helper is intended to use with int and float types");
@@ -847,6 +887,7 @@ void mlir::populateRaiseWasmMLIRConversionPatterns(
            WasmLtSIOpConversion,
            WasmLtUIOpConversion,
            WasmMaxOpConversion,
+           WasmMemoryOpConversion,
            WasmMinOpConversion,
            WasmMulOpConversion,
            WasmNeOpConversion,
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-memory-to-memref.mlir b/mlir/test/Conversion/RaiseWasm/wasm-memory-to-memref.mlir
new file mode 100644
index 0000000000000..09b07184d97fa
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-memory-to-memref.mlir
@@ -0,0 +1,14 @@
+// RUN: mlir-opt %s --raise-wasm-mlir | FileCheck %s
+
+"wasmssa.memory"() <{limits = !wasmssa<limit[17:]>, sym_name = "mem_0", sym_visibility = "nested"}> : () -> ()
+
+// CHECK-LABEL:   memref.global "nested" @mem_0 : memref<1xmemref<?xi8>>
+
+// CHECK-LABEL:   func.func @"mem_0::initializer"() attributes {initializer} {
+// CHECK:           %[[VAL_0:.*]] = memref.get_global @mem_0 : memref<1xmemref<?xi8>>
+// CHECK:           %[[VAL_1:.*]] = memref.alloc() : memref<17xi8>
+// CHECK:           %[[VAL_2:.*]] = memref.cast %[[VAL_1]] : memref<17xi8> to memref<?xi8>
+// CHECK:           %[[VAL_3:.*]] = arith.constant 0 : index
+// CHECK:           memref.store %[[VAL_2]], %[[VAL_0]]{{\[}}%[[VAL_3]]] : memref<1xmemref<?xi8>>
+// CHECK:           return
+// CHECK:         func.call @"mem_0::initializer"() : () -> ()

>From ec4763983eff03797ce2a4f1d60e296b250450a1 Mon Sep 17 00:00:00 2001
From: Ferdinand Lemaire <ferdinand.lemaire at woven-planet.global>
Date: Thu, 30 Apr 2026 21:00:48 +0900
Subject: [PATCH 5/5] [mlir][wasm] Deprecate rewriter.create in favor of
 <op>::create and cleanup the tests

---
 .../Conversion/RaiseWasm/RaiseWasmMLIR.cpp    | 123 ++++++++----------
 .../RaiseWasm/wasm-blocks-to-cf.mlir          |  18 +--
 .../wasm-comparisons-to-arith-cmp.mlir        |  64 ++++-----
 .../RaiseWasm/wasm-extend-to-arith-ext.mlir   |  14 +-
 .../Conversion/RaiseWasm/wasm-loop-to-cf.mlir |   8 +-
 .../RaiseWasm/wasm-rotl-to-arith.mlir         |   4 +-
 .../RaiseWasm/wasm-rotr-to-arith.mlir         |   4 +-
 7 files changed, 112 insertions(+), 123 deletions(-)

diff --git a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
index 53a8900b965a3..0e6e0c05b79b6 100644
--- a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
+++ b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
@@ -20,6 +20,7 @@
 #include "mlir/Dialect/MemRef/IR/MemRef.h"
 #include "mlir/Dialect/Vector/IR/VectorOps.h"
 #include "mlir/Dialect/WasmSSA/IR/WasmSSA.h"
+#include "mlir/Dialect/WasmSSA/IR/WasmSSAInterfaces.h"
 #include "mlir/IR/BuiltinAttributes.h"
 #include "mlir/IR/BuiltinDialect.h"
 #include "mlir/IR/ValueRange.h"
@@ -159,25 +160,22 @@ struct RotateOpConversion : OpConversionPattern<SourceOp> {
 
     // Materialize (width - 1) for use in both sides of the expression.
     auto cstWidthMinusOne =
-        rewriter.create<ConstOp>(loc, IntegerAttr::get(ty, width - 1));
+        ConstOp::create(rewriter, loc, IntegerAttr::get(ty, width - 1));
 
     // Form the left-hand side of the OR:
     // (val (lhs shift op) (bits & (width - 1)))
-    auto orLHS = rewriter.create<LHSShiftOp>(
-        loc, val, rewriter.create<AndOp>(loc, bits, cstWidthMinusOne));
+    auto orLHS = LHSShiftOp::create(
+        rewriter, loc, val, AndOp::create(rewriter, loc, bits, cstWidthMinusOne));
 
     // Form the right-hand side of the OR:
     // (val (rhs shift op) (-bits & (width - 1)))
-    auto orRHS = rewriter.create<RHSShiftOp>(
-        loc, val,
+    auto orRHS = RHSShiftOp::create(
+        rewriter, loc, val,
         // (-bits & (width - 1))
-        rewriter.create<AndOp>(
-            loc,
+        AndOp::create(
+            rewriter, loc,
             // 0 - bits == -bits
-            rewriter.create<SubOp>(
-                loc,
-                rewriter.create<ConstOp>(loc, IntegerAttr::get(ty, 0)),
-                bits),
+            SubOp::create(rewriter, loc, ConstOp::create(rewriter, loc, IntegerAttr::get(ty, 0)), bits),
             cstWidthMinusOne));
 
     // OR together the two shifts and replace the rotate with the new
@@ -199,8 +197,7 @@ struct ComparisonOpConversion : OpConversionPattern<SourceOp> {
   matchAndRewrite(SourceOp srcOp, typename SourceOp::Adaptor adaptor,
                   ConversionPatternRewriter &rewriter) const override {
     auto cmpRes =
-        rewriter
-            .create<TargetOp>(srcOp.getLoc(), rewriter.getI1Type(),
+        TargetOp::create(rewriter, srcOp.getLoc(), rewriter.getI1Type(),
                               AttrType::get(rewriter.getContext(), flag),
                               adaptor.getLhs(), adaptor.getRhs())
             .getResult();
@@ -257,19 +254,15 @@ struct IntFpComparisonOpConversion : OpConversionPattern<SourceOp> {
     Value comparisonResult;
     if (srcOp.getLhs().getType().isInteger())
       comparisonResult =
-          rewriter
-              .create<arith::CmpIOp>(
-                  srcOp.getLoc(), rewriter.getI1Type(),
-                  arith::CmpIPredicateAttr::get(rewriter.getContext(), IntFlag),
-                  adaptor.getLhs(), adaptor.getRhs())
+          arith::CmpIOp::create(rewriter, srcOp.getLoc(), rewriter.getI1Type(),
+                                arith::CmpIPredicateAttr::get(rewriter.getContext(), IntFlag),
+                                adaptor.getLhs(), adaptor.getRhs())
               .getResult();
     else if (srcOp.getLhs().getType().isFloat())
       comparisonResult =
-          rewriter
-              .create<arith::CmpFOp>(srcOp.getLoc(), rewriter.getI1Type(),
-                                     arith::CmpFPredicateAttr::get(
-                                         rewriter.getContext(), FloatFlag),
-                                     adaptor.getLhs(), adaptor.getRhs())
+          arith::CmpFOp::create(rewriter, srcOp.getLoc(), rewriter.getI1Type(),
+                                arith::CmpFPredicateAttr::get(rewriter.getContext(), FloatFlag),
+                                adaptor.getLhs(), adaptor.getRhs())
               .getResult();
     else
       return rewriter.notifyMatchFailure(
@@ -320,13 +313,9 @@ struct WasmEqzOpConversion : OpConversionPattern<EqzOp> {
                   ConversionPatternRewriter &rewriter) const override {
     auto loc = eqzOp->getLoc();
     auto zero =
-        rewriter
-            .create<arith::ConstantOp>(
-                loc, rewriter.getIntegerAttr(adaptor.getInput().getType(), 0))
+        arith::ConstantOp::create(rewriter, loc, rewriter.getIntegerAttr(adaptor.getInput().getType(), 0))
             .getResult();
-    auto cmpRes = rewriter
-                      .create<arith::CmpIOp>(
-                          loc, rewriter.getI1Type(),
+    auto cmpRes = arith::CmpIOp::create(rewriter, loc, rewriter.getI1Type(),
                           arith::CmpIPredicateAttr::get(
                               rewriter.getContext(), arith::CmpIPredicate::eq),
                           adaptor.getInput(), zero)
@@ -346,9 +335,7 @@ struct WasmExtendLowBitsOpConversion : OpConversionPattern<ExtendLowBitsSOp> {
                   ExtendLowBitsSOp::Adaptor adaptor,
                   ConversionPatternRewriter &rewriter) const override {
     auto truncWidth = extendLowBytesSOp.getBitsToTake().getInt();
-    auto truncation = rewriter.create<arith::TruncIOp>(
-        extendLowBytesSOp->getLoc(), rewriter.getIntegerType(truncWidth),
-        adaptor.getInput());
+    auto truncation = arith::TruncIOp::create(rewriter, extendLowBytesSOp->getLoc(), rewriter.getIntegerType(truncWidth), adaptor.getInput());
     rewriter.replaceOpWithNewOp<arith::ExtSIOp>(
         extendLowBytesSOp, extendLowBytesSOp.getResult().getType(),
         truncation.getResult());
@@ -380,15 +367,11 @@ struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
   class CFRewriterVisitor {
   private:
     using branch_to_dest_t =
-        llvm::DenseMap<WasmSSALabelBranchingInterface, Block *>;
+        llvm::DenseMap<LabelBranchingOpInterface, Block *>;
     Value getCompResultAsI1(Value compResult,
                             ConversionPatternRewriter &rewriter) {
-      auto testValue = rewriter.create<arith::ConstantOp>(
-          compResult.getLoc(), rewriter.getI32IntegerAttr(0));
-      auto flag = rewriter
-                      .create<arith::CmpIOp>(
-                          compResult.getLoc(), rewriter.getIntegerType(1),
-                          arith::CmpIPredicate::ne, compResult, testValue)
+      auto testValue = arith::ConstantOp::create(rewriter, compResult.getLoc(), rewriter.getI32IntegerAttr(0));
+      auto flag = arith::CmpIOp::create(rewriter, compResult.getLoc(), rewriter.getIntegerType(1), arith::CmpIPredicate::ne, compResult, testValue)
                       .getResult();
       return flag;
     }
@@ -420,7 +403,7 @@ struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
 
     template <typename LevelType>
     LogicalResult
-    replaceNestLevelWithBranchWrapper(WasmSSALabelLevelInterface nestingOp,
+    replaceNestLevelWithBranchWrapper(LabelLevelOpInterface nestingOp,
                                       llvm::ArrayRef<Block *> regionsToEntry,
                                       ConversionPatternRewriter &rewriter) {
       auto cast = dyn_cast<LevelType>(nestingOp.getOperation());
@@ -431,7 +414,7 @@ struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
     }
 
     template <typename... LevelTypes>
-    LogicalResult inlineNestDispatcher(WasmSSALabelLevelInterface nestingOp,
+    LogicalResult inlineNestDispatcher(LabelLevelOpInterface nestingOp,
                                        ConversionPatternRewriter &rewriter) {
       auto sip = rewriter.saveInsertionPoint();
       Block *blockSuccessor = nestingOp->getSuccessor(0);
@@ -443,8 +426,8 @@ struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
           continue;
         regionEntries.push_back(&region.front());
         /// Inline blocks of nested ops
-        llvm::SmallVector<WasmSSALabelLevelInterface> nestedOps{
-            region.getOps<WasmSSALabelLevelInterface>()};
+        llvm::SmallVector<LabelLevelOpInterface> nestedOps{
+            region.getOps<LabelLevelOpInterface>()};
         for (auto nestedOp : nestedOps) {
           LLVM_DEBUG(llvm::dbgs() << " Found nested op: " << nestedOp);
           if (failed(inlineBlocks(nestedOp, rewriter)))
@@ -466,12 +449,12 @@ struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
     }
 
     /// Take a nesting level defining op and inline it in the parent region.
-    LogicalResult inlineBlocks(WasmSSALabelLevelInterface nestingOp,
+    LogicalResult inlineBlocks(LabelLevelOpInterface nestingOp,
                                ConversionPatternRewriter &rewriter) {
       return inlineNestDispatcher<BlockOp, IfOp, LoopOp>(nestingOp, rewriter);
     }
 
-    llvm::FailureOr<Block *> getBlockFor(WasmSSALabelBranchingInterface branchOp) {
+    llvm::FailureOr<Block *> getBlockFor(LabelBranchingOpInterface branchOp) {
       auto destIter = branchToDest.find(branchOp);
       if (destIter == branchToDest.end())
         return branchOp->emitError("No indexed label op for this operation: ")
@@ -494,7 +477,7 @@ struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
 
     template <typename LevelInterfaceT>
     inline LogicalResult
-    convertBranchWrapper(WasmSSALabelBranchingInterface branchOp, Block *dest,
+    convertBranchWrapper(LabelBranchingOpInterface branchOp, Block *dest,
                          ConversionPatternRewriter &rewriter) {
       auto cast = dyn_cast<LevelInterfaceT>(branchOp.getOperation());
       if (!cast)
@@ -507,7 +490,7 @@ struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
     }
 
     template <typename... BranchInterfaceT>
-    LogicalResult convertBranchDispatch(WasmSSALabelBranchingInterface branchOp,
+    LogicalResult convertBranchDispatch(LabelBranchingOpInterface branchOp,
                                         ConversionPatternRewriter &rewriter) {
       auto dest = getBlockFor(branchOp);
       if (failed(dest))
@@ -521,7 +504,7 @@ struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
       return res;
     }
 
-    LogicalResult convertBranch(WasmSSALabelBranchingInterface branchOp,
+    LogicalResult convertBranch(LabelBranchingOpInterface branchOp,
                                 ConversionPatternRewriter &rewriter) {
       return convertBranchDispatch<BlockReturnOp, BranchIfOp>(branchOp,
                                                               rewriter);
@@ -532,19 +515,19 @@ struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
 
   public:
     CFRewriterVisitor(func::FuncOp func) : func{func} {
-      func.walk([this](WasmSSALabelBranchingInterface branchOp) {
+      func.walk([this](LabelBranchingOpInterface branchOp) {
         branchToDest.insert({branchOp, branchOp.getTarget()});
       });
     }
     LogicalResult rewrite(ConversionPatternRewriter &rewriter) {
-      llvm::SmallVector<WasmSSALabelLevelInterface> nestingOps{
-          func.getOps<WasmSSALabelLevelInterface>()};
+      llvm::SmallVector<LabelLevelOpInterface> nestingOps{
+          func.getOps<LabelLevelOpInterface>()};
       for (auto nestingOp : nestingOps)
         if (failed(inlineBlocks(nestingOp, rewriter)))
           return failure();
 
       auto res =
-          func->walk([this, &rewriter](WasmSSALabelBranchingInterface branchOp) {
+          func->walk([this, &rewriter](LabelBranchingOpInterface branchOp) {
             if (failed(convertBranch(branchOp, rewriter)))
               return WalkResult::interrupt();
             return WalkResult::advance();
@@ -687,32 +670,38 @@ struct WasmMemoryOpConversion : OpConversionPattern<MemOp> {
     auto bufferType =
         MemRefType::get({ShapedType::kDynamic}, rewriter.getI8Type());
     auto bufferPtrType = MemRefType::get({1}, bufferType);
+    auto memVisibility = memOp.getVisibility();
+    // Convert to StringAttr since memref::GlobalOp expects visibility as a string attribute.
+    mlir::StringAttr visAttr;
+    if (memVisibility == mlir::SymbolTable::Visibility::Public)
+        visAttr = mlir::StringAttr::get(memOp->getContext(), "public");
+    else if (memVisibility == mlir::SymbolTable::Visibility::Private)
+        visAttr = mlir::StringAttr::get(memOp->getContext(), "private");
+    else
+        visAttr = mlir::StringAttr::get(memOp->getContext(), "nested");
+
     auto memPtr = rewriter.replaceOpWithNewOp<memref::GlobalOp>(
-        memOp, memOp.getSymNameAttr(), memOp.getSymVisibilityAttr(),
+        memOp, memOp.getSymNameAttr(), visAttr,
         TypeAttr::get(bufferPtrType), /*initialValue*/ rewriter.getUnitAttr(),
         /*constant*/ UnitAttr{}, /*alignment*/ IntegerAttr{});
     auto initializerName = (memPtr.getSymName() + "::initializer").str();
-    auto memInitializer = rewriter.create<func::FuncOp>(
-        loc, initializerName, FunctionType::get(getContext(), {}, {}));
+    auto memInitializer = func::FuncOp::create(rewriter, loc, initializerName,
+                                               FunctionType::get(getContext(), {}, {}));
     memInitializer->setAttr(rewriter.getStringAttr("initializer"),
                             rewriter.getUnitAttr());
     auto *initializerBody = memInitializer.addEntryBlock();
     auto sip = rewriter.saveInsertionPoint();
     rewriter.setInsertionPointToStart(initializerBody);
-    auto memRefPtr = rewriter.create<memref::GetGlobalOp>(
-        loc, MemRefType::get({1}, bufferType), memPtr.getSymName());
-    auto alloc = rewriter.create<memref::AllocOp>(
-        loc,
-        MemRefType::get({memOp.getLimits().getMin()}, rewriter.getI8Type()));
+    auto memRefPtr = memref::GetGlobalOp::create(rewriter, loc, MemRefType::get({1}, bufferType), memPtr.getSymName());
+    auto alloc = memref::AllocOp::create(rewriter, loc, MemRefType::get({memOp.getLimits().getMin()}, rewriter.getI8Type()));
     auto castOp =
-        rewriter.create<memref::CastOp>(loc, bufferType, alloc.getResult());
-    auto idx = rewriter.create<arith::ConstantIndexOp>(loc, 0);
-    rewriter.create<memref::StoreOp>(loc, castOp.getResult(),
-                                     memRefPtr.getResult(),
-                                     ValueRange{idx.getResult()});
-    rewriter.create<func::ReturnOp>(loc);
+        memref::CastOp::create(rewriter, loc, bufferType, alloc.getResult());
+    auto idx = arith::ConstantIndexOp::create(rewriter, loc, 0);
+    memref::StoreOp::create(rewriter, loc, castOp.getResult(),
+                            memRefPtr.getResult(), ValueRange{idx.getResult()});
+    func::ReturnOp::create(rewriter, loc);
     rewriter.restoreInsertionPoint(sip);
-    rewriter.create<func::CallOp>(loc, memInitializer);
+    func::CallOp::create(rewriter, loc, memInitializer);
     return success();
   }
 };
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-blocks-to-cf.mlir b/mlir/test/Conversion/RaiseWasm/wasm-blocks-to-cf.mlir
index 3b275573bcbd3..fdce71cab096b 100644
--- a/mlir/test/Conversion/RaiseWasm/wasm-blocks-to-cf.mlir
+++ b/mlir/test/Conversion/RaiseWasm/wasm-blocks-to-cf.mlir
@@ -60,7 +60,7 @@ wasmssa.func @i_am_a_block(%arg0 : !wasmssa<local ref to i32>) -> i32 {
 // CHECK:         ^bb6:
 // CHECK:           %[[VAL_6:.*]] = arith.constant 7 : i32
 // CHECK:           return
-wasmssa.func nested @func_0(%arg0: !wasmssa<local ref to i32>) {
+wasmssa.func @func_0(%arg0: !wasmssa<local ref to i32>) {
   %1 = wasmssa.const 1: i32
   wasmssa.block : {
     %2 = wasmssa.const 2: i32
@@ -104,7 +104,7 @@ wasmssa.func nested @func_0(%arg0: !wasmssa<local ref to i32>) {
 // CHECK:         ^bb6:
 // CHECK:           %[[VAL_6:.*]] = arith.constant 7 : i32
 // CHECK:           return
-wasmssa.func nested @func_1() {
+wasmssa.func @func_1() {
   %1 = wasmssa.const 1: i32
   wasmssa.block : {
     %2 = wasmssa.const 2: i32
@@ -136,7 +136,7 @@ wasmssa.func nested @func_1() {
 // CHECK:           cf.br ^bb2(%[[VAL_3]] : i32)
 // CHECK:         ^bb2(%[[VAL_4:.*]]: i32):
 // CHECK:           return %[[VAL_4]] : i32
-wasmssa.func nested @func_2() -> i32 {
+wasmssa.func @func_2() -> i32 {
   %0 = wasmssa.const 14 : i32
   wasmssa.block(%0) : i32 : {
   ^bb0(%arg0: i32):
@@ -155,7 +155,7 @@ wasmssa.func nested @func_2() -> i32 {
 // CHECK:           cf.br ^bb2(%[[VAL_0]] : i32)
 // CHECK:         ^bb2(%[[VAL_1:.*]]: i32):
 // CHECK:           return %[[VAL_1]] : i32
-wasmssa.func nested @func_3() -> i32 {
+wasmssa.func @func_3() -> i32 {
   wasmssa.block : {
     %1 = wasmssa.const 17 : i32
     wasmssa.block_return %1 : i32
@@ -185,7 +185,7 @@ wasmssa.func nested @func_3() -> i32 {
 // CHECK_CANONICALIZED:           %[[VAL_0:.*]] = arith.constant 1 : i32
 // CHECK_CANONICALIZED:           return %[[VAL_0]] : i32
 
-wasmssa.func nested @branch_if_taken() -> i32 {
+wasmssa.func @branch_if_taken() -> i32 {
   wasmssa.block : {
     %1 = wasmssa.const 1 : i32
     %2 = wasmssa.const 2 : i32
@@ -218,7 +218,7 @@ wasmssa.func nested @branch_if_taken() -> i32 {
 // CHECK_CANONICALIZED:           %[[VAL_0:.*]] = arith.constant 17 : i32
 // CHECK_CANONICALIZED:           return %[[VAL_0]] : i32
 // CHECK_CANONICALIZED:         }
-wasmssa.func nested @branch_if_continue() -> i32 {
+wasmssa.func @branch_if_continue() -> i32 {
   wasmssa.block : {
     %1 = wasmssa.const 1 : i32
     %2 = wasmssa.const 0 : i32
@@ -256,7 +256,7 @@ wasmssa.func nested @branch_if_continue() -> i32 {
 // CHECK:           cf.br ^bb3(%[[VAL_13]] : i32)
 // CHECK:         ^bb3(%[[VAL_14:.*]]: i32):
 // CHECK:           return %[[VAL_14]] : i32
-wasmssa.func nested @if(%arg0: !wasmssa<local ref to i32>) -> i32 {
+wasmssa.func @if(%arg0: !wasmssa<local ref to i32>) -> i32 {
   %1 = wasmssa.local_get %arg0 : ref to i32
   %2 = wasmssa.const 1 : i32
   %3 = wasmssa.and %1 %2 : i32
@@ -294,7 +294,7 @@ wasmssa.func nested @if(%arg0: !wasmssa<local ref to i32>) -> i32 {
 // CHECK:           cf.br ^bb2(%[[VAL_9]] : i32)
 // CHECK:         ^bb2(%[[VAL_10:.*]]: i32):
 // CHECK:           return %[[VAL_10]] : i32
-wasmssa.func nested @if_else(%arg0: !wasmssa<local ref to i32>) -> i32 {
+wasmssa.func @if_else(%arg0: !wasmssa<local ref to i32>) -> i32 {
   %1 = wasmssa.local_get %arg0 : ref to i32
   %2 = wasmssa.local_get %arg0 : ref to i32
   %3 = wasmssa.const 1 : i32
@@ -339,7 +339,7 @@ wasmssa.func nested @if_else(%arg0: !wasmssa<local ref to i32>) -> i32 {
 // CHECK:           cf.br ^bb5(%[[VAL_16]] : i32)
 // CHECK:         ^bb5(%[[VAL_17:.*]]: i32):
 // CHECK:           return %[[VAL_17]] : i32
-wasmssa.func nested @if_if(%arg0: !wasmssa<local ref to i32>) -> i32 {
+wasmssa.func @if_if(%arg0: !wasmssa<local ref to i32>) -> i32 {
   %1 = wasmssa.local_get %arg0 : ref to i32
   %2 = wasmssa.ctz %1 : i32
   "wasmssa.if"(%2)[^bb1] ({
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-comparisons-to-arith-cmp.mlir b/mlir/test/Conversion/RaiseWasm/wasm-comparisons-to-arith-cmp.mlir
index bc952b47520ca..6643b0389f405 100644
--- a/mlir/test/Conversion/RaiseWasm/wasm-comparisons-to-arith-cmp.mlir
+++ b/mlir/test/Conversion/RaiseWasm/wasm-comparisons-to-arith-cmp.mlir
@@ -2,194 +2,194 @@
 
 
 module {
-  wasmssa.func nested @func_lt_si32() -> i32 {
+  wasmssa.func @func_lt_si32() -> i32 {
     %0 = wasmssa.const 12 : i32
     %1 = wasmssa.const 50 : i32
     %2 = wasmssa.lt_si %0 %1 : i32 -> i32
     wasmssa.return %2 : i32
   }
 
-  wasmssa.func nested @func_le_si32() -> i32 {
+  wasmssa.func @func_le_si32() -> i32 {
     %0 = wasmssa.const 12 : i32
     %1 = wasmssa.const 50 : i32
     %2 = wasmssa.le_si %0 %1 : i32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_lt_ui32() -> i32 {
+  wasmssa.func @func_lt_ui32() -> i32 {
     %0 = wasmssa.const 12 : i32
     %1 = wasmssa.const 50 : i32
     %2 = wasmssa.lt_ui %0 %1 : i32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_le_ui32() -> i32 {
+  wasmssa.func @func_le_ui32() -> i32 {
     %0 = wasmssa.const 12 : i32
     %1 = wasmssa.const 50 : i32
     %2 = wasmssa.le_ui %0 %1 : i32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_gt_si32() -> i32 {
+  wasmssa.func @func_gt_si32() -> i32 {
     %0 = wasmssa.const 12 : i32
     %1 = wasmssa.const 50 : i32
     %2 = wasmssa.gt_si %0 %1 : i32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_gt_ui32() -> i32 {
+  wasmssa.func @func_gt_ui32() -> i32 {
     %0 = wasmssa.const 12 : i32
     %1 = wasmssa.const 50 : i32
     %2 = wasmssa.gt_ui %0 %1 : i32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_ge_si32() -> i32 {
+  wasmssa.func @func_ge_si32() -> i32 {
     %0 = wasmssa.const 12 : i32
     %1 = wasmssa.const 50 : i32
     %2 = wasmssa.ge_si %0 %1 : i32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_ge_ui32() -> i32 {
+  wasmssa.func @func_ge_ui32() -> i32 {
     %0 = wasmssa.const 12 : i32
     %1 = wasmssa.const 50 : i32
     %2 = wasmssa.ge_ui %0 %1 : i32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_lt_si64() -> i32 {
+  wasmssa.func @func_lt_si64() -> i32 {
     %0 = wasmssa.const 12 : i64
     %1 = wasmssa.const 50 : i64
     %2 = wasmssa.lt_si %0 %1 : i64 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_le_si64() -> i32 {
+  wasmssa.func @func_le_si64() -> i32 {
     %0 = wasmssa.const 12 : i64
     %1 = wasmssa.const 50 : i64
     %2 = wasmssa.le_si %0 %1 : i64 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_lt_ui_i64() -> i32 {
+  wasmssa.func @func_lt_ui_i64() -> i32 {
     %0 = wasmssa.const 12 : i64
     %1 = wasmssa.const 50 : i64
     %2 = wasmssa.lt_ui %0 %1 : i64 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_le_ui_i64() -> i32 {
+  wasmssa.func @func_le_ui_i64() -> i32 {
     %0 = wasmssa.const 12 : i64
     %1 = wasmssa.const 50 : i64
     %2 = wasmssa.le_ui %0 %1 : i64 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_gt_si_i64() -> i32 {
+  wasmssa.func @func_gt_si_i64() -> i32 {
     %0 = wasmssa.const 12 : i64
     %1 = wasmssa.const 50 : i64
     %2 = wasmssa.gt_si %0 %1 : i64 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_gt_ui_i64() -> i32 {
+  wasmssa.func @func_gt_ui_i64() -> i32 {
     %0 = wasmssa.const 12 : i64
     %1 = wasmssa.const 50 : i64
     %2 = wasmssa.gt_ui %0 %1 : i64 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_ge_si_i64() -> i32 {
+  wasmssa.func @func_ge_si_i64() -> i32 {
     %0 = wasmssa.const 12 : i64
     %1 = wasmssa.const 50 : i64
     %2 = wasmssa.ge_si %0 %1 : i64 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_ge_ui_i64() -> i32 {
+  wasmssa.func @func_ge_ui_i64() -> i32 {
     %0 = wasmssa.const 12 : i64
     %1 = wasmssa.const 50 : i64
     %2 = wasmssa.ge_ui %0 %1 : i64 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_lt_f32() -> i32 {
+  wasmssa.func @func_lt_f32() -> i32 {
     %0 = wasmssa.const 5.000000e+00 : f32
     %1 = wasmssa.const 1.400000e+01 : f32
     %2 = wasmssa.lt %0 %1 : f32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_le_f32() -> i32 {
+  wasmssa.func @func_le_f32() -> i32 {
     %0 = wasmssa.const 5.000000e+00 : f32
     %1 = wasmssa.const 1.400000e+01 : f32
     %2 = wasmssa.le %0 %1 : f32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_gt_f32() -> i32 {
+  wasmssa.func @func_gt_f32() -> i32 {
     %0 = wasmssa.const 5.000000e+00 : f32
     %1 = wasmssa.const 1.400000e+01 : f32
     %2 = wasmssa.gt %0 %1 : f32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_ge_f32() -> i32 {
+  wasmssa.func @func_ge_f32() -> i32 {
     %0 = wasmssa.const 5.000000e+00 : f32
     %1 = wasmssa.const 1.400000e+01 : f32
     %2 = wasmssa.ge %0 %1 : f32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_lt_f64() -> i32 {
+  wasmssa.func @func_lt_f64() -> i32 {
     %0 = wasmssa.const 5.000000e+00 : f64
     %1 = wasmssa.const 1.400000e+01 : f64
     %2 = wasmssa.lt %0 %1 : f64 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_le_f64() -> i32 {
+  wasmssa.func @func_le_f64() -> i32 {
     %0 = wasmssa.const 5.000000e+00 : f64
     %1 = wasmssa.const 1.400000e+01 : f64
     %2 = wasmssa.le %0 %1 : f64 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_gt_f64() -> i32 {
+  wasmssa.func @func_gt_f64() -> i32 {
     %0 = wasmssa.const 5.000000e+00 : f64
     %1 = wasmssa.const 1.400000e+01 : f64
     %2 = wasmssa.gt %0 %1 : f64 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_ge_f64() -> i32 {
+  wasmssa.func @func_ge_f64() -> i32 {
     %0 = wasmssa.const 5.000000e+00 : f64
     %1 = wasmssa.const 1.400000e+01 : f64
     %2 = wasmssa.ge %0 %1 : f64 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_eq_i32() -> i32 {
+  wasmssa.func @func_eq_i32() -> i32 {
     %0 = wasmssa.const 12 : i32
     %1 = wasmssa.const 50 : i32
     %2 = wasmssa.eq %0 %1 : i32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_eq_i64() -> i32 {
+  wasmssa.func @func_eq_i64() -> i32 {
     %0 = wasmssa.const 20 : i64
     %1 = wasmssa.const 5 : i64
     %2 = wasmssa.eq %0 %1 : i64 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_eq_f32() -> i32 {
+  wasmssa.func @func_eq_f32() -> i32 {
     %0 = wasmssa.const 5.000000e+00 : f32
     %1 = wasmssa.const 1.400000e+01 : f32
     %2 = wasmssa.eq %0 %1 : f32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_eq_f64() -> i32 {
+  wasmssa.func @func_eq_f64() -> i32 {
     %0 = wasmssa.const 1.700000e+01 : f64
     %1 = wasmssa.const 0.000000e+00 : f64
     %2 = wasmssa.eq %0 %1 : f64 -> i32
     wasmssa.return %2 : i32
   }
-    wasmssa.func nested @func_ne_i32() -> i32 {
+    wasmssa.func @func_ne_i32() -> i32 {
     %0 = wasmssa.const 12 : i32
     %1 = wasmssa.const 50 : i32
     %2 = wasmssa.ne %0 %1 : i32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_ne_i64() -> i32 {
+  wasmssa.func @func_ne_i64() -> i32 {
     %0 = wasmssa.const 20 : i64
     %1 = wasmssa.const 5 : i64
     %2 = wasmssa.ne %0 %1 : i64 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_ne_f32() -> i32 {
+  wasmssa.func @func_ne_f32() -> i32 {
     %0 = wasmssa.const 5.000000e+00 : f32
     %1 = wasmssa.const 1.400000e+01 : f32
     %2 = wasmssa.ne %0 %1 : f32 -> i32
     wasmssa.return %2 : i32
   }
-  wasmssa.func nested @func_ne_f64() -> i32 {
+  wasmssa.func @func_ne_f64() -> i32 {
     %0 = wasmssa.const 1.700000e+01 : f64
     %1 = wasmssa.const 0.000000e+00 : f64
     %2 = wasmssa.ne %0 %1 : f64 -> i32
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-extend-to-arith-ext.mlir b/mlir/test/Conversion/RaiseWasm/wasm-extend-to-arith-ext.mlir
index 90c92001a78d6..2b8bb651bbe5b 100644
--- a/mlir/test/Conversion/RaiseWasm/wasm-extend-to-arith-ext.mlir
+++ b/mlir/test/Conversion/RaiseWasm/wasm-extend-to-arith-ext.mlir
@@ -4,7 +4,7 @@
 // CHECK:           %[[VAL_0:.*]] = arith.constant 10 : i32
 // CHECK:           %[[VAL_1:.*]] = arith.extsi %[[VAL_0]] : i32 to i64
 // CHECK:           return %[[VAL_1]] : i64
-wasmssa.func nested @func_0() -> i64 {
+wasmssa.func @func_0() -> i64 {
   %0 = wasmssa.const 10 : i32
   %1 = wasmssa.extend_i32_s %0 to i64
   wasmssa.return %1 : i64
@@ -14,7 +14,7 @@ wasmssa.func nested @func_0() -> i64 {
 // CHECK:           %[[VAL_0:.*]] = arith.constant 10 : i32
 // CHECK:           %[[VAL_1:.*]] = arith.extui %[[VAL_0]] : i32 to i64
 // CHECK:           return %[[VAL_1]] : i64
-wasmssa.func nested @func_1() -> i64 {
+wasmssa.func @func_1() -> i64 {
   %0 = wasmssa.const 10 : i32
   %1 = wasmssa.extend_i32_u %0 to i64
   wasmssa.return %1 : i64
@@ -25,7 +25,7 @@ wasmssa.func nested @func_1() -> i64 {
 // CHECK:           %[[VAL_1:.*]] = arith.trunci %[[VAL_0]] : i32 to i8
 // CHECK:           %[[VAL_2:.*]] = arith.extsi %[[VAL_1]] : i8 to i32
 // CHECK:           return %[[VAL_2]] : i32
-wasmssa.func nested @func_2() -> i32 {
+wasmssa.func @func_2() -> i32 {
   %0 = wasmssa.const 10 : i32
   %1 = wasmssa.extend 8 low bits from %0: i32
   wasmssa.return %1 : i32
@@ -36,7 +36,7 @@ wasmssa.func nested @func_2() -> i32 {
 // CHECK:           %[[VAL_1:.*]] = arith.trunci %[[VAL_0]] : i32 to i16
 // CHECK:           %[[VAL_2:.*]] = arith.extsi %[[VAL_1]] : i16 to i32
 // CHECK:           return %[[VAL_2]] : i32
-wasmssa.func nested @func_3() -> i32 {
+wasmssa.func @func_3() -> i32 {
   %0 = wasmssa.const 10 : i32
   %1 = wasmssa.extend 16 low bits from %0: i32
   wasmssa.return %1 : i32
@@ -47,7 +47,7 @@ wasmssa.func nested @func_3() -> i32 {
 // CHECK:           %[[VAL_1:.*]] = arith.trunci %[[VAL_0]] : i64 to i8
 // CHECK:           %[[VAL_2:.*]] = arith.extsi %[[VAL_1]] : i8 to i64
 // CHECK:           return %[[VAL_2]] : i64
-wasmssa.func nested @func_4() -> i64 {
+wasmssa.func @func_4() -> i64 {
   %0 = wasmssa.const 10 : i64
   %1 = wasmssa.extend 8 low bits from %0: i64
   wasmssa.return %1 : i64
@@ -58,7 +58,7 @@ wasmssa.func nested @func_4() -> i64 {
 // CHECK:           %[[VAL_1:.*]] = arith.trunci %[[VAL_0]] : i64 to i16
 // CHECK:           %[[VAL_2:.*]] = arith.extsi %[[VAL_1]] : i16 to i64
 // CHECK:           return %[[VAL_2]] : i64
-wasmssa.func nested @func_5() -> i64 {
+wasmssa.func @func_5() -> i64 {
   %0 = wasmssa.const 10 : i64
   %1 = wasmssa.extend 16 low bits from %0: i64
   wasmssa.return %1 : i64
@@ -69,7 +69,7 @@ wasmssa.func nested @func_5() -> i64 {
 // CHECK:           %[[VAL_1:.*]] = arith.trunci %[[VAL_0]] : i64 to i32
 // CHECK:           %[[VAL_2:.*]] = arith.extsi %[[VAL_1]] : i32 to i64
 // CHECK:           return %[[VAL_2]] : i64
-wasmssa.func nested @func_6() -> i64 {
+wasmssa.func @func_6() -> i64 {
   %0 = wasmssa.const 10 : i64
   %1 = wasmssa.extend 32 low bits from %0: i64
   wasmssa.return %1 : i64
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-loop-to-cf.mlir b/mlir/test/Conversion/RaiseWasm/wasm-loop-to-cf.mlir
index e49909cc9417e..6ab812008a2f8 100644
--- a/mlir/test/Conversion/RaiseWasm/wasm-loop-to-cf.mlir
+++ b/mlir/test/Conversion/RaiseWasm/wasm-loop-to-cf.mlir
@@ -2,7 +2,7 @@
 // RUN: mlir-opt --split-input-file %s --raise-wasm-mlir --canonicalize -o - | FileCheck --check-prefix=CHECK-CANONICAL %s
 
 module {
-  wasmssa.func nested @func_0() {
+  wasmssa.func @func_0() {
     wasmssa.loop : {
       wasmssa.block_return
     }> ^bb1
@@ -27,7 +27,7 @@ module {
 // -----
 
 module {
-  wasmssa.func nested @func_0() -> i32 {
+  wasmssa.func @func_0() -> i32 {
     %0 = wasmssa.local of type i32
     wasmssa.loop : {
       %1 = wasmssa.local_get %0 : ref to i32
@@ -67,7 +67,7 @@ module {
 // -----
 
 module {
-  wasmssa.func nested @func_0() {
+  wasmssa.func @func_0() {
     %0 = wasmssa.local of type i32
     wasmssa.loop : {
       %1 = wasmssa.local_get %0 : ref to i32
@@ -117,7 +117,7 @@ module {
 // -----
 
 module {
-  wasmssa.func nested @func_0() {
+  wasmssa.func @func_0() {
     %0 = wasmssa.local of type i32
     %1 = wasmssa.local of type i32
     wasmssa.loop : {
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-rotl-to-arith.mlir b/mlir/test/Conversion/RaiseWasm/wasm-rotl-to-arith.mlir
index 91e929bd5ff35..b69f88afd4d7c 100644
--- a/mlir/test/Conversion/RaiseWasm/wasm-rotl-to-arith.mlir
+++ b/mlir/test/Conversion/RaiseWasm/wasm-rotl-to-arith.mlir
@@ -31,7 +31,7 @@
 
 // CHECK:           %[[RES:.*]] = arith.ori %[[SHRU]], %[[SHL]] : i32
 // CHECK:           return %[[RES]] : i32
-wasmssa.func nested @rotl_i32(%arg0: !wasmssa<local ref to i32>, %arg1: !wasmssa<local ref to i32>) -> i32 {
+wasmssa.func @rotl_i32(%arg0: !wasmssa<local ref to i32>, %arg1: !wasmssa<local ref to i32>) -> i32 {
     %v0 = wasmssa.local_get %arg0 : ref to i32
     %v1 = wasmssa.local_get %arg1 : ref to i32
 
@@ -66,7 +66,7 @@ wasmssa.func nested @rotl_i32(%arg0: !wasmssa<local ref to i32>, %arg1: !wasmssa
 // Form final result.
 // CHECK:           %[[RES:.*]] = arith.ori %[[SHRU]], %[[SHL]] : i64
 // CHECK:           return %[[RES]] : i64
-wasmssa.func nested @rotl_i64(%arg0: !wasmssa<local ref to i64>, %arg1: !wasmssa<local ref to i64>) -> i64 {
+wasmssa.func @rotl_i64(%arg0: !wasmssa<local ref to i64>, %arg1: !wasmssa<local ref to i64>) -> i64 {
     %v0 = wasmssa.local_get %arg0 : ref to i64
     %v1 = wasmssa.local_get %arg1 : ref to i64
 
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-rotr-to-arith.mlir b/mlir/test/Conversion/RaiseWasm/wasm-rotr-to-arith.mlir
index 77e301c3221e3..f0b77271c86dd 100644
--- a/mlir/test/Conversion/RaiseWasm/wasm-rotr-to-arith.mlir
+++ b/mlir/test/Conversion/RaiseWasm/wasm-rotr-to-arith.mlir
@@ -32,7 +32,7 @@
 // CHECK:           %[[RES:.*]] = arith.ori %[[SHRU]], %[[SHL]] : i32
 // CHECK:           return %[[RES]] : i32
 // CHECK:         }
-wasmssa.func nested @rotr_i32(%arg0: !wasmssa<local ref to i32>, %arg1: !wasmssa<local ref to i32>) -> i32 {
+wasmssa.func @rotr_i32(%arg0: !wasmssa<local ref to i32>, %arg1: !wasmssa<local ref to i32>) -> i32 {
     %v0 = wasmssa.local_get %arg0 : ref to i32
     %v1 = wasmssa.local_get %arg1 : ref to i32
 
@@ -68,7 +68,7 @@ wasmssa.func nested @rotr_i32(%arg0: !wasmssa<local ref to i32>, %arg1: !wasmssa
 // CHECK:           %[[RES:.*]] = arith.ori %[[SHRU]], %[[SHL]] : i64
 // CHECK:           return %[[RES]] : i64
 // CHECK:         }
-wasmssa.func nested @rotr_i64(%arg0: !wasmssa<local ref to i64>, %arg1: !wasmssa<local ref to i64>) -> i64 {
+wasmssa.func @rotr_i64(%arg0: !wasmssa<local ref to i64>, %arg1: !wasmssa<local ref to i64>) -> i64 {
     %v0 = wasmssa.local_get %arg0 : ref to i64
     %v1 = wasmssa.local_get %arg1 : ref to i64
 



More information about the Mlir-commits mailing list