Skip to content

Conversation

lforg37
Copy link
Contributor

@lforg37 lforg37 commented Aug 20, 2025

This is a cherry pick of #154053 with a fix for bad handling of endianess when loading float and double litteral from the binary.

…lvm#154053)

This is the continuation of  llvm#152131 

This PR adds support for parsing the global initializer and function
body, and support for decoding scalar numerical instructions and
variable related instructions.

---------

Co-authored-by: Ferdinand Lemaire <ferdinand.lemaire@woven-planet.global>
Co-authored-by: Jessica Paquette <jessica.paquette@woven-planet.global>
Co-authored-by: Luc Forget <luc.forget@woven.toyota>
@lforg37 lforg37 marked this pull request as ready for review August 20, 2025 02:06
@llvmbot llvmbot added the mlir label Aug 20, 2025
@llvmbot
Copy link
Member

llvmbot commented Aug 20, 2025

@llvm/pr-subscribers-mlir

Author: Luc Forget (lforg37)

Changes

This is a cherry pick of #154053 with a fix for bad handling of endianess when loading float and double litteral from the binary.


Patch is 82.31 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/154452.diff

48 Files Affected:

  • (modified) mlir/include/mlir/Target/Wasm/WasmBinaryEncoding.h (+69)
  • (modified) mlir/lib/Target/Wasm/TranslateFromWasm.cpp (+301-23)
  • (added) mlir/test/Target/Wasm/abs.mlir (+23)
  • (added) mlir/test/Target/Wasm/and.mlir (+27)
  • (added) mlir/test/Target/Wasm/clz.mlir (+25)
  • (added) mlir/test/Target/Wasm/const.mlir (+37)
  • (added) mlir/test/Target/Wasm/copysign.mlir (+31)
  • (added) mlir/test/Target/Wasm/ctz.mlir (+25)
  • (added) mlir/test/Target/Wasm/div.mlir (+127)
  • (added) mlir/test/Target/Wasm/global.mlir (+66)
  • (added) mlir/test/Target/Wasm/inputs/abs.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/and.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/clz.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/const.yaml.wasm (+39)
  • (added) mlir/test/Target/Wasm/inputs/copysign.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/ctz.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/div.yaml.wasm (+89)
  • (added) mlir/test/Target/Wasm/inputs/global.yaml.wasm (+63)
  • (added) mlir/test/Target/Wasm/inputs/local.yaml.wasm (+37)
  • (added) mlir/test/Target/Wasm/inputs/max.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/min.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/neg.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/or.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/popcnt.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/rem.yaml.wasm (+45)
  • (added) mlir/test/Target/Wasm/inputs/rotl.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/rotr.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/shl.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/shr_s.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/shr_u.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/sqrt.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/inputs/sub.yaml.wasm (+39)
  • (added) mlir/test/Target/Wasm/inputs/xor.yaml.wasm (+33)
  • (added) mlir/test/Target/Wasm/local.mlir (+59)
  • (added) mlir/test/Target/Wasm/max.mlir (+30)
  • (added) mlir/test/Target/Wasm/min.mlir (+29)
  • (added) mlir/test/Target/Wasm/neg.mlir (+23)
  • (added) mlir/test/Target/Wasm/or.mlir (+27)
  • (added) mlir/test/Target/Wasm/popcnt.mlir (+25)
  • (added) mlir/test/Target/Wasm/rem.mlir (+53)
  • (added) mlir/test/Target/Wasm/rotl.mlir (+27)
  • (added) mlir/test/Target/Wasm/rotr.mlir (+27)
  • (added) mlir/test/Target/Wasm/shl.mlir (+27)
  • (added) mlir/test/Target/Wasm/shr_s.mlir (+27)
  • (added) mlir/test/Target/Wasm/shr_u.mlir (+27)
  • (added) mlir/test/Target/Wasm/sqrt.mlir (+23)
  • (added) mlir/test/Target/Wasm/sub.mlir (+52)
  • (added) mlir/test/Target/Wasm/xor.mlir (+27)
