[Mlir-commits] [mlir] [MLIR][WASM] Introduce the RaiseWasmMLIRPass to lower WasmSSA MLIR to core dialects (PR #164562)

Ferdinand Lemaire llvmlistbot at llvm.org
Thu Oct 23 01:57:47 PDT 2025


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

>From 3b5ed02e0e2cae307fa68a2ef2257675694e9728 Mon Sep 17 00:00:00 2001
From: Ferdinand Lemaire <ferdinand.lemaire at woven-planet.global>
Date: Thu, 3 Jul 2025 10:38:53 +0900
Subject: [PATCH 1/4] [mlir][wasm] Introduce RaiseWasmMLIRPass - a pass to
 convert Wasm MLIR to lower level MLIR dialects

Introduce the structure of the pass along with conversion of wasm.func, wasm.call and local.get
lowerings for simple functions handling.

--
 Co-authored-by: Luc Forget <luc.forget at woven-planet.global>
 Co-authored-by: Jessica Paquette <jessica.paquette at woven-planet.global>
---
 mlir/include/mlir/Conversion/Passes.h         |   1 +
 mlir/include/mlir/Conversion/Passes.td        |  13 ++
 .../mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h |  30 +++
 mlir/lib/Conversion/CMakeLists.txt            |  14 +-
 mlir/lib/Conversion/RaiseWasm/CMakeLists.txt  |  19 ++
 .../Conversion/RaiseWasm/RaiseWasmMLIR.cpp    | 182 ++++++++++++++++++
 .../RaiseWasm/wasm-func-to-func.mlir          |  35 ++++
 7 files changed, 288 insertions(+), 6 deletions(-)
 create mode 100644 mlir/include/mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h
 create mode 100644 mlir/lib/Conversion/RaiseWasm/CMakeLists.txt
 create mode 100644 mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-func-to-func.mlir

diff --git a/mlir/include/mlir/Conversion/Passes.h b/mlir/include/mlir/Conversion/Passes.h
index 40d866ec7bf10..664bcb00ab45a 100644
--- a/mlir/include/mlir/Conversion/Passes.h
+++ b/mlir/include/mlir/Conversion/Passes.h
@@ -58,6 +58,7 @@
 #include "mlir/Conversion/OpenACCToSCF/ConvertOpenACCToSCF.h"
 #include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h"
 #include "mlir/Conversion/PDLToPDLInterp/PDLToPDLInterp.h"
+#include "mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h"
 #include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h"
 #include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h"
 #include "mlir/Conversion/SCFToEmitC/SCFToEmitC.h"
diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td
index 70e3e45c225db..860e474a067a4 100644
--- a/mlir/include/mlir/Conversion/Passes.td
+++ b/mlir/include/mlir/Conversion/Passes.td
@@ -1582,6 +1582,19 @@ def ConvertVectorToAMX : Pass<"convert-vector-to-amx"> {
   ];
 }
 
+//===----------------------------------------------------------------------===//
+// RaiseWasmMLIR
+//===----------------------------------------------------------------------===//
+
+def RaiseWasmMLIR : Pass<"raise-wasm-mlir"> {
+  let summary = "Convert Wasm dialect to a group of dialect as a bridge to LLVM MLIR conversion";
+  let dependentDialects = [
+    "func::FuncDialect", "arith::ArithDialect", "cf::ControlFlowDialect",
+    "memref::MemRefDialect", "vector::VectorDialect", "wasmssa::WasmSSADialect",
+    "math::MathDialect"
+  ];
+}
+
 //===----------------------------------------------------------------------===//
 // XeVMToLLVM
 //===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h b/mlir/include/mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h
new file mode 100644
index 0000000000000..a54fc45b5d048
--- /dev/null
+++ b/mlir/include/mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h
@@ -0,0 +1,30 @@
+//===- RaiseWasmMLIR.h - Convert wasm to standard dialects ------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_CONVERSION_RAISEWASM_RAISEWASMMLIR_H
+#define MLIR_CONVERSION_RAISEWASM_RAISEWASMMLIR_H
+
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/Transforms/DialectConversion.h"
+
+namespace mlir {
+class Pass;
+class RewritePatternSet;
+
+#define GEN_PASS_DECL_RAISEWASMMLIR
+#include "mlir/Conversion/Passes.h.inc"
+
+/// Collect a set of patterns to convert from the Wasm dialect to standard dialects.
+void populateRaiseWasmMLIRConversionPatterns(TypeConverter&, RewritePatternSet &);
+
+/// Create a pass to convert ops from WasmDialect to standard dialects.
+std::unique_ptr<Pass> createRaiseWasmMLIRPass();
+
+} // namespace mlir
+
+#endif // MLIR_CONVERSION_RAISEWASM_RAISEWASMMLIR_H
diff --git a/mlir/lib/Conversion/CMakeLists.txt b/mlir/lib/Conversion/CMakeLists.txt
index bebf1b8fff3f9..0f1c3c60ba182 100644
--- a/mlir/lib/Conversion/CMakeLists.txt
+++ b/mlir/lib/Conversion/CMakeLists.txt
@@ -1,5 +1,6 @@
-add_subdirectory(AffineToStandard)
+
 add_subdirectory(AMDGPUToROCDL)
+add_subdirectory(AffineToStandard)
 add_subdirectory(ArithCommon)
 add_subdirectory(ArithToAMDGPU)
 add_subdirectory(ArithToArmSME)
@@ -7,14 +8,14 @@ add_subdirectory(ArithToEmitC)
 add_subdirectory(ArithToLLVM)
 add_subdirectory(ArithToSPIRV)
 add_subdirectory(ArmNeon2dToIntr)
-add_subdirectory(ArmSMEToSCF)
 add_subdirectory(ArmSMEToLLVM)
+add_subdirectory(ArmSMEToSCF)
 add_subdirectory(AsyncToLLVM)
 add_subdirectory(BufferizationToMemRef)
 add_subdirectory(ComplexCommon)
-add_subdirectory(ComplexToLibm)
 add_subdirectory(ComplexToROCDLLibraryCalls)
 add_subdirectory(ComplexToLLVM)
+add_subdirectory(ComplexToLibm)
 add_subdirectory(ComplexToSPIRV)
 add_subdirectory(ComplexToStandard)
 add_subdirectory(ControlFlowToLLVM)
@@ -32,12 +33,12 @@ add_subdirectory(GPUToROCDL)
 add_subdirectory(GPUToSPIRV)
 add_subdirectory(IndexToLLVM)
 add_subdirectory(IndexToSPIRV)
-add_subdirectory(LinalgToStandard)
 add_subdirectory(LLVMCommon)
+add_subdirectory(LinalgToStandard)
 add_subdirectory(MathToEmitC)
 add_subdirectory(MathToFuncs)
-add_subdirectory(MathToLibm)
 add_subdirectory(MathToLLVM)
+add_subdirectory(MathToLibm)
 add_subdirectory(MathToROCDL)
 add_subdirectory(MathToSPIRV)
 add_subdirectory(MathToXeVM)
@@ -52,15 +53,16 @@ add_subdirectory(OpenACCToSCF)
 add_subdirectory(OpenMPToLLVM)
 add_subdirectory(PDLToPDLInterp)
 add_subdirectory(PtrToLLVM)
+add_subdirectory(RaiseWasm)
 add_subdirectory(ReconcileUnrealizedCasts)
 add_subdirectory(SCFToControlFlow)
 add_subdirectory(SCFToEmitC)
 add_subdirectory(SCFToGPU)
 add_subdirectory(SCFToOpenMP)
 add_subdirectory(SCFToSPIRV)
-add_subdirectory(ShapeToStandard)
 add_subdirectory(SPIRVCommon)
 add_subdirectory(SPIRVToLLVM)
+add_subdirectory(ShapeToStandard)
 add_subdirectory(TensorToLinalg)
 add_subdirectory(TensorToSPIRV)
 add_subdirectory(TosaToArith)
diff --git a/mlir/lib/Conversion/RaiseWasm/CMakeLists.txt b/mlir/lib/Conversion/RaiseWasm/CMakeLists.txt
new file mode 100644
index 0000000000000..43b5fd79e49df
--- /dev/null
+++ b/mlir/lib/Conversion/RaiseWasm/CMakeLists.txt
@@ -0,0 +1,19 @@
+add_mlir_conversion_library(MLIRWasmRaise
+  RaiseWasmMLIR.cpp
+
+  ADDITIONAL_HEADER_DIRS
+  ${MLIR_MAIN_INCLUDE_DIR}/mlir/Conversion/RaiseWasm
+
+  DEPENDS
+  MLIRConversionPassIncGen
+
+  LINK_LIBS PUBLIC
+  MLIRArithDialect
+  MLIRControlFlowDialect
+  MLIRFuncDialect
+  MLIRMathDialect
+  MLIRMemRefDialect
+  MLIRTransforms
+  MLIRVectorDialect
+  MLIRWasmSSADialect
+  )
diff --git a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
new file mode 100644
index 0000000000000..872fa7427dc84
--- /dev/null
+++ b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
@@ -0,0 +1,182 @@
+//===- RaiseWasmMLIR.cpp - Convert Wasm to less abstract dialects ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements lowering of wasm operations to standard dialects ops.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h"
+
+#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
+#include "mlir/Dialect/Func/IR/FuncOps.h"
+#include "mlir/Dialect/Math/IR/Math.h"
+#include "mlir/Dialect/MemRef/IR/MemRef.h"
+#include "mlir/Dialect/Vector/IR/VectorOps.h"
+#include "mlir/Dialect/WasmSSA/IR/WasmSSA.h"
+#include "mlir/IR/BuiltinDialect.h"
+#include "mlir/IR/ValueRange.h"
+#include "mlir/Transforms/DialectConversion.h"
+#include "mlir/Transforms/Passes.h"
+#include "llvm/Support/LogicalResult.h"
+
+#include <optional>
+
+
+#define DEBUG_TYPE "wasm-convert"
+
+namespace mlir {
+#define GEN_PASS_DEF_RAISEWASMMLIR
+#include "mlir/Conversion/Passes.h.inc"
+} // namespace mlir
+
+using namespace mlir;
+using namespace mlir::wasmssa;
+
+namespace {
+
+struct WasmCallOpConversion : OpConversionPattern<FuncCallOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  LogicalResult
+  matchAndRewrite(FuncCallOp funcCallOp, FuncCallOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    rewriter.replaceOpWithNewOp<func::CallOp>(
+        funcCallOp, funcCallOp.getCallee(), funcCallOp.getResults().getTypes(),
+        funcCallOp.getOperands());
+    return success();
+  }
+};
+
+struct WasmFuncImportOpConversion : OpConversionPattern<FuncImportOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  LogicalResult
+  matchAndRewrite(FuncImportOp funcImportOp, FuncImportOp::Adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    auto nFunc = rewriter.replaceOpWithNewOp<func::FuncOp>(
+        funcImportOp, funcImportOp.getSymName(),
+        funcImportOp.getType());
+    nFunc.setVisibility(SymbolTable::Visibility::Private);
+    return success();
+  }
+};
+
+struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
+  using OpConversionPattern::OpConversionPattern;
+  LogicalResult
+  matchAndRewrite(FuncOp funcOp, FuncOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    auto newFunc = rewriter.create<func::FuncOp>(
+        funcOp->getLoc(), funcOp.getSymName(), funcOp.getFunctionType());
+    rewriter.cloneRegionBefore(funcOp.getBody(), newFunc.getBody(),
+                               newFunc.getBody().end());
+    Block *oldEntryBlock = &newFunc.getBody().front();
+    auto blockArgTypes = oldEntryBlock->getArgumentTypes();
+    TypeConverter::SignatureConversion sC{oldEntryBlock->getNumArguments()};
+    auto numArgs = blockArgTypes.size();
+    for (size_t i = 0; i < numArgs; ++i) {
+      auto argType = dyn_cast<LocalRefType>(blockArgTypes[i]);
+      if (!argType)
+        return failure();
+      sC.addInputs(i, argType.getElementType());
+    }
+
+    rewriter.applySignatureConversion(oldEntryBlock, sC, getTypeConverter());
+    rewriter.replaceOp(funcOp, newFunc);
+    return success();
+  }
+};
+
+struct WasmLocalGetConversion : OpConversionPattern<LocalGetOp> {
+  using OpConversionPattern::OpConversionPattern;
+  LogicalResult
+  matchAndRewrite(LocalGetOp localGetOp, LocalGetOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    rewriter.replaceOpWithNewOp<memref::LoadOp>(localGetOp,
+                                                localGetOp.getResult().getType(),
+                                                adaptor.getLocalVar(),
+                                              ValueRange{});
+    return success();
+  }
+};
+
+struct WasmReturnOpConversion : OpConversionPattern<ReturnOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  LogicalResult
+  matchAndRewrite(ReturnOp returnOp, ReturnOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    rewriter.replaceOpWithNewOp<func::ReturnOp>(returnOp, adaptor.getOperands());
+    return success();
+  }
+};
+
+struct RaiseWasmMLIRPass
+    : public impl::RaiseWasmMLIRBase<RaiseWasmMLIRPass> {
+  void runOnOperation() override {
+    ConversionTarget target{getContext()};
+    target.addIllegalDialect<WasmSSADialect>();
+    target.addLegalDialect<arith::ArithDialect, BuiltinDialect,
+                           cf::ControlFlowDialect, func::FuncDialect,
+                           memref::MemRefDialect, math::MathDialect>();
+    RewritePatternSet patterns(&getContext());
+    TypeConverter tc{};
+    tc.addConversion([](Type type) -> std::optional<Type> { return type; });
+    tc.addConversion([](LocalRefType type)->std::optional<Type> {
+      return MemRefType::get({}, type.getElementType());
+    });
+    tc.addTargetMaterialization([](OpBuilder& builder, MemRefType destType, ValueRange values, Location loc)->Value{
+      if (values.size() != 1 || values.front().getType() != destType.getElementType())
+        return {};
+      auto localVar = builder.create<memref::AllocaOp>(loc, destType);
+      builder.create<memref::StoreOp>(loc, values.front(), localVar.getResult());
+      return localVar.getResult();
+    });
+    populateRaiseWasmMLIRConversionPatterns(tc, patterns);
+
+    llvm::DenseMap<StringAttr, StringAttr> idxSymToImportSym{};
+    auto *topOp = getOperation();
+    topOp->walk([&idxSymToImportSym, this](ImportOpInterface importOp) {
+      auto const qualifiedImportName = importOp.getQualifiedImportName();
+      auto qualNameAttr = StringAttr::get(&getContext(), qualifiedImportName);
+      idxSymToImportSym.insert(
+          std::make_pair(importOp.getSymbolName(), qualNameAttr));
+    });
+
+    if (failed(applyFullConversion(topOp, target, std::move(patterns))))
+      return signalPassFailure();
+
+    auto symTable = SymbolTable{topOp};
+    for (auto &[oldName, newName] : idxSymToImportSym) {
+      if (failed(symTable.rename(oldName, newName)))
+        return signalPassFailure();
+    }
+  }
+};
+} // namespace
+
+void mlir::populateRaiseWasmMLIRConversionPatterns(
+    TypeConverter &tc, RewritePatternSet &patternSet) {
+  auto *ctx = patternSet.getContext();
+  // Disable clang-format in patternSet for readability + small diffs.
+  // clang-format off
+  patternSet
+      .add<
+           WasmCallOpConversion,
+           WasmFuncImportOpConversion,
+           WasmFuncOpConversion,
+           WasmLocalGetConversion,
+           WasmReturnOpConversion
+           >(tc, ctx);
+  // clang-format on
+}
+
+std::unique_ptr<Pass> mlir::createRaiseWasmMLIRPass() {
+  return std::make_unique<RaiseWasmMLIRPass>();
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-func-to-func.mlir b/mlir/test/Conversion/RaiseWasm/wasm-func-to-func.mlir
new file mode 100644
index 0000000000000..65a6831b442ca
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-func-to-func.mlir
@@ -0,0 +1,35 @@
+// RUN: mlir-opt %s --raise-wasm-mlir | FileCheck %s
+
+
+// CHECK-LABEL:   func.func @callee(
+// CHECK-SAME:                      %[[ARG0:.*]]: i32) -> i32 {
+wasmssa.func exported @callee(%arg0: !wasmssa<local ref to 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>
+%v0 = wasmssa.local_get %arg0 : ref to i32
+// CHECK:           return %[[VAL_1]] : i32
+wasmssa.return %v0 : i32
+}
+
+wasmssa.func exported @caller(%arg0: !wasmssa<local ref to 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>
+%v0 = wasmssa.local_get %arg0 : ref to i32
+// CHECK:           %[[VAL_2:.*]] = call @callee(%[[VAL_1]]) : (i32) -> i32
+%0 = wasmssa.call @callee (%v0) : (i32) -> i32
+// CHECK:           return %[[VAL_2]] : i32
+wasmssa.return %0 : i32
+}
+
+// CHECK-LABEL:         func.func private @"my_module::foo"() -> i32
+wasmssa.import_func "foo" from "my_module" as @func_0 {sym_visibility = "nested", type = () -> (i32)}
+
+// CHECK-LABEL:   func.func @user_of_func0() -> i32 {
+wasmssa.func exported @user_of_func0() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = call @"my_module::foo"() : () -> i32
+%0 = wasmssa.call @func_0 : () -> i32
+// CHECK:           return %[[VAL_0]] : i32
+wasmssa.return %0 : i32
+}