diff --git a/mlir/include/mlir/Target/Wasm/WasmBinaryEncoding.h b/mlir/include/mlir/Target/Wasm/WasmBinaryEncoding.h
index 3280432b5f038..21adde878994e 100644
--- a/mlir/include/mlir/Target/Wasm/WasmBinaryEncoding.h
+++ b/mlir/include/mlir/Target/Wasm/WasmBinaryEncoding.h
@@ -20,10 +20,79 @@ struct WasmBinaryEncoding {
   /// Byte encodings for Wasm instructions.
   struct OpCode {
     // Locals, globals, constants.
+    static constexpr std::byte localGet{0x20};
+    static constexpr std::byte localSet{0x21};
+    static constexpr std::byte localTee{0x22};
+    static constexpr std::byte globalGet{0x23};
     static constexpr std::byte constI32{0x41};
     static constexpr std::byte constI64{0x42};
     static constexpr std::byte constFP32{0x43};
     static constexpr std::byte constFP64{0x44};
+
+    // Numeric operations.
+    static constexpr std::byte clzI32{0x67};
+    static constexpr std::byte ctzI32{0x68};
+    static constexpr std::byte popcntI32{0x69};
+    static constexpr std::byte addI32{0x6A};
+    static constexpr std::byte subI32{0x6B};
+    static constexpr std::byte mulI32{0x6C};
+    static constexpr std::byte divSI32{0x6d};
+    static constexpr std::byte divUI32{0x6e};
+    static constexpr std::byte remSI32{0x6f};
+    static constexpr std::byte remUI32{0x70};
+    static constexpr std::byte andI32{0x71};
+    static constexpr std::byte orI32{0x72};
+    static constexpr std::byte xorI32{0x73};
+    static constexpr std::byte shlI32{0x74};
+    static constexpr std::byte shrSI32{0x75};
+    static constexpr std::byte shrUI32{0x76};
+    static constexpr std::byte rotlI32{0x77};
+    static constexpr std::byte rotrI32{0x78};
+    static constexpr std::byte clzI64{0x79};
+    static constexpr std::byte ctzI64{0x7A};
+    static constexpr std::byte popcntI64{0x7B};
+    static constexpr std::byte addI64{0x7C};
+    static constexpr std::byte subI64{0x7D};
+    static constexpr std::byte mulI64{0x7E};
+    static constexpr std::byte divSI64{0x7F};
+    static constexpr std::byte divUI64{0x80};
+    static constexpr std::byte remSI64{0x81};
+    static constexpr std::byte remUI64{0x82};
+    static constexpr std::byte andI64{0x83};
+    static constexpr std::byte orI64{0x84};
+    static constexpr std::byte xorI64{0x85};
+    static constexpr std::byte shlI64{0x86};
+    static constexpr std::byte shrSI64{0x87};
+    static constexpr std::byte shrUI64{0x88};
+    static constexpr std::byte rotlI64{0x89};
+    static constexpr std::byte rotrI64{0x8A};
+    static constexpr std::byte absF32{0x8B};
+    static constexpr std::byte negF32{0x8C};
+    static constexpr std::byte ceilF32{0x8D};
+    static constexpr std::byte floorF32{0x8E};
+    static constexpr std::byte truncF32{0x8F};
+    static constexpr std::byte sqrtF32{0x91};
+    static constexpr std::byte addF32{0x92};
+    static constexpr std::byte subF32{0x93};
+    static constexpr std::byte mulF32{0x94};
+    static constexpr std::byte divF32{0x95};
+    static constexpr std::byte minF32{0x96};
+    static constexpr std::byte maxF32{0x97};
+    static constexpr std::byte copysignF32{0x98};
+    static constexpr std::byte absF64{0x99};
+    static constexpr std::byte negF64{0x9A};
+    static constexpr std::byte ceilF64{0x9B};
+    static constexpr std::byte floorF64{0x9C};
+    static constexpr std::byte truncF64{0x9D};
+    static constexpr std::byte sqrtF64{0x9F};
+    static constexpr std::byte addF64{0xA0};
+    static constexpr std::byte subF64{0xA1};
+    static constexpr std::byte mulF64{0xA2};
+    static constexpr std::byte divF64{0xA3};
+    static constexpr std::byte minF64{0xA4};
+    static constexpr std::byte maxF64{0xA5};
+    static constexpr std::byte copysignF64{0xA6};
+    static constexpr std::byte wrap{0xA7};
   };
 
   /// Byte encodings of types in Wasm binaries
diff --git a/mlir/lib/Target/Wasm/TranslateFromWasm.cpp b/mlir/lib/Target/Wasm/TranslateFromWasm.cpp
index 8d450520629eb..f77699cb6ca9c 100644
--- a/mlir/lib/Target/Wasm/TranslateFromWasm.cpp
+++ b/mlir/lib/Target/Wasm/TranslateFromWasm.cpp
@@ -16,15 +16,18 @@
 #include "mlir/IR/BuiltinAttributeInterfaces.h"
 #include "mlir/IR/BuiltinTypes.h"
 #include "mlir/IR/Location.h"
+#include "mlir/Support/LLVM.h"
 #include "mlir/Target/Wasm/WasmBinaryEncoding.h"
 #include "mlir/Target/Wasm/WasmImporter.h"
-#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/bit.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/DebugLog.h"
+#include "llvm/Support/Endian.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/LEB128.h"
+#include "llvm/Support/LogicalResult.h"
 
-#include <climits>
+#include <cstddef>
 #include <cstdint>
 #include <variant>
 
@@ -148,22 +151,22 @@ struct WasmModuleSymbolTables {
   }
 
   std::string getNewFuncSymbolName() const {
-    auto id = funcSymbols.size();
+    size_t id = funcSymbols.size();
     return getNewSymbolName("func_", id);
   }
 
   std::string getNewGlobalSymbolName() const {
-    auto id = globalSymbols.size();
+    size_t id = globalSymbols.size();
     return getNewSymbolName("global_", id);
   }
 
   std::string getNewMemorySymbolName() const {
-    auto id = memSymbols.size();
+    size_t id = memSymbols.size();
     return getNewSymbolName("mem_", id);
   }
 
   std::string getNewTableSymbolName() const {
-    auto id = tableSymbols.size();
+    size_t id = tableSymbols.size();
     return getNewSymbolName("table_", id);
   }
 };
@@ -232,6 +235,20 @@ class ExpressionParser {
   parseConstInst(OpBuilder &builder,
                  std::enable_if_t<std::is_arithmetic_v<valueT>> * = nullptr);
 
+  /// Construct an operation with \p numOperands operands and a single result.
+  /// Each operand must have the same type. Suitable for e.g. binops, unary
+  /// ops, etc.
+  ///
+  /// \p opcode - The WASM opcode to build.
+  /// \p valueType - The operand and result type for the built instruction.
+  /// \p numOperands - The number of operands for the built operation.
+  ///
+  /// \returns The parsed instruction result, or failure.
+  template <typename opcode, typename valueType, unsigned int numOperands>
+  inline parsed_inst_t
+  buildNumericOp(OpBuilder &builder,
+                 std::enable_if_t<std::is_arithmetic_v<valueType>> * = nullptr);
+
   /// This function generates a dispatch tree to associate an opcode with a
   /// parser. Parsers are registered by specialising the
   /// `parseSpecificInstruction` function for the op code to handle.
@@ -286,10 +303,16 @@ class ExpressionParser {
     return valueStack.pushResults(results, &currentOpLoc.value());
   }
 
+  /// The local.set and local.tee operations behave similarly and only differ
+  /// on their return value. This function factorizes the behavior of the two
+  /// operations in one place.
+  template <typename OpToCreate>
+  parsed_inst_t parseSetOrTee(OpBuilder &);
+
 private:
   std::optional<Location> currentOpLoc;
   ParserHead &parser;
-  [[maybe_unused]] WasmModuleSymbolTables const &symbols;
+  WasmModuleSymbolTables const &symbols;
   locals_t locals;
   ValueStack valueStack;
 };