>From 86a772d2cada896a390123fcc4d488c02906f423 Mon Sep 17 00:00:00 2001
From: Ferdinand Lemaire <ferdinand.lemaire at woven-planet.global>
Date: Thu, 3 Jul 2025 11:06:55 +0900
Subject: [PATCH 2/4] [mlir][wasm] RaiseWasmMLIRPass: Local and global
 variables and arithmetic ops

--
 Co-authored-by: Luc Forget <luc.forget at woven-planet.global>
 Co-authored-by: Jessica Paquette <jessica.paquette at woven-planet.global>
---
 .../mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h |   6 +-
 mlir/lib/Conversion/CMakeLists.txt            |  13 +-
 .../Conversion/RaiseWasm/RaiseWasmMLIR.cpp    | 320 +++++++++++++++++-
 .../RaiseWasm/wasm-abs-to-math-abs.mlir       |  27 ++
 .../RaiseWasm/wasm-add-to-arith-add.mlir      |  79 +++++
 .../RaiseWasm/wasm-and-to-arith-and.mlir      |  38 +++
 .../RaiseWasm/wasm-ceil-to-math-ceil.mlir     |  24 ++
 .../RaiseWasm/wasm-clz-to-math-clz.mlir       |  27 ++
 .../RaiseWasm/wasm-const-to-arith-const.mlir  |  15 +
 .../RaiseWasm/wasm-convert-to-arith-tofp.mlir |  81 +++++
 .../wasm-copysign-to-math-copysign.mlir       |  38 +++
 .../RaiseWasm/wasm-ctz-to-math-ctz.mlir       |  27 ++
 .../RaiseWasm/wasm-demote-to-arith-trunc.mlir |  14 +
 .../RaiseWasm/wasm-div-to-arith-div.mlir      | 109 ++++++
 .../RaiseWasm/wasm-floor-to-math-floor.mlir   |  24 ++
 .../wasm-global-to-memref-global.mlir         |  43 +++
 .../RaiseWasm/wasm-local-to-memref.mlir       |  68 ++++
 .../RaiseWasm/wasm-max-to-arith-maximumf.mlir |  37 ++
 .../RaiseWasm/wasm-min-to-arith-minimumf.mlir |  37 ++
 .../RaiseWasm/wasm-mul-to-arith-mul.mlir      |  78 +++++
 .../RaiseWasm/wasm-neg-to-arith-neg.mlir      |  27 ++
 .../RaiseWasm/wasm-or-to-arith-or.mlir        |  38 +++
 .../RaiseWasm/wasm-popcnt-to-math-ctpop.mlir  |  27 ++
 .../RaiseWasm/wasm-promote-to-arith-ext.mlir  |  11 +
 .../wasm-reinterpret-to-arith-bitcast.mlir    |  42 +++
 .../RaiseWasm/wasm-rem-to-arith-rem.mlir      |  74 ++++
 .../RaiseWasm/wasm-shl-to-arith-shl.mlir      |  38 +++
 .../RaiseWasm/wasm-shr_s-to-arith-shrs.mlir   |  38 +++
 .../RaiseWasm/wasm-shr_u-to-arith-shru.mlir   |  37 ++
 .../RaiseWasm/wasm-sqrt-to-math-sqrt.mlir     |  27 ++
 .../RaiseWasm/wasm-sub-to-arith-sub.mlir      |  80 +++++
 .../RaiseWasm/wasm-trunc-to-math-trunc.mlir   |  24 ++
 .../RaiseWasm/wasm-wrap-to-arith-trunc.mlir   |  17 +
 .../RaiseWasm/wasm-xor-to-arith-xor.mlir      |  37 ++
 34 files changed, 1595 insertions(+), 27 deletions(-)
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-abs-to-math-abs.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-add-to-arith-add.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-and-to-arith-and.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-ceil-to-math-ceil.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-clz-to-math-clz.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-const-to-arith-const.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-convert-to-arith-tofp.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-copysign-to-math-copysign.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-ctz-to-math-ctz.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-demote-to-arith-trunc.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-div-to-arith-div.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-floor-to-math-floor.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-global-to-memref-global.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-local-to-memref.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-max-to-arith-maximumf.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-min-to-arith-minimumf.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-mul-to-arith-mul.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-neg-to-arith-neg.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-or-to-arith-or.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-popcnt-to-math-ctpop.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-promote-to-arith-ext.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-reinterpret-to-arith-bitcast.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-rem-to-arith-rem.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-shl-to-arith-shl.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-shr_s-to-arith-shrs.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-shr_u-to-arith-shru.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-sqrt-to-math-sqrt.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-sub-to-arith-sub.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-trunc-to-math-trunc.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-wrap-to-arith-trunc.mlir
 create mode 100644 mlir/test/Conversion/RaiseWasm/wasm-xor-to-arith-xor.mlir

diff --git a/mlir/include/mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h b/mlir/include/mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h
index a54fc45b5d048..3faf9dc255a11 100644
--- a/mlir/include/mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h
+++ b/mlir/include/mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h
@@ -19,8 +19,10 @@ class RewritePatternSet;
 #define GEN_PASS_DECL_RAISEWASMMLIR
 #include "mlir/Conversion/Passes.h.inc"
 
-/// Collect a set of patterns to convert from the Wasm dialect to standard dialects.
-void populateRaiseWasmMLIRConversionPatterns(TypeConverter&, RewritePatternSet &);
+/// Collect a set of patterns to convert from the Wasm dialect to standard
+/// dialects.
+void populateRaiseWasmMLIRConversionPatterns(TypeConverter &,
+                                             RewritePatternSet &);
 
 /// Create a pass to convert ops from WasmDialect to standard dialects.
 std::unique_ptr<Pass> createRaiseWasmMLIRPass();
diff --git a/mlir/lib/Conversion/CMakeLists.txt b/mlir/lib/Conversion/CMakeLists.txt
index 0f1c3c60ba182..c43b5f3ad5489 100644
--- a/mlir/lib/Conversion/CMakeLists.txt
+++ b/mlir/lib/Conversion/CMakeLists.txt
@@ -1,6 +1,5 @@
-
-add_subdirectory(AMDGPUToROCDL)
 add_subdirectory(AffineToStandard)
+add_subdirectory(AMDGPUToROCDL)
 add_subdirectory(ArithCommon)
 add_subdirectory(ArithToAMDGPU)
 add_subdirectory(ArithToArmSME)
@@ -8,14 +7,14 @@ add_subdirectory(ArithToEmitC)
 add_subdirectory(ArithToLLVM)
 add_subdirectory(ArithToSPIRV)
 add_subdirectory(ArmNeon2dToIntr)
-add_subdirectory(ArmSMEToLLVM)
 add_subdirectory(ArmSMEToSCF)
+add_subdirectory(ArmSMEToLLVM)
 add_subdirectory(AsyncToLLVM)
 add_subdirectory(BufferizationToMemRef)
 add_subdirectory(ComplexCommon)
+add_subdirectory(ComplexToLibm)
 add_subdirectory(ComplexToROCDLLibraryCalls)
 add_subdirectory(ComplexToLLVM)
-add_subdirectory(ComplexToLibm)
 add_subdirectory(ComplexToSPIRV)
 add_subdirectory(ComplexToStandard)
 add_subdirectory(ControlFlowToLLVM)
@@ -33,12 +32,12 @@ add_subdirectory(GPUToROCDL)
 add_subdirectory(GPUToSPIRV)
 add_subdirectory(IndexToLLVM)
 add_subdirectory(IndexToSPIRV)
-add_subdirectory(LLVMCommon)
 add_subdirectory(LinalgToStandard)
+add_subdirectory(LLVMCommon)
 add_subdirectory(MathToEmitC)
 add_subdirectory(MathToFuncs)
-add_subdirectory(MathToLLVM)
 add_subdirectory(MathToLibm)
+add_subdirectory(MathToLLVM)
 add_subdirectory(MathToROCDL)
 add_subdirectory(MathToSPIRV)
 add_subdirectory(MathToXeVM)
@@ -60,9 +59,9 @@ add_subdirectory(SCFToEmitC)
 add_subdirectory(SCFToGPU)
 add_subdirectory(SCFToOpenMP)
 add_subdirectory(SCFToSPIRV)
+add_subdirectory(ShapeToStandard)
 add_subdirectory(SPIRVCommon)
 add_subdirectory(SPIRVToLLVM)
-add_subdirectory(ShapeToStandard)
 add_subdirectory(TensorToLinalg)
 add_subdirectory(TensorToSPIRV)
 add_subdirectory(TosaToArith)
diff --git a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
index 872fa7427dc84..3970903164286 100644
--- a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
+++ b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
@@ -1,4 +1,5 @@
-//===- RaiseWasmMLIR.cpp - Convert Wasm to less abstract dialects ---*- C++ -*-===//
+//===- RaiseWasmMLIR.cpp - Convert Wasm to less abstract dialects ---*- C++
+//-*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -19,15 +20,14 @@
 #include "mlir/Dialect/MemRef/IR/MemRef.h"
 #include "mlir/Dialect/Vector/IR/VectorOps.h"
 #include "mlir/Dialect/WasmSSA/IR/WasmSSA.h"
+#include "mlir/IR/BuiltinAttributes.h"
 #include "mlir/IR/BuiltinDialect.h"
 #include "mlir/IR/ValueRange.h"
 #include "mlir/Transforms/DialectConversion.h"
 #include "mlir/Transforms/Passes.h"
 #include "llvm/Support/LogicalResult.h"
-
 #include <optional>
 
-
 #define DEBUG_TYPE "wasm-convert"
 
 namespace mlir {
@@ -37,9 +37,93 @@ namespace mlir {
 
 using namespace mlir;
 using namespace mlir::wasmssa;
-
 namespace {
 
+template <typename SourceOp, typename TargetIntOp, typename TargetFPOp>
+struct IntFPDispatchMappingConversion : OpConversionPattern<SourceOp> {
+  using OpConversionPattern<SourceOp>::OpConversionPattern;
+
+  LogicalResult
+  matchAndRewrite(SourceOp srcOp, typename SourceOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    Type type = srcOp.getRhs().getType();
+    if (type.isInteger()) {
+      rewriter.replaceOpWithNewOp<TargetIntOp>(srcOp, srcOp->getResultTypes(),
+                                               adaptor.getOperands());
+      return success();
+    }
+    if (!type.isFloat())
+      return failure();
+    rewriter.replaceOpWithNewOp<TargetFPOp>(srcOp, srcOp->getResultTypes(),
+                                            adaptor.getOperands());
+    return success();
+  }
+};
+
+using WasmAddOpConversion =
+    IntFPDispatchMappingConversion<AddOp, arith::AddIOp, arith::AddFOp>;
+using WasmMulOpConversion =
+    IntFPDispatchMappingConversion<MulOp, arith::MulIOp, arith::MulFOp>;
+using WasmSubOpConversion =
+    IntFPDispatchMappingConversion<SubOp, arith::SubIOp, arith::SubFOp>;
+
+/// Convert a k-ary source operation \p SourceOp into an operation \p TargetOp.
+/// Both \p SourceOp and \p TargetOp must have the same number of operands.
+template <typename SourceOp, typename TargetOp>
+struct OpMappingConversion : OpConversionPattern<SourceOp> {
+  using OpConversionPattern<SourceOp>::OpConversionPattern;
+
+  LogicalResult
+  matchAndRewrite(SourceOp srcOp, typename SourceOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    rewriter.replaceOpWithNewOp<TargetOp>(srcOp, srcOp->getResultTypes(),
+                                          adaptor.getOperands());
+    return success();
+  }
+};
+
+using WasmAndOpConversion = OpMappingConversion<AndOp, arith::AndIOp>;
+using WasmCeilOpConversion = OpMappingConversion<CeilOp, math::CeilOp>;
+/// TODO: SIToFP and UIToFP don't allow specification of the floating point
+/// rounding mode
+using WasmConvertSOpConversion =
+    OpMappingConversion<ConvertSOp, arith::SIToFPOp>;
+using WasmConvertUOpConversion =
+    OpMappingConversion<ConvertUOp, arith::UIToFPOp>;
+using WasmDemoteOpConversion = OpMappingConversion<DemoteOp, arith::TruncFOp>;
+using WasmDivFPOpConversion = OpMappingConversion<DivOp, arith::DivFOp>;
+using WasmDivSIOpConversion = OpMappingConversion<DivSIOp, arith::DivSIOp>;
+using WasmDivUIOpConversion = OpMappingConversion<DivUIOp, arith::DivUIOp>;
+using WasmExtendSOpConversion =
+    OpMappingConversion<ExtendSI32Op, arith::ExtSIOp>;
+using WasmExtendUOpConversion =
+    OpMappingConversion<ExtendUI32Op, arith::ExtUIOp>;
+using WasmFloorOpConversion = OpMappingConversion<FloorOp, math::FloorOp>;
+using WasmMaxOpConversion = OpMappingConversion<MaxOp, arith::MaximumFOp>;
+using WasmMinOpConversion = OpMappingConversion<MinOp, arith::MinimumFOp>;
+using WasmOrOpConversion = OpMappingConversion<OrOp, arith::OrIOp>;
+using WasmPromoteOpConversion = OpMappingConversion<PromoteOp, arith::ExtFOp>;
+using WasmRemSIOpConversion = OpMappingConversion<RemSIOp, arith::RemSIOp>;
+using WasmRemUIOpConversion = OpMappingConversion<RemUIOp, arith::RemUIOp>;
+using WasmReinterpretOpConversion =
+    OpMappingConversion<ReinterpretOp, arith::BitcastOp>;
+using WasmShLOpConversion = OpMappingConversion<ShLOp, arith::ShLIOp>;
+using WasmShRSOpConversion = OpMappingConversion<ShRSOp, arith::ShRSIOp>;
+using WasmShRUOpConversion = OpMappingConversion<ShRUOp, arith::ShRUIOp>;
+using WasmXOrOpConversion = OpMappingConversion<XOrOp, arith::XOrIOp>;
+using WasmNegOpConversion = OpMappingConversion<NegOp, arith::NegFOp>;
+using WasmCopySignOpConversion =
+    OpMappingConversion<CopySignOp, math::CopySignOp>;
+using WasmClzOpConversion =
+    OpMappingConversion<ClzOp, math::CountLeadingZerosOp>;
+using WasmCtzOpConversion =
+    OpMappingConversion<CtzOp, math::CountTrailingZerosOp>;
+using WasmPopCntOpConversion = OpMappingConversion<PopCntOp, math::CtPopOp>;
+using WasmAbsOpConversion = OpMappingConversion<AbsOp, math::AbsFOp>;
+using WasmTruncOpConversion = OpMappingConversion<TruncOp, math::TruncOp>;
+using WasmSqrtOpConversion = OpMappingConversion<SqrtOp, math::SqrtOp>;
+using WasmWrapOpConversion = OpMappingConversion<WrapOp, arith::TruncIOp>;
+
 struct WasmCallOpConversion : OpConversionPattern<FuncCallOp> {
   using OpConversionPattern::OpConversionPattern;
 
@@ -53,6 +137,17 @@ struct WasmCallOpConversion : OpConversionPattern<FuncCallOp> {
   }
 };
 
+struct WasmConstOpConversion : OpConversionPattern<ConstOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  LogicalResult
+  matchAndRewrite(ConstOp constOp, ConstOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    rewriter.replaceOpWithNewOp<arith::ConstantOp>(constOp, constOp.getValue());
+    return success();
+  }
+};
+
 struct WasmFuncImportOpConversion : OpConversionPattern<FuncImportOp> {
   using OpConversionPattern::OpConversionPattern;
 
@@ -60,8 +155,7 @@ struct WasmFuncImportOpConversion : OpConversionPattern<FuncImportOp> {
   matchAndRewrite(FuncImportOp funcImportOp, FuncImportOp::Adaptor,
                   ConversionPatternRewriter &rewriter) const override {
     auto nFunc = rewriter.replaceOpWithNewOp<func::FuncOp>(
-        funcImportOp, funcImportOp.getSymName(),
-        funcImportOp.getType());
+        funcImportOp, funcImportOp.getSymName(), funcImportOp.getType());
     nFunc.setVisibility(SymbolTable::Visibility::Private);
     return success();
   }
@@ -69,6 +163,7 @@ struct WasmFuncImportOpConversion : OpConversionPattern<FuncImportOp> {
 
 struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
   using OpConversionPattern::OpConversionPattern;
+
   LogicalResult
   matchAndRewrite(FuncOp funcOp, FuncOp::Adaptor adaptor,
                   ConversionPatternRewriter &rewriter) const override {
@@ -93,15 +188,160 @@ struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
   }
 };
 
+struct WasmGlobalImportOpConverter : OpConversionPattern<GlobalImportOp> {
+  using OpConversionPattern::OpConversionPattern;
+  LogicalResult
+  matchAndRewrite(GlobalImportOp gIOp, GlobalImportOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    auto memrefGOp = rewriter.replaceOpWithNewOp<memref::GlobalOp>(
+        gIOp, gIOp.getSymNameAttr(), rewriter.getStringAttr("nested"),
+        TypeAttr::get(MemRefType::get({1}, gIOp.getType())), Attribute{},
+        /*constant*/ UnitAttr{},
+        /*alignment*/ IntegerAttr{});
+    memrefGOp.setConstant(!gIOp.getIsMutable());
+    return success();
+  }
+};
+
+template <typename CRTP, typename OriginOpType>
+struct GlobalOpConverter : OpConversionPattern<GlobalOp> {
+  using OpConversionPattern::OpConversionPattern;
+  LogicalResult
+  matchAndRewrite(GlobalOp globalOp, GlobalOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    ReturnOp rop;
+    globalOp->walk([&rop](ReturnOp op) { rop = op; });
+
+    if (rop->getNumOperands() != 1)
+      return rewriter.notifyMatchFailure(
+          globalOp, "globalOp initializer should return one value exactly");
+
+    auto initializerOp =
+        dyn_cast<OriginOpType>(rop->getOperand(0).getDefiningOp());
+
+    if (!initializerOp)
+      return rewriter.notifyMatchFailure(
+          globalOp, "invalid initializer op type for this pattern");
+
+    return static_cast<CRTP const *>(this)->handleInitializer(
+        globalOp, rewriter, initializerOp);
+  }
+};
+
+struct WasmGlobalWithConstInitConversion
+    : GlobalOpConverter<WasmGlobalWithConstInitConversion, ConstOp> {
+  using GlobalOpConverter::GlobalOpConverter;
+  LogicalResult handleInitializer(GlobalOp globalOp,
+                                  ConversionPatternRewriter &rewriter,
+                                  ConstOp constInit) const {
+    auto initializer =
+        DenseElementsAttr::get(RankedTensorType::get({1}, globalOp.getType()),
+                               ArrayRef<Attribute>{constInit.getValueAttr()});
+    auto globalReplacement = rewriter.replaceOpWithNewOp<memref::GlobalOp>(
+        globalOp, globalOp.getSymNameAttr(), rewriter.getStringAttr("private"),
+        TypeAttr::get(MemRefType::get({1}, globalOp.getType())), initializer,
+        /*constant*/ UnitAttr{},
+        /*alignment*/ IntegerAttr{});
+    globalReplacement.setConstant(!globalOp.getIsMutable());
+    return success();
+  }
+};
+
+struct WasmGlobalWithGetGlobalInitConversion
+    : GlobalOpConverter<WasmGlobalWithGetGlobalInitConversion, GlobalGetOp> {
+  using GlobalOpConverter::GlobalOpConverter;
+  LogicalResult handleInitializer(GlobalOp globalOp,
+                                  ConversionPatternRewriter &rewriter,
+                                  GlobalGetOp constInit) const {
+    auto globalReplacement = rewriter.replaceOpWithNewOp<memref::GlobalOp>(
+        globalOp, globalOp.getSymNameAttr(), rewriter.getStringAttr("private"),
+        TypeAttr::get(MemRefType::get({1}, globalOp.getType())),
+        rewriter.getUnitAttr(),
+        /*constant*/ UnitAttr{},
+        /*alignment*/ IntegerAttr{});
+    globalReplacement.setConstant(!globalOp.getIsMutable());
+    auto loc = globalOp.getLoc();
+    auto initializerName = (globalOp.getSymName() + "::initializer").str();
+    auto globalInitializer = rewriter.create<func::FuncOp>(
+        loc, initializerName, FunctionType::get(getContext(), {}, {}));
+    globalInitializer->setAttr(rewriter.getStringAttr("initializer"),
+                               rewriter.getUnitAttr());
+    auto *initializerBody = globalInitializer.addEntryBlock();
+    auto sip = rewriter.saveInsertionPoint();
+    rewriter.setInsertionPointToStart(initializerBody);
+    auto srcGlobalPtr = rewriter.create<memref::GetGlobalOp>(
+        loc, MemRefType::get({1}, constInit.getType()), constInit.getGlobal());
+    auto destGlobalPtr = rewriter.create<memref::GetGlobalOp>(
+        loc, globalReplacement.getType(), globalReplacement.getSymName());
+    auto idx = rewriter.create<arith::ConstantIndexOp>(loc, 0).getResult();
+    auto loadSrc =
+        rewriter.create<memref::LoadOp>(loc, srcGlobalPtr, ValueRange{idx});
+    rewriter.create<memref::StoreOp>(
+        loc, loadSrc.getResult(), destGlobalPtr.getResult(), ValueRange{idx});
+    rewriter.create<func::ReturnOp>(loc);
+    rewriter.restoreInsertionPoint(sip);
+    return success();
+  }
+};
+
+inline TypedAttr getInitializerAttr(Type t) {
+  assert(t.isIntOrFloat() &&
+         "This helper is intended to use with int and float types");
+  if (t.isInteger())
+    return IntegerAttr::get(t, 0);
+  if (t.isFloat())
+    return FloatAttr::get(t, 0.);
+  return TypedAttr{};
+}
+
+struct WasmLocalConversion : OpConversionPattern<LocalOp> {
+  using OpConversionPattern::OpConversionPattern;
+  LogicalResult
+  matchAndRewrite(LocalOp localOp, LocalOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    auto alloca = rewriter.replaceOpWithNewOp<memref::AllocaOp>(
+        localOp,
+        MemRefType::get({}, localOp.getResult().getType().getElementType()));
+    auto initializer = rewriter.create<arith::ConstantOp>(
+        localOp->getLoc(),
+        getInitializerAttr(localOp.getResult().getType().getElementType()));
+    rewriter.create<memref::StoreOp>(localOp->getLoc(), initializer.getResult(),
+                                     alloca.getResult());
+    return success();
+  }
+};
+
 struct WasmLocalGetConversion : OpConversionPattern<LocalGetOp> {
   using OpConversionPattern::OpConversionPattern;
   LogicalResult
   matchAndRewrite(LocalGetOp localGetOp, LocalGetOp::Adaptor adaptor,
                   ConversionPatternRewriter &rewriter) const override {
-    rewriter.replaceOpWithNewOp<memref::LoadOp>(localGetOp,
-                                                localGetOp.getResult().getType(),
-                                                adaptor.getLocalVar(),
-                                              ValueRange{});
+    rewriter.replaceOpWithNewOp<memref::LoadOp>(
+        localGetOp, localGetOp.getResult().getType(), adaptor.getLocalVar(),
+        ValueRange{});
+    return success();
+  }
+};
+
+struct WasmLocalSetConversion : OpConversionPattern<LocalSetOp> {
+  using OpConversionPattern::OpConversionPattern;
+  LogicalResult
+  matchAndRewrite(LocalSetOp localSetOp, LocalSetOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    rewriter.replaceOpWithNewOp<memref::StoreOp>(
+        localSetOp, adaptor.getValue(), adaptor.getLocalVar(), ValueRange{});
+    return success();
+  }
+};
+
+struct WasmLocalTeeConversion : OpConversionPattern<LocalTeeOp> {
+  using OpConversionPattern::OpConversionPattern;
+  LogicalResult
+  matchAndRewrite(LocalTeeOp localTeeOp, LocalTeeOp::Adaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const override {
+    rewriter.create<memref::StoreOp>(localTeeOp->getLoc(), adaptor.getValue(),
+                                     adaptor.getLocalVar());
+    rewriter.replaceOp(localTeeOp, adaptor.getValue());
     return success();
   }
 };
@@ -112,13 +352,13 @@ struct WasmReturnOpConversion : OpConversionPattern<ReturnOp> {
   LogicalResult
   matchAndRewrite(ReturnOp returnOp, ReturnOp::Adaptor adaptor,
                   ConversionPatternRewriter &rewriter) const override {
-    rewriter.replaceOpWithNewOp<func::ReturnOp>(returnOp, adaptor.getOperands());
+    rewriter.replaceOpWithNewOp<func::ReturnOp>(returnOp,
+                                                adaptor.getOperands());
     return success();
   }
 };
 
-struct RaiseWasmMLIRPass
-    : public impl::RaiseWasmMLIRBase<RaiseWasmMLIRPass> {
+struct RaiseWasmMLIRPass : public impl::RaiseWasmMLIRBase<RaiseWasmMLIRPass> {
   void runOnOperation() override {
     ConversionTarget target{getContext()};
     target.addIllegalDialect<WasmSSADialect>();
@@ -128,14 +368,17 @@ struct RaiseWasmMLIRPass
     RewritePatternSet patterns(&getContext());
     TypeConverter tc{};
     tc.addConversion([](Type type) -> std::optional<Type> { return type; });
-    tc.addConversion([](LocalRefType type)->std::optional<Type> {
+    tc.addConversion([](LocalRefType type) -> std::optional<Type> {
       return MemRefType::get({}, type.getElementType());
     });
-    tc.addTargetMaterialization([](OpBuilder& builder, MemRefType destType, ValueRange values, Location loc)->Value{
-      if (values.size() != 1 || values.front().getType() != destType.getElementType())
+    tc.addTargetMaterialization([](OpBuilder &builder, MemRefType destType,
+                                   ValueRange values, Location loc) -> Value {
+      if (values.size() != 1 ||
+          values.front().getType() != destType.getElementType())
         return {};
       auto localVar = builder.create<memref::AllocaOp>(loc, destType);
-      builder.create<memref::StoreOp>(loc, values.front(), localVar.getResult());
+      builder.create<memref::StoreOp>(loc, values.front(),
+                                      localVar.getResult());
       return localVar.getResult();
     });
     populateRaiseWasmMLIRConversionPatterns(tc, patterns);
@@ -168,11 +411,52 @@ void mlir::populateRaiseWasmMLIRConversionPatterns(
   // clang-format off
   patternSet
       .add<
+           WasmAbsOpConversion,
+           WasmAddOpConversion,
+           WasmAndOpConversion,
            WasmCallOpConversion,
+           WasmCeilOpConversion,
+           WasmClzOpConversion,
+           WasmConstOpConversion,
+           WasmConvertSOpConversion,
+           WasmConvertUOpConversion,
+           WasmCopySignOpConversion,
+           WasmCtzOpConversion,
+           WasmDemoteOpConversion,
+           WasmDivFPOpConversion,
+           WasmDivSIOpConversion,
+           WasmDivUIOpConversion,
+           WasmExtendSOpConversion,
+           WasmExtendUOpConversion,
+           WasmFloorOpConversion,
            WasmFuncImportOpConversion,
            WasmFuncOpConversion,
+           WasmGlobalImportOpConverter,
+           WasmGlobalWithConstInitConversion,
+           WasmGlobalWithGetGlobalInitConversion,
+           WasmLocalConversion,
            WasmLocalGetConversion,
-           WasmReturnOpConversion
+           WasmLocalSetConversion,
+           WasmLocalTeeConversion,
+           WasmMaxOpConversion,
+           WasmMinOpConversion,
+           WasmMulOpConversion,
+           WasmNegOpConversion,
+           WasmOrOpConversion,
+           WasmPopCntOpConversion,
+           WasmPromoteOpConversion,
+           WasmReinterpretOpConversion,
+           WasmRemSIOpConversion,
+           WasmRemUIOpConversion,
+           WasmReturnOpConversion,
+           WasmShLOpConversion,
+           WasmShRSOpConversion,
+           WasmShRUOpConversion,
+           WasmSqrtOpConversion,
+           WasmSubOpConversion,
+           WasmTruncOpConversion,
+           WasmWrapOpConversion,
+           WasmXOrOpConversion
            >(tc, ctx);
   // clang-format on
 }
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-abs-to-math-abs.mlir b/mlir/test/Conversion/RaiseWasm/wasm-abs-to-math-abs.mlir
new file mode 100644
index 0000000000000..eee03772589b9
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-abs-to-math-abs.mlir
@@ -0,0 +1,27 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+// CHECK-LABEL:   func.func @abs_f32(
+// CHECK-SAME:      %[[ARG0:.*]]: f32) -> f32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_1:.*]] = memref.load %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_2:.*]] = math.absf %[[VAL_1]] : f32
+// CHECK:           return %[[VAL_2]] : f32
+wasmssa.func @abs_f32(%arg0: !wasmssa<local ref to f32>) -> f32 {
+    %val = wasmssa.local_get %arg0 : ref to f32
+    %op = wasmssa.abs %val : f32
+    wasmssa.return %op : f32
+}
+
+// CHECK-LABEL:   func.func @abs_f64(
+// CHECK-SAME:      %[[ARG0:.*]]: f64) -> f64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_1:.*]] = memref.load %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_2:.*]] = math.absf %[[VAL_1]] : f64
+// CHECK:           return %[[VAL_2]] : f64
+wasmssa.func @abs_f64(%arg0: !wasmssa<local ref to f64>) -> f64 {
+    %val = wasmssa.local_get %arg0 : ref to f64
+    %op = wasmssa.abs %val : f64
+    wasmssa.return %op : f64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-add-to-arith-add.mlir b/mlir/test/Conversion/RaiseWasm/wasm-add-to-arith-add.mlir
new file mode 100644
index 0000000000000..377be5d1a2f1e
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-add-to-arith-add.mlir
@@ -0,0 +1,79 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir | FileCheck %s
+
+// CHECK-LABEL:   func.func @func_1(
+// CHECK-SAME:                      %[[ARG0:.*]]: i32,
+// CHECK-SAME:                      %[[ARG1:.*]]: i32) -> i32 {
+wasmssa.func @func_1(%arg0: !wasmssa<local ref to i32>, %arg1: !wasmssa<local ref to i32>) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+%v0 = wasmssa.local_get %arg0 : ref to i32
+%v1 = wasmssa.local_get %arg1 : ref to i32
+// CHECK:           %[[VAL_4:.*]] = arith.addi %[[VAL_2]], %[[VAL_3]] : i32
+%0 = wasmssa.add %v0 %v1 : i32
+// CHECK:           return %[[VAL_4]] : i32
+wasmssa.return %0 : i32
+}
+
+// -----
+
+// CHECK-LABEL:   func.func @func_2(
+// CHECK-SAME:                      %[[ARG0:.*]]: i64,
+// CHECK-SAME:                      %[[ARG1:.*]]: i64) -> i64 {
+wasmssa.func @func_2(%arg0: !wasmssa<local ref to i64>, %arg1: !wasmssa<local ref to i64>) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+%v0 = wasmssa.local_get %arg0 : ref to i64
+%v1 = wasmssa.local_get %arg1 : ref to i64
+// CHECK:           %[[VAL_4:.*]] = arith.addi %[[VAL_2]], %[[VAL_3]] : i64
+%0 = wasmssa.add %v0 %v1 : i64
+// CHECK:           return %[[VAL_4]] : i64
+wasmssa.return %0 : i64
+}
+
+// -----
+
+// CHECK-LABEL:   func.func @func_3(
+// CHECK-SAME:                      %[[ARG0:.*]]: f32,
+// CHECK-SAME:                      %[[ARG1:.*]]: f32) -> f32 {
+wasmssa.func @func_3(%arg0: !wasmssa<local ref to f32>, %arg1: !wasmssa<local ref to f32>) -> f32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<f32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<f32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<f32>
+%v0 = wasmssa.local_get %arg0 : ref to f32
+%v1 = wasmssa.local_get %arg1 : ref to f32
+// CHECK:           %[[VAL_4:.*]] = arith.addf %[[VAL_2]], %[[VAL_3]] : f32
+%0 = wasmssa.add %v0 %v1 : f32
+// CHECK:           return %[[VAL_4]] : f32
+wasmssa.return %0 : f32
+}
+
+// -----
+
+// CHECK-LABEL:   func.func @func_4(
+// CHECK-SAME:                      %[[ARG0:.*]]: f64,
+// CHECK-SAME:                      %[[ARG1:.*]]: f64) -> f64 {
+wasmssa.func @func_4(%arg0: !wasmssa<local ref to f64>, %arg1: !wasmssa<local ref to f64>) -> f64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<f64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<f64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<f64>
+%v0 = wasmssa.local_get %arg0 : ref to f64
+%v1 = wasmssa.local_get %arg1 : ref to f64
+// CHECK:           %[[VAL_4:.*]] = arith.addf %[[VAL_2]], %[[VAL_3]] : f64
+%0 = wasmssa.add %v0 %v1 : f64
+// CHECK:           return %[[VAL_4]] : f64
+wasmssa.return %0 : f64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-and-to-arith-and.mlir b/mlir/test/Conversion/RaiseWasm/wasm-and-to-arith-and.mlir
new file mode 100644
index 0000000000000..eebc76e7322ae
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-and-to-arith-and.mlir
@@ -0,0 +1,38 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+
+// CHECK-LABEL:   func.func @and_i32(
+// CHECK-SAME:                      %[[ARG0:.*]]: i32,
+// CHECK-SAME:                      %[[ARG1:.*]]: i32) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_4:.*]] = arith.andi %[[VAL_2]], %[[VAL_3]] : i32
+// CHECK:           return %[[VAL_4]] : i32
+wasmssa.func exported @and_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
+    %and = wasmssa.and %v0 %v1 : i32
+    wasmssa.return %and : i32
+}
+
+// CHECK-LABEL:   func.func @and_i64(
+// CHECK-SAME:                      %[[ARG0:.*]]: i64,
+// CHECK-SAME:                      %[[ARG1:.*]]: i64) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_4:.*]] = arith.andi %[[VAL_2]], %[[VAL_3]] : i64
+// CHECK:           return %[[VAL_4]] : i64
+wasmssa.func exported @and_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
+    %and = wasmssa.and %v0 %v1 : i64
+    wasmssa.return %and : i64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-ceil-to-math-ceil.mlir b/mlir/test/Conversion/RaiseWasm/wasm-ceil-to-math-ceil.mlir
new file mode 100644
index 0000000000000..15875f60c1c43
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-ceil-to-math-ceil.mlir
@@ -0,0 +1,24 @@
+// RUN: mlir-opt %s --raise-wasm-mlir | FileCheck %s
+
+module {
+  wasmssa.func exported @func_0() -> f64 {
+    %0 = wasmssa.const -1.210000e+01 : f64
+    %1 = wasmssa.ceil %0 : f64
+    wasmssa.return %1 : f64
+  }
+  wasmssa.func exported @func_1() -> f32 {
+    %0 = wasmssa.const 1.618000e+00 : f32
+    %1 = wasmssa.ceil %0 : f32
+    wasmssa.return %1 : f32
+  }
+}
+
+// CHECK-LABEL:   func.func @func_0() -> f64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant -1.210000e+01 : f64
+// CHECK:           %[[VAL_1:.*]] = math.ceil %[[VAL_0]] : f64
+// CHECK:           return %[[VAL_1]] : f64
+
+// CHECK-LABEL:   func.func @func_1() -> f32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 1.618000e+00 : f32
+// CHECK:           %[[VAL_1:.*]] = math.ceil %[[VAL_0]] : f32
+// CHECK:           return %[[VAL_1]] : f32
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-clz-to-math-clz.mlir b/mlir/test/Conversion/RaiseWasm/wasm-clz-to-math-clz.mlir
new file mode 100644
index 0000000000000..944cf24ff40c2
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-clz-to-math-clz.mlir
@@ -0,0 +1,27 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+// CHECK-LABEL:   func.func @clz_i32(
+// 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.ctlz %[[VAL_1]] : i32
+// CHECK:           return %[[VAL_2]] : i32
+wasmssa.func exported @clz_i32(%arg0: !wasmssa<local ref to i32>) -> i32 {
+    %v0 = wasmssa.local_get %arg0 : ref to i32
+    %op = wasmssa.clz %v0 : i32
+    wasmssa.return %op : i32
+}
+
+// CHECK-LABEL:   func.func @clz_i64(
+// CHECK-SAME:      %[[ARG0:.*]]: i64) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = math.ctlz %[[VAL_1]] : i64
+// CHECK:           return %[[VAL_2]] : i64
+wasmssa.func exported @clz_i64(%arg0: !wasmssa<local ref to i64>) -> i64 {
+    %v0 = wasmssa.local_get %arg0 : ref to i64
+    %op = wasmssa.clz %v0 : i64
+    wasmssa.return %op : i64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-const-to-arith-const.mlir b/mlir/test/Conversion/RaiseWasm/wasm-const-to-arith-const.mlir
new file mode 100644
index 0000000000000..06bd0acab4f96
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-const-to-arith-const.mlir
@@ -0,0 +1,15 @@
+// RUN: mlir-opt %s --raise-wasm-mlir | FileCheck %s
+
+// CHECK-LABEL:   func.func @get_some_const() -> (i32, i64, f32, f64) {
+wasmssa.func exported @get_some_const() -> (i32, i64, f32, f64) {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 17 : i32
+%0 = wasmssa.const 17: i32
+// CHECK:           %[[VAL_1:.*]] = arith.constant -163 : i64
+%1 = wasmssa.const -163 : i64
+// CHECK:           %[[VAL_2:.*]] = arith.constant 3.140000e+00 : f32
+%2 = wasmssa.const 3.14 : f32
+// CHECK:           %[[VAL_3:.*]] = arith.constant -1.575000e+02 : f64
+%3 = wasmssa.const -157.5 : f64
+// CHECK:           return %[[VAL_0]], %[[VAL_1]], %[[VAL_2]], %[[VAL_3]] : i32, i64, f32, f64
+wasmssa.return %0, %1, %2, %3 : i32, i64, f32, f64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-convert-to-arith-tofp.mlir b/mlir/test/Conversion/RaiseWasm/wasm-convert-to-arith-tofp.mlir
new file mode 100644
index 0000000000000..4eeea757d48d0
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-convert-to-arith-tofp.mlir
@@ -0,0 +1,81 @@
+// RUN: mlir-opt %s --raise-wasm-mlir | FileCheck %s
+
+// CHECK-LABEL:   func.func @convert_i32_u_to_f32() -> f32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 10 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.uitofp %[[VAL_0]] : i32 to f32
+// CHECK:           return %[[VAL_1]] : f32
+wasmssa.func @convert_i32_u_to_f32() -> f32 {
+  %0 = wasmssa.const 10 : i32
+  %1 = wasmssa.convert_u %0 : i32 to f32
+  wasmssa.return %1 : f32
+}
+
+// CHECK-LABEL:   func.func @convert_i32_s_to_f32() -> f32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 42 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.sitofp %[[VAL_0]] : i32 to f32
+// CHECK:           return %[[VAL_1]] : f32
+wasmssa.func @convert_i32_s_to_f32() -> f32 {
+  %0 = wasmssa.const 42 : i32
+  %1 = wasmssa.convert_s %0 : i32 to f32
+  wasmssa.return %1 : f32
+}
+
+// CHECK-LABEL:   func.func @convert_i64_u_to_f32() -> f32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 17 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.uitofp %[[VAL_0]] : i64 to f32
+// CHECK:           return %[[VAL_1]] : f32
+wasmssa.func @convert_i64_u_to_f32() -> f32 {
+  %0 = wasmssa.const 17 : i64
+  %1 = wasmssa.convert_u %0 : i64 to f32
+  wasmssa.return %1 : f32
+}
+
+// CHECK-LABEL:   func.func @convert_i64s_to_f32() -> f32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 10 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.sitofp %[[VAL_0]] : i64 to f32
+// CHECK:           return %[[VAL_1]] : f32
+wasmssa.func @convert_i64s_to_f32() -> f32 {
+  %0 = wasmssa.const 10 : i64
+  %1 = wasmssa.convert_s %0 : i64 to f32
+  wasmssa.return %1 : f32
+}
+
+// CHECK-LABEL:   func.func @convert_i32_u_to_f64() -> f64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 10 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.uitofp %[[VAL_0]] : i32 to f64
+// CHECK:           return %[[VAL_1]] : f64
+wasmssa.func @convert_i32_u_to_f64() -> f64 {
+  %0 = wasmssa.const 10 : i32
+  %1 = wasmssa.convert_u %0 : i32 to f64
+  wasmssa.return %1 : f64
+}
+
+// CHECK-LABEL:   func.func @convert_i32_s_to_f64() -> f64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 42 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.sitofp %[[VAL_0]] : i32 to f64
+// CHECK:           return %[[VAL_1]] : f64
+wasmssa.func @convert_i32_s_to_f64() -> f64 {
+  %0 = wasmssa.const 42 : i32
+  %1 = wasmssa.convert_s %0 : i32 to f64
+  wasmssa.return %1 : f64
+}
+
+// CHECK-LABEL:   func.func @convert_i64_u_to_f64() -> f64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 17 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.uitofp %[[VAL_0]] : i64 to f64
+// CHECK:           return %[[VAL_1]] : f64
+wasmssa.func @convert_i64_u_to_f64() -> f64 {
+  %0 = wasmssa.const 17 : i64
+  %1 = wasmssa.convert_u %0 : i64 to f64
+  wasmssa.return %1 : f64
+}
+
+// CHECK-LABEL:   func.func @convert_i64s_to_f64() -> f64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 10 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.sitofp %[[VAL_0]] : i64 to f64
+// CHECK:           return %[[VAL_1]] : f64
+wasmssa.func @convert_i64s_to_f64() -> f64 {
+  %0 = wasmssa.const 10 : i64
+  %1 = wasmssa.convert_s %0 : i64 to f64
+  wasmssa.return %1 : f64
+}
\ No newline at end of file
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-copysign-to-math-copysign.mlir b/mlir/test/Conversion/RaiseWasm/wasm-copysign-to-math-copysign.mlir
new file mode 100644
index 0000000000000..9ab2b7990e7c0
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-copysign-to-math-copysign.mlir
@@ -0,0 +1,38 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+
+// CHECK-LABEL:   func.func @copysign_f32(
+// CHECK-SAME:      %[[ARG0:.*]]: f32,
+// CHECK-SAME:      %[[ARG1:.*]]: f32) -> f32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<f32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<f32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_4:.*]] = math.copysign %[[VAL_2]], %[[VAL_3]] : f32
+// CHECK:           return %[[VAL_4]] : f32
+wasmssa.func exported @copysign_f32(%arg0: !wasmssa<local ref to f32>, %arg1: !wasmssa<local ref to f32>) -> f32 {
+    %v0 = wasmssa.local_get %arg0 : ref to f32
+    %v1 = wasmssa.local_get %arg1 : ref to f32
+    %op = wasmssa.copysign %v0 %v1: f32
+    wasmssa.return %op : f32
+}
+
+// CHECK-LABEL:   func.func @copysign_f64(
+// CHECK-SAME:      %[[ARG0:.*]]: f64,
+// CHECK-SAME:      %[[ARG1:.*]]: f64) -> f64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<f64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<f64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_4:.*]] = math.copysign %[[VAL_2]], %[[VAL_3]] : f64
+// CHECK:           return %[[VAL_4]] : f64
+wasmssa.func exported @copysign_f64(%arg0: !wasmssa<local ref to f64>, %arg1: !wasmssa<local ref to f64>) -> f64 {
+    %v0 = wasmssa.local_get %arg0 : ref to f64
+    %v1 = wasmssa.local_get %arg1 : ref to f64
+    %op = wasmssa.copysign %v0 %v1: f64
+    wasmssa.return %op : f64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-ctz-to-math-ctz.mlir b/mlir/test/Conversion/RaiseWasm/wasm-ctz-to-math-ctz.mlir
new file mode 100644
index 0000000000000..6cc9394eea99c
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-ctz-to-math-ctz.mlir
@@ -0,0 +1,27 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+// CHECK-LABEL:   func.func @ctz_i32(
+// 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:           return %[[VAL_2]] : i32
+wasmssa.func exported @ctz_i32(%arg0: !wasmssa<local ref to i32>) -> i32 {
+    %v0 = wasmssa.local_get %arg0 : ref to i32
+    %op = wasmssa.ctz %v0 : i32
+    wasmssa.return %op : i32
+}
+
+// CHECK-LABEL:   func.func @ctz_i64(
+// CHECK-SAME:      %[[ARG0:.*]]: i64) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = math.cttz %[[VAL_1]] : i64
+// CHECK:           return %[[VAL_2]] : i64
+wasmssa.func exported @ctz_i64(%arg0: !wasmssa<local ref to i64>) -> i64 {
+    %v0 = wasmssa.local_get %arg0 : ref to i64
+    %op = wasmssa.ctz %v0 : i64
+    wasmssa.return %op : i64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-demote-to-arith-trunc.mlir b/mlir/test/Conversion/RaiseWasm/wasm-demote-to-arith-trunc.mlir
new file mode 100644
index 0000000000000..342886e3bda00
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-demote-to-arith-trunc.mlir
@@ -0,0 +1,14 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+module {
+  wasmssa.func @func_0() -> f32 {
+    %0 = wasmssa.const 2.240000e+00 : f64
+    %1 = wasmssa.demote %0 : f64 to f32
+    wasmssa.return %1 : f32
+  }
+}
+
+// CHECK-LABEL:   func.func @func_0() -> f32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 2.240000e+00 : f64
+// CHECK:           %[[VAL_1:.*]] = arith.truncf %[[VAL_0]] : f64 to f32
+// CHECK:           return %[[VAL_1]] : f32
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-div-to-arith-div.mlir b/mlir/test/Conversion/RaiseWasm/wasm-div-to-arith-div.mlir
new file mode 100644
index 0000000000000..3d6fa9af95442
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-div-to-arith-div.mlir
@@ -0,0 +1,109 @@
+// RUN: mlir-opt %s --raise-wasm-mlir | FileCheck %s
+
+// CHECK-LABEL:   func.func @div_i32_si(
+// CHECK-SAME:      %[[ARG0:.*]]: i32,
+// CHECK-SAME:      %[[ARG1:.*]]: i32) -> i32 {
+wasmssa.func @div_i32_si(%arg0: !wasmssa<local ref to i32>, %arg1: !wasmssa<local ref to i32>) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+%v0 = wasmssa.local_get %arg0 : ref to i32
+%v1 = wasmssa.local_get %arg1 : ref to i32
+// CHECK:           %[[VAL_4:.*]] = arith.divsi %[[VAL_2]], %[[VAL_3]] : i32
+%0 = wasmssa.div_si %v0 %v1 : i32
+// CHECK:           return %[[VAL_4]] : i32
+wasmssa.return %0 : i32
+}
+
+// CHECK-LABEL:   func.func @div_i64_si(
+// CHECK-SAME:      %[[ARG0:.*]]: i64,
+// CHECK-SAME:      %[[ARG1:.*]]: i64) -> i64 {
+wasmssa.func @div_i64_si(%arg0: !wasmssa<local ref to i64>, %arg1: !wasmssa<local ref to i64>) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+%v0 = wasmssa.local_get %arg0 : ref to i64
+%v1 = wasmssa.local_get %arg1 : ref to i64
+// CHECK:           %[[VAL_4:.*]] = arith.divsi %[[VAL_2]], %[[VAL_3]] : i64
+%0 = wasmssa.div_si %v0 %v1 : i64
+// CHECK:           return %[[VAL_4]] : i64
+wasmssa.return %0 : i64
+}
+
+// CHECK-LABEL:   func.func @div_i32_ui(
+// CHECK-SAME:      %[[ARG0:.*]]: i32,
+// CHECK-SAME:      %[[ARG1:.*]]: i32) -> i32 {
+wasmssa.func @div_i32_ui(%arg0: !wasmssa<local ref to i32>, %arg1: !wasmssa<local ref to i32>) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+%v0 = wasmssa.local_get %arg0 : ref to i32
+%v1 = wasmssa.local_get %arg1 : ref to i32
+// CHECK:           %[[VAL_4:.*]] = arith.divui %[[VAL_2]], %[[VAL_3]] : i32
+%0 = wasmssa.div_ui %v0 %v1 : i32
+// CHECK:           return %[[VAL_4]] : i32
+wasmssa.return %0 : i32
+}
+
+// CHECK-LABEL:   func.func @div_i64_ui(
+// CHECK-SAME:      %[[ARG0:.*]]: i64,
+// CHECK-SAME:      %[[ARG1:.*]]: i64) -> i64 {
+wasmssa.func @div_i64_ui(%arg0: !wasmssa<local ref to i64>, %arg1: !wasmssa<local ref to i64>) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+%v0 = wasmssa.local_get %arg0 : ref to i64
+%v1 = wasmssa.local_get %arg1 : ref to i64
+// CHECK:           %[[VAL_4:.*]] = arith.divui %[[VAL_2]], %[[VAL_3]] : i64
+%0 = wasmssa.div_ui %v0 %v1 : i64
+// CHECK:           return %[[VAL_4]] : i64
+wasmssa.return %0 : i64
+}
+
+// CHECK-LABEL:   func.func @div_f32(
+// CHECK-SAME:      %[[ARG0:.*]]: f32,
+// CHECK-SAME:      %[[ARG1:.*]]: f32) -> f32 {
+wasmssa.func @div_f32(%arg0: !wasmssa<local ref to f32>, %arg1: !wasmssa<local ref to f32>) -> f32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<f32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<f32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<f32>
+%v0 = wasmssa.local_get %arg0 : ref to f32
+%v1 = wasmssa.local_get %arg1 : ref to f32
+// CHECK:           %[[VAL_4:.*]] = arith.divf %[[VAL_2]], %[[VAL_3]] : f32
+%0 = wasmssa.div %v0 %v1 : f32
+// CHECK:           return %[[VAL_4]] : f32
+wasmssa.return %0 : f32
+}
+
+// CHECK-LABEL:   func.func @div_f64(
+// CHECK-SAME:      %[[ARG0:.*]]: f64,
+// CHECK-SAME:      %[[ARG1:.*]]: f64) -> f64 {
+wasmssa.func @div_f64(%arg0: !wasmssa<local ref to f64>, %arg1: !wasmssa<local ref to f64>) -> f64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<f64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<f64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<f64>
+%v0 = wasmssa.local_get %arg0 : ref to f64
+%v1 = wasmssa.local_get %arg1 : ref to f64
+// CHECK:           %[[VAL_4:.*]] = arith.divf %[[VAL_2]], %[[VAL_3]] : f64
+%0 = wasmssa.div %v0 %v1 : f64
+// CHECK:           return %[[VAL_4]] : f64
+wasmssa.return %0 : f64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-floor-to-math-floor.mlir b/mlir/test/Conversion/RaiseWasm/wasm-floor-to-math-floor.mlir
new file mode 100644
index 0000000000000..5ca4694bdb824
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-floor-to-math-floor.mlir
@@ -0,0 +1,24 @@
+// RUN: mlir-opt %s --raise-wasm-mlir | FileCheck %s
+
+module {
+  wasmssa.func @func_0() -> f64 {
+    %0 = wasmssa.const -1.210000e+01 : f64
+    %1 = wasmssa.floor %0 : f64
+    wasmssa.return %1 : f64
+  }
+  wasmssa.func @func_1() -> f32 {
+    %0 = wasmssa.const 1.618000e+00 : f32
+    %1 = wasmssa.floor %0 : f32
+    wasmssa.return %1 : f32
+  }
+}
+
+// CHECK-LABEL:   func.func @func_0() -> f64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant -1.210000e+01 : f64
+// CHECK:           %[[VAL_1:.*]] = math.floor %[[VAL_0]] : f64
+// CHECK:           return %[[VAL_1]] : f64
+
+// CHECK-LABEL:   func.func @func_1() -> f32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 1.618000e+00 : f32
+// CHECK:           %[[VAL_1:.*]] = math.floor %[[VAL_0]] : f32
+// CHECK:           return %[[VAL_1]] : f32
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-global-to-memref-global.mlir b/mlir/test/Conversion/RaiseWasm/wasm-global-to-memref-global.mlir
new file mode 100644
index 0000000000000..45a6636d89c22
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-global-to-memref-global.mlir
@@ -0,0 +1,43 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir | FileCheck %s
+
+wasmssa.global @global_i32 i32 mutable : {
+  %0 = wasmssa.const 66560 : i32
+  wasmssa.return %0 : i32
+}
+
+wasmssa.global @global_i64 i64 mutable : {
+  %0 = wasmssa.const 37017 : i64
+  wasmssa.return %0 : i64
+}
+
+wasmssa.global @global_f32 f32 mutable : {
+  %0 = wasmssa.const 0.125 : f32
+  wasmssa.return %0 : f32
+}
+
+wasmssa.global @global_f64 f64 mutable : {
+  %0 = wasmssa.const 3.14 : f64
+  wasmssa.return %0 : f64
+}
+
+wasmssa.global @global_user0 i32 mutable : {
+  %0 = wasmssa.global_get @global_top_define : i32
+  wasmssa.return %0 : i32
+}
+
+wasmssa.import_global "extern_global_var" from "module" as @global_top_define nested : i32
+
+// CHECK-LABEL:   memref.global "private" @global_i32 : memref<1xi32> = dense<66560>
+// CHECK:         memref.global "private" @global_i64 : memref<1xi64> = dense<37017>
+// CHECK:         memref.global "private" @global_f32 : memref<1xf32> = dense<1.250000e-01>
+// CHECK:         memref.global "private" @global_f64 : memref<1xf64> = dense<3.140000e+00>
+// CHECK:         memref.global "private" @global_user0 : memref<1xi32> = uninitialized
+
+// CHECK-LABEL:   func.func @"global_user0::initializer"() attributes {initializer} {
+// CHECK:           %[[VAL_0:.*]] = memref.get_global @"module::extern_global_var" : memref<1xi32>
+// CHECK:           %[[VAL_1:.*]] = memref.get_global @global_user0 : memref<1xi32>
+// CHECK:           %[[VAL_2:.*]] = arith.constant 0 : index
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]]{{\[}}%[[VAL_2]]] : memref<1xi32>
+// CHECK:           memref.store %[[VAL_3]], %[[VAL_1]]{{\[}}%[[VAL_2]]] : memref<1xi32>
+// CHECK:           return
+// CHECK:         memref.global "nested" constant @"module::extern_global_var" : memref<1xi32>
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-local-to-memref.mlir b/mlir/test/Conversion/RaiseWasm/wasm-local-to-memref.mlir
new file mode 100644
index 0000000000000..839975ab87daa
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-local-to-memref.mlir
@@ -0,0 +1,68 @@
+// RUN: mlir-opt %s --raise-wasm-mlir | FileCheck %s
+
+// CHECK-LABEL:   func.func @func_0() -> f32 {
+wasmssa.func exported @func_0() -> f32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f32>
+// CHECK:           %[[VAL_1:.*]] = arith.constant 0.000000e+00 : f32
+// CHECK:           memref.store %[[VAL_1]], %[[VAL_0]][] : memref<f32>
+  %0 = wasmssa.local of type f32
+// CHECK:           %[[VAL_2:.*]] = memref.alloca() : memref<f32>
+// CHECK:           %[[VAL_3:.*]] = arith.constant 0.000000e+00 : f32
+// CHECK:           memref.store %[[VAL_3]], %[[VAL_2]][] : memref<f32>
+  %1 = wasmssa.local of type f32
+// CHECK:           %[[VAL_4:.*]] = arith.constant 8.000000e+00 : f32
+  %2 = wasmssa.const 8.000000e+00 : f32
+// CHECK:           memref.store %[[VAL_4]], %[[VAL_0]][] : memref<f32>
+  wasmssa.local_set %0 : ref to f32 to %2 : f32
+// CHECK:           %[[VAL_5:.*]] = memref.load %[[VAL_0]][] : memref<f32>
+  %3 = wasmssa.local_get %0 : ref to f32
+// CHECK:           %[[VAL_6:.*]] = arith.constant 1.200000e+01 : f32
+  %4 = wasmssa.const 1.200000e+01 : f32
+// CHECK:           memref.store %[[VAL_6]], %[[VAL_2]][] : memref<f32>
+  %5 = wasmssa.local_tee %1 : ref to f32 to %4 : f32
+// CHECK:           %[[VAL_7:.*]] = arith.addf %[[VAL_5]], %[[VAL_6]] : f32
+  %6 = wasmssa.add %3 %5 : f32
+// CHECK:           return %[[VAL_7]] : f32
+  wasmssa.return %6 : f32
+}
+
+// CHECK-LABEL:   func.func @func_1() -> i32 {
+wasmssa.func exported @func_1() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = arith.constant 0 : i32
+// CHECK:           memref.store %[[VAL_1]], %[[VAL_0]][] : memref<i32>
+  %0 = wasmssa.local of type i32
+// CHECK:           %[[VAL_2:.*]] = memref.alloca() : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = arith.constant 0 : i32
+// CHECK:           memref.store %[[VAL_3]], %[[VAL_2]][] : memref<i32>
+  %1 = wasmssa.local of type i32
+// CHECK:           %[[VAL_4:.*]] = arith.constant 8 : i32
+  %2 = wasmssa.const 8 : i32
+// CHECK:           memref.store %[[VAL_4]], %[[VAL_0]][] : memref<i32>
+  wasmssa.local_set %0 : ref to i32 to %2 : i32
+// CHECK:           %[[VAL_5:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+  %3 = wasmssa.local_get %0 : ref to i32
+// CHECK:           %[[VAL_6:.*]] = arith.constant 12 : i32
+  %4 = wasmssa.const 12 : i32
+// CHECK:           memref.store %[[VAL_6]], %[[VAL_2]][] : memref<i32>
+  %5 = wasmssa.local_tee %1 : ref to i32 to %4 : i32
+// CHECK:           %[[VAL_7:.*]] = arith.addi %[[VAL_5]], %[[VAL_6]] : i32
+  %6 = wasmssa.add %3 %5 : i32
+// CHECK:           return %[[VAL_7]] : i32
+  wasmssa.return %6 : i32
+}
+
+// CHECK-LABEL:   func.func @func_2(
+// CHECK-SAME:                      %[[VAL_0:.*]]: i32) -> i32 {
+wasmssa.func exported @func_2(%arg0: !wasmssa<local ref to i32>) -> i32 {
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[VAL_0]], %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = arith.constant 3 : i32
+  %1 = wasmssa.const 3 : i32
+// CHECK:           memref.store %[[VAL_2]], %[[VAL_1]][] : memref<i32>
+  wasmssa.local_set %arg0 : ref to i32 to %1 : i32
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+  %2 = wasmssa.local_get %arg0 : ref to i32
+// CHECK:           return %[[VAL_3]] : i32
+  wasmssa.return %2 : i32
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-max-to-arith-maximumf.mlir b/mlir/test/Conversion/RaiseWasm/wasm-max-to-arith-maximumf.mlir
new file mode 100644
index 0000000000000..2f0d10788f03c
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-max-to-arith-maximumf.mlir
@@ -0,0 +1,37 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+// CHECK-LABEL:   func.func @max_f32(
+// CHECK-SAME:      %[[ARG0:.*]]: f32,
+// CHECK-SAME:      %[[ARG1:.*]]: f32) -> f32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<f32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<f32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_4:.*]] = arith.maximumf %[[VAL_2]], %[[VAL_3]] : f32
+// CHECK:           return %[[VAL_4]] : f32
+wasmssa.func exported @max_f32(%arg0: !wasmssa<local ref to f32>, %arg1: !wasmssa<local ref to f32>) -> f32 {
+    %v0 = wasmssa.local_get %arg0 : ref to f32
+    %v1 = wasmssa.local_get %arg1 : ref to f32
+    %op = wasmssa.max %v0 %v1 : f32
+    wasmssa.return %op : f32
+}
+
+// CHECK-LABEL:   func.func @max_f64(
+// CHECK-SAME:      %[[ARG0:.*]]: f64,
+// CHECK-SAME:      %[[ARG1:.*]]: f64) -> f64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<f64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<f64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_4:.*]] = arith.maximumf %[[VAL_2]], %[[VAL_3]] : f64
+// CHECK:           return %[[VAL_4]] : f64
+wasmssa.func exported @max_f64(%arg0: !wasmssa<local ref to f64>, %arg1: !wasmssa<local ref to f64>) -> f64 {
+    %v0 = wasmssa.local_get %arg0 : ref to f64
+    %v1 = wasmssa.local_get %arg1 : ref to f64
+    %op = wasmssa.max %v0 %v1 : f64
+    wasmssa.return %op : f64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-min-to-arith-minimumf.mlir b/mlir/test/Conversion/RaiseWasm/wasm-min-to-arith-minimumf.mlir
new file mode 100644
index 0000000000000..d6a0141a5199f
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-min-to-arith-minimumf.mlir
@@ -0,0 +1,37 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+// CHECK-LABEL:   func.func @min_f32(
+// CHECK-SAME:      %[[ARG0:.*]]: f32,
+// CHECK-SAME:      %[[ARG1:.*]]: f32) -> f32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<f32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<f32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_4:.*]] = arith.minimumf %[[VAL_2]], %[[VAL_3]] : f32
+// CHECK:           return %[[VAL_4]] : f32
+wasmssa.func exported @min_f32(%arg0: !wasmssa<local ref to f32>, %arg1: !wasmssa<local ref to f32>) -> f32 {
+    %v0 = wasmssa.local_get %arg0 : ref to f32
+    %v1 = wasmssa.local_get %arg1 : ref to f32
+    %op = wasmssa.min %v0 %v1 : f32
+    wasmssa.return %op : f32
+}
+
+// CHECK-LABEL:   func.func @min_f64(
+// CHECK-SAME:      %[[ARG0:.*]]: f64,
+// CHECK-SAME:      %[[ARG1:.*]]: f64) -> f64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<f64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<f64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_4:.*]] = arith.minimumf %[[VAL_2]], %[[VAL_3]] : f64
+// CHECK:           return %[[VAL_4]] : f64
+wasmssa.func exported @min_f64(%arg0: !wasmssa<local ref to f64>, %arg1: !wasmssa<local ref to f64>) -> f64 {
+    %v0 = wasmssa.local_get %arg0 : ref to f64
+    %v1 = wasmssa.local_get %arg1 : ref to f64
+    %op = wasmssa.min %v0 %v1 : f64
+    wasmssa.return %op : f64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-mul-to-arith-mul.mlir b/mlir/test/Conversion/RaiseWasm/wasm-mul-to-arith-mul.mlir
new file mode 100644
index 0000000000000..51c8b43d980b5
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-mul-to-arith-mul.mlir
@@ -0,0 +1,78 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir | FileCheck %s
+
+// CHECK-LABEL:   func.func @mul_i32(
+// CHECK-SAME:                      %[[ARG0:.*]]: i32,
+// CHECK-SAME:                      %[[ARG1:.*]]: i32) -> i32 {
+wasmssa.func @mul_i32(%arg0: !wasmssa<local ref to i32>, %arg1: !wasmssa<local ref to i32>) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+%v0 = wasmssa.local_get %arg0 : ref to i32
+%v1 = wasmssa.local_get %arg1 : ref to i32
+// CHECK:           %[[VAL_4:.*]] = arith.muli %[[VAL_2]], %[[VAL_3]] : i32
+%0 = wasmssa.mul %v0 %v1 : i32
+// CHECK:           return %[[VAL_4]] : i32
+wasmssa.return %0 : i32
+}
+
+// -----
+
+// CHECK-LABEL:   func.func @mul_i64(
+// CHECK-SAME:                      %[[ARG0:.*]]: i64,
+// CHECK-SAME:                      %[[ARG1:.*]]: i64) -> i64 {
+wasmssa.func @mul_i64(%arg0: !wasmssa<local ref to i64>, %arg1: !wasmssa<local ref to i64>) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+%v0 = wasmssa.local_get %arg0 : ref to i64
+%v1 = wasmssa.local_get %arg1 : ref to i64
+// CHECK:           %[[VAL_4:.*]] = arith.muli %[[VAL_2]], %[[VAL_3]] : i64
+%0 = wasmssa.mul %v0 %v1 : i64
+// CHECK:           return %[[VAL_4]] : i64
+wasmssa.return %0 : i64
+}
+// -----
+
+// CHECK-LABEL:   func.func @mul_f32(
+// CHECK-SAME:                      %[[ARG0:.*]]: f32,
+// CHECK-SAME:                      %[[ARG1:.*]]: f32) -> f32 {
+wasmssa.func @mul_f32(%arg0: !wasmssa<local ref to f32>, %arg1: !wasmssa<local ref to f32>) -> f32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<f32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<f32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<f32>
+%v0 = wasmssa.local_get %arg0 : ref to f32
+%v1 = wasmssa.local_get %arg1 : ref to f32
+// CHECK:           %[[VAL_4:.*]] = arith.mulf %[[VAL_2]], %[[VAL_3]] : f32
+%0 = wasmssa.mul %v0 %v1 : f32
+// CHECK:           return %[[VAL_4]] : f32
+wasmssa.return %0 : f32
+}
+
+// -----
+
+// CHECK-LABEL:   func.func @mul_f64(
+// CHECK-SAME:                      %[[ARG0:.*]]: f64,
+// CHECK-SAME:                      %[[ARG1:.*]]: f64) -> f64 {
+wasmssa.func @mul_f64(%arg0: !wasmssa<local ref to f64>, %arg1: !wasmssa<local ref to f64>) -> f64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<f64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<f64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<f64>
+%v0 = wasmssa.local_get %arg0 : ref to f64
+%v1 = wasmssa.local_get %arg1 : ref to f64
+// CHECK:           %[[VAL_4:.*]] = arith.mulf %[[VAL_2]], %[[VAL_3]] : f64
+%0 = wasmssa.mul %v0 %v1 : f64
+// CHECK:           return %[[VAL_4]] : f64
+wasmssa.return %0 : f64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-neg-to-arith-neg.mlir b/mlir/test/Conversion/RaiseWasm/wasm-neg-to-arith-neg.mlir
new file mode 100644
index 0000000000000..a15b9a6c25990
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-neg-to-arith-neg.mlir
@@ -0,0 +1,27 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+// CHECK-LABEL:   func.func @neg_f32(
+// CHECK-SAME:      %[[ARG0:.*]]: f32) -> f32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_1:.*]] = memref.load %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_2:.*]] = arith.negf %[[VAL_1]] : f32
+// CHECK:           return %[[VAL_2]] : f32
+wasmssa.func @neg_f32(%arg0: !wasmssa<local ref to f32>) -> f32 {
+    %val = wasmssa.local_get %arg0 : ref to f32
+    %op = wasmssa.neg %val : f32
+    wasmssa.return %op : f32
+}
+
+// CHECK-LABEL:   func.func @neg_f64(
+// CHECK-SAME:      %[[ARG0:.*]]: f64) -> f64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_1:.*]] = memref.load %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_2:.*]] = arith.negf %[[VAL_1]] : f64
+// CHECK:           return %[[VAL_2]] : f64
+wasmssa.func @neg_f64(%arg0: !wasmssa<local ref to f64>) -> f64 {
+    %val = wasmssa.local_get %arg0 : ref to f64
+    %op = wasmssa.neg %val : f64
+    wasmssa.return %op : f64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-or-to-arith-or.mlir b/mlir/test/Conversion/RaiseWasm/wasm-or-to-arith-or.mlir
new file mode 100644
index 0000000000000..44ce35209511d
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-or-to-arith-or.mlir
@@ -0,0 +1,38 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+
+// CHECK-LABEL:   func.func @or_i32(
+// CHECK-SAME:                      %[[ARG0:.*]]: i32,
+// CHECK-SAME:                      %[[ARG1:.*]]: i32) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_4:.*]] = arith.ori %[[VAL_2]], %[[VAL_3]] : i32
+// CHECK:           return %[[VAL_4]] : i32
+wasmssa.func exported @or_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
+    %or = wasmssa.or %v0 %v1 : i32
+    wasmssa.return %or : i32
+}
+
+// CHECK-LABEL:   func.func @or_i64(
+// CHECK-SAME:                      %[[ARG0:.*]]: i64,
+// CHECK-SAME:                      %[[ARG1:.*]]: i64) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_4:.*]] = arith.ori %[[VAL_2]], %[[VAL_3]] : i64
+// CHECK:           return %[[VAL_4]] : i64
+wasmssa.func exported @or_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
+    %or = wasmssa.or %v0 %v1 : i64
+    wasmssa.return %or : i64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-popcnt-to-math-ctpop.mlir b/mlir/test/Conversion/RaiseWasm/wasm-popcnt-to-math-ctpop.mlir
new file mode 100644
index 0000000000000..1c027cf1972e8
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-popcnt-to-math-ctpop.mlir
@@ -0,0 +1,27 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+// CHECK-LABEL:   func.func @popcnt_i32(
+// 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.ctpop %[[VAL_1]] : i32
+// CHECK:           return %[[VAL_2]] : i32
+wasmssa.func exported @popcnt_i32(%arg0: !wasmssa<local ref to i32>) -> i32 {
+    %v = wasmssa.local_get %arg0 : ref to i32
+    %op = wasmssa.popcnt %v : i32
+    wasmssa.return %op : i32
+}
+
+// CHECK-LABEL:   func.func @popcnt_i64(
+// CHECK-SAME:      %[[ARG0:.*]]: i64) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = math.ctpop %[[VAL_1]] : i64
+// CHECK:           return %[[VAL_2]] : i64
+wasmssa.func exported @popcnt_i64(%arg0: !wasmssa<local ref to i64>) -> i64 {
+    %v = wasmssa.local_get %arg0 : ref to i64
+    %op = wasmssa.popcnt %v : i64
+    wasmssa.return %op : i64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-promote-to-arith-ext.mlir b/mlir/test/Conversion/RaiseWasm/wasm-promote-to-arith-ext.mlir
new file mode 100644
index 0000000000000..5cf04a0ccbd3c
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-promote-to-arith-ext.mlir
@@ -0,0 +1,11 @@
+// RUN: mlir-opt %s --raise-wasm-mlir | FileCheck %s
+
+// CHECK-LABEL:   func.func @promote_f32_to_f64() -> f64 {
+wasmssa.func @promote_f32_to_f64() -> f64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 3.140000e+00 : f32
+  %0 = wasmssa.const 3.14 : f32
+// CHECK:           %[[VAL_1:.*]] = arith.extf %[[VAL_0]] : f32 to f64
+  %1 = wasmssa.promote %0 : f32 to f64
+// CHECK:           return %[[VAL_1]] : f64
+  wasmssa.return %1 : f64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-reinterpret-to-arith-bitcast.mlir b/mlir/test/Conversion/RaiseWasm/wasm-reinterpret-to-arith-bitcast.mlir
new file mode 100644
index 0000000000000..78e3984870d6b
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-reinterpret-to-arith-bitcast.mlir
@@ -0,0 +1,42 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+module {
+// CHECK-LABEL:   func.func @i32.reinterpret_f32() -> i32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant -1.000000e+00 : f32
+// CHECK:           %[[VAL_1:.*]] = arith.bitcast %[[VAL_0]] : f32 to i32
+// CHECK:           return %[[VAL_1]] : i32
+  wasmssa.func @i32.reinterpret_f32() -> i32 {
+    %0 = wasmssa.const -1.000000e+00 : f32
+    %1 = wasmssa.reinterpret %0 : f32 as i32
+    wasmssa.return %1 : i32
+  }
+
+// CHECK-LABEL:   func.func @i64.reinterpret_f64() -> i64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant -1.000000e+00 : f64
+// CHECK:           %[[VAL_1:.*]] = arith.bitcast %[[VAL_0]] : f64 to i64
+// CHECK:           return %[[VAL_1]] : i64
+  wasmssa.func @i64.reinterpret_f64() -> i64 {
+    %0 = wasmssa.const -1.000000e+00 : f64
+    %1 = wasmssa.reinterpret %0 : f64 as i64
+    wasmssa.return %1 : i64
+  }
+
+// CHECK-LABEL:   func.func @f32.reinterpret_i32() -> f32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant -1 : i32
+// CHECK:           %[[VAL_1:.*]] = arith.bitcast %[[VAL_0]] : i32 to f32
+// CHECK:           return %[[VAL_1]] : f32
+  wasmssa.func @f32.reinterpret_i32() -> f32 {
+    %0 = wasmssa.const -1 : i32
+    %1 = wasmssa.reinterpret %0 : i32 as f32
+    wasmssa.return %1 : f32
+  }
+
+// CHECK-LABEL:   func.func @f64.reinterpret_i64() -> f64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant -1 : i64
+// CHECK:           %[[VAL_1:.*]] = arith.bitcast %[[VAL_0]] : i64 to f64
+// CHECK:           return %[[VAL_1]] : f64
+  wasmssa.func @f64.reinterpret_i64() -> f64 {
+    %0 = wasmssa.const -1 : i64
+    %1 = wasmssa.reinterpret %0 : i64 as f64
+    wasmssa.return %1 : f64
+  }
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-rem-to-arith-rem.mlir b/mlir/test/Conversion/RaiseWasm/wasm-rem-to-arith-rem.mlir
new file mode 100644
index 0000000000000..05a5b5bd10cfa
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-rem-to-arith-rem.mlir
@@ -0,0 +1,74 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+
+// CHECK-LABEL:   func.func @rem_ui_32(
+// CHECK-SAME:      %[[ARG0:.*]]: i32,
+// CHECK-SAME:      %[[ARG1:.*]]: i32) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_4:.*]] = arith.remui %[[VAL_2]], %[[VAL_3]] : i32
+// CHECK:           return %[[VAL_4]] : i32
+wasmssa.func exported @rem_ui_32(%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
+    %rem = wasmssa.rem_ui %v0 %v1 : i32
+    wasmssa.return %rem : i32
+}
+
+// CHECK-LABEL:   func.func @rem_si_32(
+// CHECK-SAME:      %[[ARG0:.*]]: i32,
+// CHECK-SAME:      %[[ARG1:.*]]: i32) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_4:.*]] = arith.remsi %[[VAL_2]], %[[VAL_3]] : i32
+// CHECK:           return %[[VAL_4]] : i32
+wasmssa.func exported @rem_si_32(%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
+    %rem = wasmssa.rem_si %v0 %v1 : i32
+    wasmssa.return %rem : i32
+}
+
+// CHECK-LABEL:   func.func @rem_ui_64(
+// CHECK-SAME:      %[[ARG0:.*]]: i64,
+// CHECK-SAME:      %[[ARG1:.*]]: i64) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_4:.*]] = arith.remui %[[VAL_2]], %[[VAL_3]] : i64
+// CHECK:           return %[[VAL_4]] : i64
+wasmssa.func exported @rem_ui_64(%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
+    %rem = wasmssa.rem_ui %v0 %v1 : i64
+    wasmssa.return %rem : i64
+}
+
+// CHECK-LABEL:   func.func @rem_si_64(
+// CHECK-SAME:      %[[ARG0:.*]]: i64,
+// CHECK-SAME:      %[[ARG1:.*]]: i64) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_4:.*]] = arith.remsi %[[VAL_2]], %[[VAL_3]] : i64
+// CHECK:           return %[[VAL_4]] : i64
+wasmssa.func exported @rem_si_64(%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
+    %rem = wasmssa.rem_si %v0 %v1 : i64
+    wasmssa.return %rem : i64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-shl-to-arith-shl.mlir b/mlir/test/Conversion/RaiseWasm/wasm-shl-to-arith-shl.mlir
new file mode 100644
index 0000000000000..efc4b5ca49225
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-shl-to-arith-shl.mlir
@@ -0,0 +1,38 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+
+// CHECK-LABEL:   func.func @shl_i32(
+// CHECK-SAME:      %[[ARG0:.*]]: i32,
+// CHECK-SAME:      %[[ARG1:.*]]: i32) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_4:.*]] = arith.shli %[[VAL_2]], %[[VAL_3]] : i32
+// CHECK:           return %[[VAL_4]] : i32
+wasmssa.func exported @shl_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.shl %v0 by %v1 bits : i32
+    wasmssa.return %op : i32
+}
+
+// CHECK-LABEL:   func.func @shl_i64(
+// CHECK-SAME:      %[[ARG0:.*]]: i64,
+// CHECK-SAME:      %[[ARG1:.*]]: i64) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_4:.*]] = arith.shli %[[VAL_2]], %[[VAL_3]] : i64
+// CHECK:           return %[[VAL_4]] : i64
+wasmssa.func exported @shl_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.shl %v0 by %v1 bits : i64
+    wasmssa.return %op : i64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-shr_s-to-arith-shrs.mlir b/mlir/test/Conversion/RaiseWasm/wasm-shr_s-to-arith-shrs.mlir
new file mode 100644
index 0000000000000..d0c3a94e611a8
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-shr_s-to-arith-shrs.mlir
@@ -0,0 +1,38 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+
+// CHECK-LABEL:   func.func @shr_s_i32(
+// CHECK-SAME:      %[[ARG0:.*]]: i32,
+// CHECK-SAME:      %[[ARG1:.*]]: i32) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_4:.*]] = arith.shrsi %[[VAL_2]], %[[VAL_3]] : i32
+// CHECK:           return %[[VAL_4]] : i32
+wasmssa.func exported @shr_s_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.shr_s %v0 by %v1 bits : i32
+    wasmssa.return %op : i32
+}
+
+// CHECK-LABEL:   func.func @shr_s_i64(
+// CHECK-SAME:      %[[ARG0:.*]]: i64,
+// CHECK-SAME:      %[[ARG1:.*]]: i64) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_4:.*]] = arith.shrsi %[[VAL_2]], %[[VAL_3]] : i64
+// CHECK:           return %[[VAL_4]] : i64
+wasmssa.func exported @shr_s_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.shr_s %v0 by %v1 bits : i64
+    wasmssa.return %op : i64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-shr_u-to-arith-shru.mlir b/mlir/test/Conversion/RaiseWasm/wasm-shr_u-to-arith-shru.mlir
new file mode 100644
index 0000000000000..38925b6899c4b
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-shr_u-to-arith-shru.mlir
@@ -0,0 +1,37 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+// CHECK-LABEL:   func.func @shr_u_i32(
+// CHECK-SAME:      %[[ARG0:.*]]: i32,
+// CHECK-SAME:      %[[ARG1:.*]]: i32) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_4:.*]] = arith.shrui %[[VAL_2]], %[[VAL_3]] : i32
+// CHECK:           return %[[VAL_4]] : i32
+wasmssa.func exported @shr_u_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.shr_u %v0 by %v1 bits : i32
+    wasmssa.return %op : i32
+}
+
+// CHECK-LABEL:   func.func @shr_u_i64(
+// CHECK-SAME:      %[[ARG0:.*]]: i64,
+// CHECK-SAME:      %[[ARG1:.*]]: i64) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_4:.*]] = arith.shrui %[[VAL_2]], %[[VAL_3]] : i64
+// CHECK:           return %[[VAL_4]] : i64
+wasmssa.func exported @shr_u_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.shr_u %v0 by %v1 bits : i64
+    wasmssa.return %op : i64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-sqrt-to-math-sqrt.mlir b/mlir/test/Conversion/RaiseWasm/wasm-sqrt-to-math-sqrt.mlir
new file mode 100644
index 0000000000000..394dc9e3216af
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-sqrt-to-math-sqrt.mlir
@@ -0,0 +1,27 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+// CHECK-LABEL:   func.func @sqrt_f32(
+// CHECK-SAME:      %[[ARG0:.*]]: f32) -> f32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_1:.*]] = memref.load %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_2:.*]] = math.sqrt %[[VAL_1]] : f32
+// CHECK:           return %[[VAL_2]] : f32
+wasmssa.func @sqrt_f32(%arg0: !wasmssa<local ref to f32>) -> f32 {
+    %local = wasmssa.local_get %arg0 : ref to f32
+    %op = wasmssa.sqrt %local : f32
+    wasmssa.return %op : f32
+}
+
+// CHECK-LABEL:   func.func @sqrt_f64(
+// CHECK-SAME:      %[[ARG0:.*]]: f64) -> f64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_1:.*]] = memref.load %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_2:.*]] = math.sqrt %[[VAL_1]] : f64
+// CHECK:           return %[[VAL_2]] : f64
+wasmssa.func @sqrt_f64(%arg0: !wasmssa<local ref to f64>) -> f64 {
+    %local = wasmssa.local_get %arg0 : ref to f64
+    %op = wasmssa.sqrt %local : f64
+    wasmssa.return %op : f64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-sub-to-arith-sub.mlir b/mlir/test/Conversion/RaiseWasm/wasm-sub-to-arith-sub.mlir
new file mode 100644
index 0000000000000..933d3d16add7b
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-sub-to-arith-sub.mlir
@@ -0,0 +1,80 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir | FileCheck %s
+
+// CHECK-LABEL:   func.func @func_1(
+// CHECK-SAME:                      %[[ARG0:.*]]: i32,
+// CHECK-SAME:                      %[[ARG1:.*]]: i32) -> i32 {
+wasmssa.func @func_1(%arg0: !wasmssa<local ref to i32>, %arg1: !wasmssa<local ref to i32>) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+%v0 = wasmssa.local_get %arg0 : ref to i32
+%v1 = wasmssa.local_get %arg1 : ref to i32
+// CHECK:           %[[VAL_4:.*]] = arith.subi %[[VAL_2]], %[[VAL_3]] : i32
+%res = wasmssa.sub %v0 %v1 : i32
+// CHECK:           return %[[VAL_4]] : i32
+wasmssa.return %res : i32
+}
+
+// -----
+
+// CHECK-LABEL:   func.func @func_2(
+// CHECK-SAME:                      %[[ARG0:.*]]: i64,
+// CHECK-SAME:                      %[[ARG1:.*]]: i64) -> i64 {
+wasmssa.func @func_2(%arg0: !wasmssa<local ref to i64>, %arg1: !wasmssa<local ref to i64>) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+%v0 = wasmssa.local_get %arg0 : ref to i64
+%v1 = wasmssa.local_get %arg1 : ref to i64
+// CHECK:           %[[VAL_4:.*]] = arith.subi %[[VAL_2]], %[[VAL_3]] : i64
+%res = wasmssa.sub %v0 %v1 : i64
+// CHECK:           return %[[VAL_4]] : i64
+wasmssa.return %res : i64
+}
+
+// -----
+
+// CHECK-LABEL:   func.func @func_3(
+// CHECK-SAME:                      %[[ARG0:.*]]: f32,
+// CHECK-SAME:                      %[[ARG1:.*]]: f32) -> f32 {
+wasmssa.func @func_3(%arg0: !wasmssa<local ref to f32>, %arg1: !wasmssa<local ref to f32>) -> f32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<f32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<f32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<f32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<f32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<f32>
+%v0 = wasmssa.local_get %arg0 : ref to f32
+%v1 = wasmssa.local_get %arg1 : ref to f32
+// CHECK:           %[[VAL_4:.*]] = arith.subf %[[VAL_2]], %[[VAL_3]] : f32
+%res = wasmssa.sub %v0 %v1 : f32
+// CHECK:           return %[[VAL_4]] : f32
+wasmssa.return %res : f32
+}
+
+
+// -----
+
+// CHECK-LABEL:   func.func @func_4(
+// CHECK-SAME:                      %[[ARG0:.*]]: f64,
+// CHECK-SAME:                      %[[ARG1:.*]]: f64) -> f64 {
+wasmssa.func @func_4(%arg0: !wasmssa<local ref to f64>, %arg1: !wasmssa<local ref to f64>) -> f64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<f64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<f64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<f64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<f64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<f64>
+%v0 = wasmssa.local_get %arg0 : ref to f64
+%v1 = wasmssa.local_get %arg1 : ref to f64
+// CHECK:           %[[VAL_4:.*]] = arith.subf %[[VAL_2]], %[[VAL_3]] : f64
+%res = wasmssa.sub %v0 %v1 : f64
+// CHECK:           return %[[VAL_4]] : f64
+wasmssa.return %res : f64
+}
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-trunc-to-math-trunc.mlir b/mlir/test/Conversion/RaiseWasm/wasm-trunc-to-math-trunc.mlir
new file mode 100644
index 0000000000000..a120967bc3c0e
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-trunc-to-math-trunc.mlir
@@ -0,0 +1,24 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+module {
+  wasmssa.func @func_4() -> f64 {
+    %0 = wasmssa.const -1.210000e+01 : f64
+    %1 = wasmssa.trunc %0 : f64
+    wasmssa.return %1 : f64
+  }
+  wasmssa.func @func_5() -> f32 {
+    %0 = wasmssa.const 1.618000e+00 : f32
+    %1 = wasmssa.trunc %0 : f32
+    wasmssa.return %1 : f32
+  }
+}
+
+// CHECK-LABEL:   func.func @func_4() -> f64 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant -1.210000e+01 : f64
+// CHECK:           %[[VAL_1:.*]] = math.trunc %[[VAL_0]] : f64
+// CHECK:           return %[[VAL_1]] : f64
+
+// CHECK-LABEL:   func.func @func_5() -> f32 {
+// CHECK:           %[[VAL_0:.*]] = arith.constant 1.618000e+00 : f32
+// CHECK:           %[[VAL_1:.*]] = math.trunc %[[VAL_0]] : f32
+// CHECK:           return %[[VAL_1]] : f32
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-wrap-to-arith-trunc.mlir b/mlir/test/Conversion/RaiseWasm/wasm-wrap-to-arith-trunc.mlir
new file mode 100644
index 0000000000000..6164525626086
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-wrap-to-arith-trunc.mlir
@@ -0,0 +1,17 @@
+// RUN: mlir-opt %s --raise-wasm-mlir | FileCheck %s
+
+module {
+  wasmssa.func @i64_wrap(%arg0: !wasmssa<local ref to i64>) -> i32 {
+    %0 = wasmssa.local_get %arg0 :  ref to i64
+    %1 = wasmssa.wrap %0 : i64 to i32
+    wasmssa.return %1 : i32
+  }
+}
+
+// CHECK-LABEL:   func.func @i64_wrap(
+// CHECK-SAME:      %[[ARG0:.*]]: i64) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = arith.trunci %[[VAL_1]] : i64 to i32
+// CHECK:           return %[[VAL_2]] : i32
diff --git a/mlir/test/Conversion/RaiseWasm/wasm-xor-to-arith-xor.mlir b/mlir/test/Conversion/RaiseWasm/wasm-xor-to-arith-xor.mlir
new file mode 100644
index 0000000000000..810729d883c61
--- /dev/null
+++ b/mlir/test/Conversion/RaiseWasm/wasm-xor-to-arith-xor.mlir
@@ -0,0 +1,37 @@
+// RUN: mlir-opt --split-input-file %s --raise-wasm-mlir -o - | FileCheck %s
+
+// CHECK-LABEL:   func.func @xor_i32(
+// CHECK-SAME:                      %[[ARG0:.*]]: i32,
+// CHECK-SAME:                      %[[ARG1:.*]]: i32) -> i32 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i32>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i32>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i32>
+// CHECK:           %[[VAL_4:.*]] = arith.xori %[[VAL_2]], %[[VAL_3]] : i32
+// CHECK:           return %[[VAL_4]] : i32
+wasmssa.func @xor_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
+    %xor = wasmssa.xor %v0 %v1 : i32
+    wasmssa.return %xor : i32
+}
+
+// CHECK-LABEL:   func.func @xor_i64(
+// CHECK-SAME:                      %[[ARG0:.*]]: i64,
+// CHECK-SAME:                      %[[ARG1:.*]]: i64) -> i64 {
+// CHECK:           %[[VAL_0:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG1]], %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_1:.*]] = memref.alloca() : memref<i64>
+// CHECK:           memref.store %[[ARG0]], %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_2:.*]] = memref.load %[[VAL_1]][] : memref<i64>
+// CHECK:           %[[VAL_3:.*]] = memref.load %[[VAL_0]][] : memref<i64>
+// CHECK:           %[[VAL_4:.*]] = arith.xori %[[VAL_2]], %[[VAL_3]] : i64
+// CHECK:           return %[[VAL_4]] : i64
+wasmssa.func @xor_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
+    %xor = wasmssa.xor %v0 %v1 : i64
+    wasmssa.return %xor : i64
+}

>From 45777056948ab39d1bc0169904aa98261db79425 Mon Sep 17 00:00:00 2001
From: Ferdinand Lemaire <ferdinand.lemaire at woven-planet.global>
Date: Thu, 23 Oct 2025 13:58:45 +0900
Subject: [PATCH 3/4] [mlir][WASM] Remove extraneous declaration and change
 interface of GlobalOp to retrieve its terminator operation

---
 .../mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h      |  3 ---
 mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td |  5 ++++-
 mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp    |  5 ++---
 mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp         | 14 ++++++++++++++
 4 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/mlir/include/mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h b/mlir/include/mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h
index 3faf9dc255a11..048eeb3149cf7 100644
--- a/mlir/include/mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h
+++ b/mlir/include/mlir/Conversion/RaiseWasm/RaiseWasmMLIR.h
@@ -24,9 +24,6 @@ class RewritePatternSet;
 void populateRaiseWasmMLIRConversionPatterns(TypeConverter &,
                                              RewritePatternSet &);
 
-/// Create a pass to convert ops from WasmDialect to standard dialects.
-std::unique_ptr<Pass> createRaiseWasmMLIRPass();
-
 } // namespace mlir
 
 #endif // MLIR_CONVERSION_RAISEWASM_RAISEWASMMLIR_H
diff --git a/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td b/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td
index e9425e884ae83..afa98c57f0ad9 100644
--- a/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td
+++ b/mlir/include/mlir/Dialect/WasmSSA/IR/WasmSSAOps.td
@@ -318,7 +318,7 @@ def WasmSSA_GlobalOp : WasmSSA_Op<"global", [
     }
     ```
   }];
-  let regions = (region AnyRegion: $initializer);
+  let regions = (region SizedRegion<1>: $initializer);
 
   let extraClassDeclaration = [{
     ::mlir::SymbolTable::Visibility getVisibility() {
@@ -326,8 +326,11 @@ def WasmSSA_GlobalOp : WasmSSA_Op<"global", [
         ::mlir::SymbolTable::Visibility::Public :
         ::mlir::SymbolTable::Visibility::Nested;
     };
+
+    wasmssa::ReturnOp getInitTerminator();
   }];
   let hasCustomAssemblyFormat = 1;
+  let hasVerifier = 1;
 }
 
 def WasmSSA_GlobalImportOp : WasmSSA_Op<"import_global", [
diff --git a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
index 3970903164286..81e8a2a311bc3 100644
--- a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
+++ b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
@@ -209,8 +209,7 @@ struct GlobalOpConverter : OpConversionPattern<GlobalOp> {
   LogicalResult
   matchAndRewrite(GlobalOp globalOp, GlobalOp::Adaptor adaptor,
                   ConversionPatternRewriter &rewriter) const override {
-    ReturnOp rop;
-    globalOp->walk([&rop](ReturnOp op) { rop = op; });
+    ReturnOp rop = globalOp.getInitTerminator();
 
     if (rop->getNumOperands() != 1)
       return rewriter.notifyMatchFailure(
@@ -461,6 +460,6 @@ void mlir::populateRaiseWasmMLIRConversionPatterns(
   // clang-format on
 }
 
-std::unique_ptr<Pass> mlir::createRaiseWasmMLIRPass() {
+std::unique_ptr<Pass> createRaiseWasmMLIRPass() {
   return std::make_unique<RaiseWasmMLIRPass>();
 }
diff --git a/mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp b/mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp
index a514ea9218bd7..144fbb21de915 100644
--- a/mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp
+++ b/mlir/lib/Dialect/WasmSSA/IR/WasmSSAOps.cpp
@@ -246,6 +246,16 @@ void FuncImportOp::build(OpBuilder &odsBuilder, OperationState &odsState,
 //===----------------------------------------------------------------------===//
 // GlobalOp
 //===----------------------------------------------------------------------===//
+namespace {
+Operation *getGlobalOpTerminatorOp(GlobalOp gop) {
+  return gop.getInitializer().begin()->getTerminator();
+}
+} // namespace
+
+ReturnOp GlobalOp::getInitTerminator() {
+  return llvm::cast<wasmssa::ReturnOp>(getGlobalOpTerminatorOp(*this));
+}
+
 // Custom formats
 ParseResult GlobalOp::parse(OpAsmParser &parser, OperationState &result) {
   StringAttr symbolName;
@@ -292,6 +302,10 @@ void GlobalOp::print(OpAsmPrinter &printer) {
   }
 }
 
+LogicalResult GlobalOp::verify() {
+  return success(llvm::isa<ReturnOp>(getGlobalOpTerminatorOp(*this)));
+}
+
 //===----------------------------------------------------------------------===//
 // GlobalGetOp
 //===----------------------------------------------------------------------===//

>From 45e31c05d851d2cc2a64b696af7b43b5f6125b74 Mon Sep 17 00:00:00 2001
From: Ferdinand Lemaire <ferdinand.lemaire at woven-planet.global>
Date: Thu, 23 Oct 2025 17:34:27 +0900
Subject: [PATCH 4/4] [mlir][WASM] Deprecate rewriter.create in RaiseWasmMLIR

---
 .../Conversion/RaiseWasm/RaiseWasmMLIR.cpp    | 46 ++++++++++---------
 1 file changed, 25 insertions(+), 21 deletions(-)

diff --git a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
index 81e8a2a311bc3..0f035a2cdcca7 100644
--- a/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
+++ b/mlir/lib/Conversion/RaiseWasm/RaiseWasmMLIR.cpp
@@ -167,8 +167,9 @@ struct WasmFuncOpConversion : OpConversionPattern<FuncOp> {
   LogicalResult
   matchAndRewrite(FuncOp funcOp, FuncOp::Adaptor adaptor,
                   ConversionPatternRewriter &rewriter) const override {
-    auto newFunc = rewriter.create<func::FuncOp>(
-        funcOp->getLoc(), funcOp.getSymName(), funcOp.getFunctionType());
+    auto newFunc =
+      func::FuncOp::create(rewriter, funcOp->getLoc(), funcOp.getSymName(),
+                           funcOp.getFunctionType());
     rewriter.cloneRegionBefore(funcOp.getBody(), newFunc.getBody(),
                                newFunc.getBody().end());
     Block *oldEntryBlock = &newFunc.getBody().front();
@@ -261,23 +262,26 @@ struct WasmGlobalWithGetGlobalInitConversion
     globalReplacement.setConstant(!globalOp.getIsMutable());
     auto loc = globalOp.getLoc();
     auto initializerName = (globalOp.getSymName() + "::initializer").str();
-    auto globalInitializer = rewriter.create<func::FuncOp>(
-        loc, initializerName, FunctionType::get(getContext(), {}, {}));
+    auto globalInitializer =
+        func::FuncOp::create(rewriter,loc, initializerName,
+                             FunctionType::get(getContext(), {}, {}));
     globalInitializer->setAttr(rewriter.getStringAttr("initializer"),
                                rewriter.getUnitAttr());
     auto *initializerBody = globalInitializer.addEntryBlock();
     auto sip = rewriter.saveInsertionPoint();
     rewriter.setInsertionPointToStart(initializerBody);
-    auto srcGlobalPtr = rewriter.create<memref::GetGlobalOp>(
-        loc, MemRefType::get({1}, constInit.getType()), constInit.getGlobal());
-    auto destGlobalPtr = rewriter.create<memref::GetGlobalOp>(
-        loc, globalReplacement.getType(), globalReplacement.getSymName());
-    auto idx = rewriter.create<arith::ConstantIndexOp>(loc, 0).getResult();
+    auto srcGlobalPtr = memref::GetGlobalOp::create(
+      rewriter, loc, MemRefType::get({1}, constInit.getType()),
+      constInit.getGlobal());
+    auto destGlobalPtr =
+        memref::GetGlobalOp::create(rewriter, loc, globalReplacement.getType(),
+                                    globalReplacement.getSymName());
+    auto idx = arith::ConstantIndexOp::create(rewriter, loc, 0).getResult();
     auto loadSrc =
-        rewriter.create<memref::LoadOp>(loc, srcGlobalPtr, ValueRange{idx});
-    rewriter.create<memref::StoreOp>(
+        memref::LoadOp::create(rewriter, loc, srcGlobalPtr, ValueRange{idx});
+    memref::StoreOp::create(rewriter,
         loc, loadSrc.getResult(), destGlobalPtr.getResult(), ValueRange{idx});
-    rewriter.create<func::ReturnOp>(loc);
+    func::ReturnOp::create(rewriter, loc);
     rewriter.restoreInsertionPoint(sip);
     return success();
   }
@@ -301,11 +305,11 @@ struct WasmLocalConversion : OpConversionPattern<LocalOp> {
     auto alloca = rewriter.replaceOpWithNewOp<memref::AllocaOp>(
         localOp,
         MemRefType::get({}, localOp.getResult().getType().getElementType()));
-    auto initializer = rewriter.create<arith::ConstantOp>(
-        localOp->getLoc(),
+    auto initializer = arith::ConstantOp::create(
+        rewriter, localOp->getLoc(),
         getInitializerAttr(localOp.getResult().getType().getElementType()));
-    rewriter.create<memref::StoreOp>(localOp->getLoc(), initializer.getResult(),
-                                     alloca.getResult());
+    memref::StoreOp::create(rewriter, localOp->getLoc(),
+                            initializer.getResult(), alloca.getResult());
     return success();
   }
 };
@@ -338,8 +342,8 @@ struct WasmLocalTeeConversion : OpConversionPattern<LocalTeeOp> {
   LogicalResult
   matchAndRewrite(LocalTeeOp localTeeOp, LocalTeeOp::Adaptor adaptor,
                   ConversionPatternRewriter &rewriter) const override {
-    rewriter.create<memref::StoreOp>(localTeeOp->getLoc(), adaptor.getValue(),
-                                     adaptor.getLocalVar());
+    memref::StoreOp::create(rewriter, localTeeOp->getLoc(), adaptor.getValue(),
+                            adaptor.getLocalVar());
     rewriter.replaceOp(localTeeOp, adaptor.getValue());
     return success();
   }
@@ -375,9 +379,9 @@ struct RaiseWasmMLIRPass : public impl::RaiseWasmMLIRBase<RaiseWasmMLIRPass> {
       if (values.size() != 1 ||
           values.front().getType() != destType.getElementType())
         return {};
-      auto localVar = builder.create<memref::AllocaOp>(loc, destType);
-      builder.create<memref::StoreOp>(loc, values.front(),
-                                      localVar.getResult());
+      auto localVar = memref::AllocaOp::create(builder, loc, destType);
+      memref::StoreOp::create(builder, loc, values.front(),
+                              localVar.getResult());
       return localVar.getResult();
     });
     populateRaiseWasmMLIRConversionPatterns(tc, patterns);



More information about the Mlir-commits mailing list