@@ -322,7 +345,7 @@ class ParserHead {
   }
 
   FailureOr<std::byte> consumeByte() {
-    auto res = consumeNBytes(1);
+    FailureOr<StringRef> res = consumeNBytes(1);
     if (failed(res))
       return failure();
     return std::byte{*res->bytes_begin()};
@@ -482,7 +505,7 @@ class ParserHead {
     FileLineColLoc importLoc = getLocation();
     FailureOr<std::byte> importType = consumeByte();
     auto packager = [](auto parseResult) -> FailureOr<ImportDesc> {
-      if (llvm::failed(parseResult))
+      if (failed(parseResult))
         return failure();
       return {*parseResult};
     };
@@ -510,6 +533,60 @@ class ParserHead {
     return eParser.parse(builder);
   }
 
+  LogicalResult parseCodeFor(FuncOp func,
+                             WasmModuleSymbolTables const &symbols) {
+    SmallVector<local_val_t> locals{};
+    // Populating locals with function argument
+    Block &block = func.getBody().front();
+    // Delete temporary return argument which was only created for IR validity
+    assert(func.getBody().getBlocks().size() == 1 &&
+           "Function should only have its default created block at this point");
+    assert(block.getOperations().size() == 1 &&
+           "Only the placeholder return op should be present at this point");
+    auto returnOp = cast<ReturnOp>(&block.back());
+    assert(returnOp);
+
+    FailureOr<uint32_t> codeSizeInBytes = parseUI32();
+    if (failed(codeSizeInBytes))
+      return failure();
+    FailureOr<StringRef> codeContent = consumeNBytes(*codeSizeInBytes);
+    if (failed(codeContent))
+      return failure();
+    auto name = StringAttr::get(func->getContext(),
+                                locName.str() + "::" + func.getSymName());
+    auto cParser = ParserHead{*codeContent, name};
+    FailureOr<uint32_t> localVecSize = cParser.parseVectorSize();
+    if (failed(localVecSize))
+      return failure();
+    OpBuilder builder{&func.getBody().front().back()};
+    for (auto arg : block.getArguments())
+      locals.push_back(cast<TypedValue<LocalRefType>>(arg));
+    // Declare the local ops
+    uint32_t nVarVec = *localVecSize;
+    for (size_t i = 0; i < nVarVec; ++i) {
+      FileLineColLoc varLoc = cParser.getLocation();
+      FailureOr<uint32_t> nSubVar = cParser.parseUI32();
+      if (failed(nSubVar))
+        return failure();
+      FailureOr<Type> varT = cParser.parseValueType(func->getContext());
+      if (failed(varT))
+        return failure();
+      for (size_t j = 0; j < *nSubVar; ++j) {
+        auto local = builder.create<LocalOp>(varLoc, *varT);
+        locals.push_back(local.getResult());
+      }
+    }
+    parsed_inst_t res = cParser.parseExpression(builder, symbols, locals);
+    if (failed(res))
+      return failure();
+    if (!cParser.end())
+      return emitError(cParser.getLocation(),
+                       "unparsed garbage remaining at end of code block");
+    builder.create<ReturnOp>(func->getLoc(), *res);
+    returnOp->erase();
+    return success();
+  }
+
   bool end() const { return curHead().empty(); }
 
   ParserHead copy() const { return *this; }
@@ -535,22 +612,20 @@ class ParserHead {
 
 template <>
 FailureOr<float> ParserHead::parseLiteral<float>() {
-  auto bytes = consumeNBytes(4);
+  FailureOr<StringRef> bytes = consumeNBytes(4);
   if (failed(bytes))
     return failure();
-  float result;
-  std::memcpy(&result, bytes->bytes_begin(), 4);
-  return result;
+  return llvm::support::endian::read<float>(bytes->bytes_begin(),
+                                            llvm::endianness::little);
 }
 
 template <>
 FailureOr<double> ParserHead::parseLiteral<double>() {
-  auto bytes = consumeNBytes(8);
+  FailureOr<StringRef> bytes = consumeNBytes(8);
   if (failed(bytes))
     return failure();
-  double result;
-  std::memcpy(&result, bytes->bytes_begin(), 8);
-  return result;
+  return llvm::support::endian::read<double>(bytes->bytes_begin(),
+                                             llvm::endianness::little);
 }
 
 template <>
@@ -650,7 +725,7 @@ parsed_inst_t ValueStack::popOperands(TypeRange operandTypes, Location *opLoc) {
          << "  Current stack size: " << values.size();
   if (operandTypes.size() > values.size())
     return emitError(*opLoc,
-                     "stack doesn't contain enough values. Trying to get ")
+                     "stack doesn't contain enough values. trying to get ")
            << operandTypes.size() << " operands on a stack containing only "
            << values.size() << " values.";
   size_t stackIdxOffset = values.size() - operandTypes.size();
@@ -660,7 +735,7 @@ parsed_inst_t ValueStack::popOperands(TypeRange operandTypes, Location *opLoc) {
     Value operand = values[i + stackIdxOffset];
     Type stackType = operand.getType();
     if (stackType != operandTypes[i])
-      return emitError(*opLoc, "invalid operand type on stack. Expecting ")
+      return emitError(*opLoc, "invalid operand type on stack. expecting ")
              << operandTypes[i] << ", value on stack is of type " << stackType
              << ".";
     LDBG() << "    POP: " << operand;
@@ -718,6 +793,70 @@ ExpressionParser::parse(OpBuilder &builder,
   }
 }
 
+template <>
+inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
+    WasmBinaryEncoding::OpCode::localGet>(OpBuilder &builder) {
+  FailureOr<uint32_t> id = parser.parseLiteral<uint32_t>();
+  Location instLoc = *currentOpLoc;
+  if (failed(id))
+    return failure();
+  if (*id >= locals.size())
+    return emitError(instLoc, "invalid local index. function has ")
+           << locals.size() << " accessible locals, received index " << *id;
+  return {{builder.create<LocalGetOp>(instLoc, locals[*id]).getResult()}};
+}
+
+template <>
+inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
+    WasmBinaryEncoding::OpCode::globalGet>(OpBuilder &builder) {
+  FailureOr<uint32_t> id = parser.parseLiteral<uint32_t>();
+  Location instLoc = *currentOpLoc;
+  if (failed(id))
+    return failure();
+  if (*id >= symbols.globalSymbols.size())
+    return emitError(instLoc, "invalid global index. function has ")
+           << symbols.globalSymbols.size()
+           << " accessible globals, received index " << *id;
+  GlobalSymbolRefContainer globalVar = symbols.globalSymbols[*id];
+  auto globalOp = builder.create<GlobalGetOp>(instLoc, globalVar.globalType,
+                                              globalVar.symbol);
+
+  return {{globalOp.getResult()}};
+}
+
+template <typename OpToCreate>
+parsed_inst_t ExpressionParser::parseSetOrTee(OpBuilder &builder) {
+  FailureOr<uint32_t> id = parser.parseLiteral<uint32_t>();
+  if (failed(id))
+    return failure();
+  if (*id >= locals.size())
+    return emitError(*currentOpLoc, "invalid local index. function has ")
+           << locals.size() << " accessible locals, received index " << *id;
+  if (valueStack.empty())
+    return emitError(
+        *currentOpLoc,
+        "invalid stack access, trying to access a value on an empty stack.");
+
+  parsed_inst_t poppedOp = popOperands(locals[*id].getType().getElementType());
+  if (failed(poppedOp))
+    return failure();
+  return {
+      builder.create<OpToCreate>(*currentOpLoc, locals[*id], poppedOp->front())
+          ->getResults()};
+}
+
+template <>
+inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
+    WasmBinaryEncoding::OpCode::localSet>(OpBuilder &builder) {
+  return parseSetOrTee<LocalSetOp>(builder);
+}
+
+template <>
+inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
+    WasmBinaryEncoding::OpCode::localTee>(OpBuilder &builder) {
+  return parseSetOrTee<LocalTeeOp>(builder);
+}
+
 template <typename T>
 inline Type buildLiteralType(OpBuilder &);
 
@@ -810,6 +949,94 @@ inline parsed_inst_t ExpressionParser::parseSpecificInstruction<
   return parseConstInst<double>(builder);
 }
 
+template <typename opcode, typename valueType, unsigned int numOperands>
+inline parsed_inst_t ExpressionParser::buildNumericOp(
+    OpBuilder &builder, std::enable_if_t<std::is_arithmetic_v<valueType>> *) {
+  auto ty = buildLiteralType<valueType>(builder);
+  LDBG() << "*** buildNumericOp: numOperands = " << numOperands
+         << ", type = " << ty << " ***";
+  auto tysToPop = SmallVector<Type, numOperands>();
+  tysToPop.resize(numOperands);
+  std::fill(tysToPop.begin(), tysToPop.end(), ty);
+  auto operands = popOperands(tysToPop);
+  if (failed(operands))
+    return failure();
+  auto op = builder.create<opcode>(*currentOpLoc, *operands).getResult();
+  LDBG() << "Built operation: " << op;
+  return {{op}};
+}
+
+// Convenience macro for generating numerical operations.
+#define BUILD_NUMERIC_OP(OP_NAME, N_ARGS, PREFIX, SUFFIX, TYPE)                \
+  template <>                                                                  \
+  inline parsed_inst_t ExpressionParser::parseSpecificInstruction<             \
+      WasmBinaryEncoding::OpCode::PREFIX##SUFFIX>(OpBuilder & builder) {       \
+    return buildNumericOp<OP_NAME, TYPE, N_ARGS>(builder);                     \
+  }
+
+// Macro to define binops that only support integer types.
+#define BUILD_NUMERIC_BINOP_INT(OP_NAME, PREFIX)                               \
+  BUILD_NUMERIC_OP(OP_NAME, 2, PREFIX, I32, int32_t)                           \
+  BUILD_NUMERIC_OP(OP_NAME, 2, PREFIX, I64, int64_t)
+
+// Macro to define binops that only support floating point types.
+#define BUILD_NUMERIC_BINOP_FP(OP_NAME, PREFIX)                                \
+  BUILD_NUMERIC_OP(OP_NAME, 2, PREFIX, F32, float)                             \
+  BUILD_NUMERIC_OP(OP_NAME, 2, PREFIX, F64, double)
+
+// Macro to define binops that support both floating point and integer types.
+#define BUILD_NUMERIC_BINOP_INTFP(OP_NAME, PREFIX)                             \
+  BUILD_NUMERIC_BINOP_INT(OP_NAME, PREFIX)                                     \
+  BUILD_NUMERIC_BINOP_FP(OP_NAME, PREFIX)
+
+// Macro to implement unary ops that only support integers.
+#define BUILD_NUMERIC_UNARY_OP_INT(OP_NAME, PREFIX)                            \
+  BUILD_NUMERIC_OP(OP_NAME, 1, PREFIX, I32, int32_t)                           \
+  BUILD_NUMERIC_OP(OP_NAME, 1, PREFIX, I64, int64_t)
+
+// Macro to implement unary ops that support integer and floating point types.
+#define BUILD_NUMERIC_UNARY_OP_FP(OP_NAME, PREFIX)                             \
+  BUILD_NUMERIC_OP(OP_NAME, 1, PREFIX, F32, float)                             \
+  BUILD_NUMERIC_OP(OP_NAME, 1, PREFIX, F64, double)
+
+BUILD_NUMERIC_BINOP_FP(CopySignOp, copysign)
+BUILD_NUMERIC_BINOP_FP(DivOp, div)
+BUILD_NUMERIC_BINOP_FP(MaxOp, max)
+BUILD_NUMERIC_BINOP_FP(MinOp, min)
+BUILD_NUMERIC_BINOP_INT(AndOp, and)
+BUILD_NUMERIC_BINOP_INT(DivSIOp, divS)
+BUILD_NUMERIC_BINOP_INT(DivUIOp, divU)
+BUILD_NUMERIC_BINOP_INT(OrOp, or)
+BUILD_NUMERIC_BINOP_INT(RemSIOp, remS)
+BUILD_NUMERIC_BINOP_INT(RemUIOp, remU)
+BUILD_NUMERIC_BINOP_INT(RotlOp, rotl)
+BUILD_NUMERIC_BINOP_INT(RotrOp, rotr)
+BUILD_NUMERIC_BINOP_INT(ShLOp, shl)
+BUILD_NUMERIC_BINOP_INT(ShRSOp, shrS)
+BUILD_NUMERIC_BINOP_INT(ShRUOp, shrU)
+BUILD_NUMERIC_BINOP_INT(XOrOp, xor)
+BUILD_NUMERIC_BINOP_INTFP(AddOp, add)
+BUILD_NUMERIC_BINOP_INTFP(MulOp, mul)
+BUILD_NUMERIC_BINOP_INTFP(SubOp, sub)
+BUILD_NUMERIC_UNARY_OP_FP(AbsOp, abs)
+BUILD_NUMERIC_UNARY_OP_FP(CeilOp, ceil)
+BUILD_NUMERIC_UNARY_OP_FP(FloorOp, floor)
+BUILD_NUMERIC_UNARY_OP_FP(NegOp, neg)
+BUILD_NUMERIC_UNARY_OP_FP(SqrtOp, sqrt)
+BUILD_NUMERIC_UNARY_OP_FP(TruncOp, trunc)
+BUILD_NUMERIC_UNARY_OP_INT(ClzOp, clz)
+BUILD_NUMERIC_UNARY_OP_INT(CtzOp, ctz)
+BUILD_NUMERIC_UNARY_OP_INT(PopCntOp, popcnt)
+
+// Don't need these anymore so let's undef them.
+#undef BUILD_NUMERIC_BINOP_FP
+#undef BUILD_NUMERIC_BINOP_INT
+#undef BUILD_NUMERIC_BINOP_INTFP
+#undef BUILD_NUMERIC_UNARY_OP_FP
+#undef BUILD_NUMERIC_UNARY_OP_INT
+#undef BUILD_NUMERIC_OP
+#undef BUILD_NUMERIC_CAST_OP
+
 class WasmBinaryParser {
 private:
   struct SectionRegistry {
@@ -907,7 +1134,7 @@ class WasmBinaryParser {
     if (failed(nElemsParsed))
       return failure();
     uint32_t nElems = *nElemsParsed;
-    LDBG() << "Starting to parse " << nElems << " items for section "
+    LDBG() << "starting to parse " << nElems << " items for section "
            << secName;
     for (size_t i = 0; i < nElems; ++i) {
       if (failed(parseSectionItem<section>(ph, i)))
@@ -1006,7 +1233,7 @@ class WasmBinaryParser {
       return;
     if (version->compare(expectedVersionString)) {
       emitError(versionLoc,
-                "unsupported Wasm version. Only version 1 is supported.");
+                "unsupported Wasm version. only version 1 is supported");
       return;
     }
     LogicalResult fillRegistry = registry.populateFromBody(parser.copy());
@@ -1037,6 +1264,14 @@ class WasmBinaryParser {
     if (failed(parsingMems))
       return;
 
+    LogicalResult parsingGlobals = parseSection<WasmSectionType::GLOBAL>();
+    if (failed(parsingGlobals))
+      return;
+
+    LogicalResult parsingCode = parseSection<WasmSectionType::CODE>();
+    if (failed(parsingCode))
+      return;
+
     LogicalResult parsingExports = parseSection<WasmSectionType::EXPORT>();
     if (failed(parsingExports))
       return;
@@ -1193,10 +1428,9 @@ WasmBinaryParser::parseSectionItem<WasmSectionType::FUNCTION>(ParserHead &ph,
   auto funcOp =
       FuncOp::create(builder, ...
[truncated]

@lforg37 lforg37 changed the title [MLIR][Wasm} Extending Wasm binary to WasmSSA dialect importer [MLIR][Wasm] Extending Wasm binary to WasmSSA dialect importer Aug 20, 2025
@lforg37
Copy link
Contributor Author

lforg37 commented Aug 20, 2025

@joker-eph This should fix the bug of #154053, but I can't test it on big endian machine.

@lforg37 lforg37 force-pushed the lforget.wasm_importer_fix_endianness branch from fdd9957 to 8a603da Compare August 20, 2025 04:15
@joker-eph joker-eph merged commit 95fbc18 into llvm:main Aug 20, 2025
9 checks passed
rupprecht added a commit to rupprecht/llvm-project that referenced this pull request Aug 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants