From 2462064fcde0ed2411a0a5eb041758b66f6f6378 Mon Sep 17 00:00:00 2001 From: Ali Mohammad Pur Date: Mon, 12 Jun 2023 13:04:22 +0330 Subject: [PATCH] LibWasm+LibWeb: Parse and validate all Wasm SIMD instructions --- Meta/Lagom/CMakeLists.txt | 2 +- Tests/LibWasm/CMakeLists.txt | 2 +- Tests/LibWasm/test-wasm.cpp | 15 + .../AbstractMachine/AbstractMachine.cpp | 1 + .../LibWasm/AbstractMachine/AbstractMachine.h | 13 +- .../LibWasm/AbstractMachine/Validator.cpp | 1558 ++++++++++++++++- .../LibWasm/AbstractMachine/Validator.h | 13 +- Userland/Libraries/LibWasm/Constants.h | 1 + Userland/Libraries/LibWasm/Opcode.h | 299 +++- Userland/Libraries/LibWasm/Parser/Parser.cpp | 360 +++- .../Libraries/LibWasm/Printer/Printer.cpp | 252 ++- Userland/Libraries/LibWasm/Types.h | 33 +- .../LibWeb/WebAssembly/WebAssembly.cpp | 3 + 13 files changed, 2474 insertions(+), 78 deletions(-) diff --git a/Meta/Lagom/CMakeLists.txt b/Meta/Lagom/CMakeLists.txt index cad8fbd991..345cc56087 100644 --- a/Meta/Lagom/CMakeLists.txt +++ b/Meta/Lagom/CMakeLists.txt @@ -711,7 +711,7 @@ if (BUILD_LAGOM) add_executable(test-wasm ../../Tests/LibWasm/test-wasm.cpp ../../Userland/Libraries/LibTest/JavaScriptTestRunnerMain.cpp) - target_link_libraries(test-wasm LibCore LibFileSystem LibTest LibWasm LibJS) + target_link_libraries(test-wasm LibCore LibFileSystem LibTest LibWasm LibJS LibCrypto) add_test( NAME WasmParser COMMAND test-wasm --show-progress=false ${CMAKE_CURRENT_BINARY_DIR}/Userland/Libraries/LibWasm/Tests diff --git a/Tests/LibWasm/CMakeLists.txt b/Tests/LibWasm/CMakeLists.txt index 8e393132f3..b6cf817796 100644 --- a/Tests/LibWasm/CMakeLists.txt +++ b/Tests/LibWasm/CMakeLists.txt @@ -1,2 +1,2 @@ -serenity_testjs_test(test-wasm.cpp test-wasm LIBS LibWasm LibJS) +serenity_testjs_test(test-wasm.cpp test-wasm LIBS LibWasm LibJS LibCrypto) install(TARGETS test-wasm RUNTIME DESTINATION bin OPTIONAL) diff --git a/Tests/LibWasm/test-wasm.cpp b/Tests/LibWasm/test-wasm.cpp index fe63f67b2d..fc18fc1227 100644 --- a/Tests/LibWasm/test-wasm.cpp +++ b/Tests/LibWasm/test-wasm.cpp @@ -173,6 +173,7 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::get_export) [&](auto const& value) -> JS::Value { return JS::Value(static_cast(value)); }, [&](i32 value) { return JS::Value(static_cast(value)); }, [&](i64 value) -> JS::Value { return JS::BigInt::create(vm, Crypto::SignedBigInteger { value }); }, + [&](u128 value) -> JS::Value { return JS::BigInt::create(vm, Crypto::SignedBigInteger::import_data(bit_cast(&value), sizeof(value))); }, [&](Wasm::Reference const& reference) -> JS::Value { return reference.ref().visit( [&](const Wasm::Reference::Null&) -> JS::Value { return JS::js_null(); }, @@ -225,6 +226,19 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke) case Wasm::ValueType::Kind::F64: arguments.append(Wasm::Value(static_cast(double_value))); break; + case Wasm::ValueType::Kind::V128: { + if (!argument.is_bigint()) { + if (argument.is_number()) + argument = JS::BigInt::create(vm, Crypto::SignedBigInteger { TRY(argument.to_double(vm)) }); + else + argument = TRY(argument.to_bigint(vm)); + } + + u128 bits; + (void)argument.as_bigint().big_integer().export_data({ bit_cast(&bits), sizeof(bits) }); + arguments.append(Wasm::Value(bits)); + break; + } case Wasm::ValueType::Kind::FunctionReference: arguments.append(Wasm::Value(Wasm::Reference { Wasm::Reference::Func { static_cast(double_value) } })); break; @@ -255,6 +269,7 @@ JS_DEFINE_NATIVE_FUNCTION(WebAssemblyModule::wasm_invoke) [](auto const& value) { return JS::Value(static_cast(value)); }, [](i32 value) { return JS::Value(static_cast(value)); }, [&](i64 value) { return JS::Value(JS::BigInt::create(vm, Crypto::SignedBigInteger { value })); }, + [&](u128 value) { return JS::Value(JS::BigInt::create(vm, Crypto::SignedBigInteger::import_data(bit_cast(&value), sizeof(value)))); }, [](Wasm::Reference const& reference) { return reference.ref().visit( [](const Wasm::Reference::Null&) { return JS::js_null(); }, diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp index 1736a159bb..f11b0277dc 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp @@ -330,6 +330,7 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vectoris_error()) return; diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h index a97c61286b..ed73d6fb8f 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h @@ -12,6 +12,7 @@ #include #include #include +#include #include // NOTE: Special case for Wasm::Result. @@ -74,7 +75,7 @@ public: { } - using AnyValueType = Variant; + using AnyValueType = Variant; explicit Value(AnyValueType value) : m_value(move(value)) { @@ -111,11 +112,20 @@ public: VERIFY(raw_value == 0); m_value = Reference { Reference::Null { ValueType(ValueType::Kind::ExternReference) } }; break; + case ValueType::Kind::V128: + m_value = u128(0ull, bit_cast(raw_value)); + break; default: VERIFY_NOT_REACHED(); } } + template T> + explicit Value(T raw_value) + : m_value(raw_value) + { + } + ALWAYS_INLINE Value(Value const& value) = default; ALWAYS_INLINE Value(Value&& value) = default; ALWAYS_INLINE Value& operator=(Value&& value) = default; @@ -158,6 +168,7 @@ public: [](i64) { return ValueType::Kind::I64; }, [](float) { return ValueType::Kind::F32; }, [](double) { return ValueType::Kind::F64; }, + [](u128) { return ValueType::Kind::V128; }, [&](Reference const& type) { return type.ref().visit( [](Reference::Func const&) { return ValueType::Kind::FunctionReference; }, diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp b/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp index 8918357342..0365b090ed 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp @@ -330,7 +330,7 @@ ErrorOr Validator::validate(Limits const& limits, size_t return {}; } -template +template ErrorOr Validator::validate_instruction(Instruction const& instruction, Stack&, bool&) { return Errors::invalid(DeprecatedString::formatted("instruction opcode (0x{:x}) (missing validation!)", instruction.opcode().value())); @@ -2181,6 +2181,1562 @@ VALIDATE_INSTRUCTION(call_indirect) return {}; } +VALIDATE_INSTRUCTION(v128_load) +{ + TRY(validate(MemoryIndex { 0 })); + + auto& arg = instruction.arguments().get(); + if ((1ull << arg.align) > sizeof(u128)) + return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, sizeof(u128)); + + TRY((stack.take_and_put(ValueType::V128))); + + return {}; +} + +VALIDATE_INSTRUCTION(v128_load8x8_s) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 8; + constexpr auto M = 8; + constexpr auto max_alignment = N * M / 8; + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_load8x8_u) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 8; + constexpr auto M = 8; + constexpr auto max_alignment = N * M / 8; + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_load16x4_s) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 16; + constexpr auto M = 4; + constexpr auto max_alignment = N * M / 8; + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_load16x4_u) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 16; + constexpr auto M = 4; + constexpr auto max_alignment = N * M / 8; + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_load32x2_s) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 32; + constexpr auto M = 2; + constexpr auto max_alignment = N * M / 8; + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_load32x2_u) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 32; + constexpr auto M = 2; + constexpr auto max_alignment = N * M / 8; + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_load8_splat) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 8; + constexpr auto max_alignment = N / 8; + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_load16_splat) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 16; + constexpr auto max_alignment = N / 8; + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_load32_splat) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 32; + constexpr auto max_alignment = N / 8; + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_load64_splat) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 64; + constexpr auto max_alignment = N / 8; + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_store) +{ + TRY(validate(MemoryIndex { 0 })); + + auto& arg = instruction.arguments().get(); + if ((1ull << arg.align) > sizeof(u128)) + return Errors::out_of_bounds("memory op alignment"sv, 1ull << arg.align, 0, sizeof(u128)); + + TRY((stack.take())); + + return {}; +} + +VALIDATE_INSTRUCTION(v128_const) +{ + is_constant = true; + stack.append(ValueType(ValueType::V128)); + return {}; +} + +VALIDATE_INSTRUCTION(i8x16_shuffle) +{ + auto const& arg = instruction.arguments().get(); + for (auto lane : arg.lanes) { + if (lane >= 32) + return Errors::out_of_bounds("shuffle lane"sv, lane, 0, 32); + } + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_swizzle) +{ + return stack.take_and_put(ValueType::V128); +} + +enum class Shape { + I8x16, + I16x8, + I32x4, + I64x2, + F32x4, + F64x2, +}; + +template +static constexpr Wasm::ValueType::Kind unpacked() +{ + switch (shape) { + case Shape::I8x16: + case Shape::I16x8: + case Shape::I32x4: + return Wasm::ValueType::I32; + case Shape::I64x2: + return Wasm::ValueType::I64; + case Shape::F32x4: + return Wasm::ValueType::F32; + case Shape::F64x2: + return Wasm::ValueType::F64; + } +} + +template +static constexpr size_t dimensions() +{ + switch (shape) { + case Shape::I8x16: + return 16; + case Shape::I16x8: + return 8; + case Shape::I32x4: + return 4; + case Shape::I64x2: + return 2; + case Shape::F32x4: + return 4; + case Shape::F64x2: + return 2; + } +} + +VALIDATE_INSTRUCTION(i8x16_splat) +{ + constexpr auto unpacked_shape = unpacked(); + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_splat) +{ + constexpr auto unpacked_shape = unpacked(); + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_splat) +{ + constexpr auto unpacked_shape = unpacked(); + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_splat) +{ + constexpr auto unpacked_shape = unpacked(); + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_splat) +{ + constexpr auto unpacked_shape = unpacked(); + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_splat) +{ + constexpr auto unpacked_shape = unpacked(); + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_extract_lane_s) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto shape = Shape::I8x16; + constexpr auto max_lane = dimensions(); + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("extract lane"sv, arg.lane, 0, max_lane); + return stack.take_and_put(unpacked()); +} + +VALIDATE_INSTRUCTION(i8x16_extract_lane_u) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto shape = Shape::I8x16; + constexpr auto max_lane = dimensions(); + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("extract lane"sv, arg.lane, 0, max_lane); + return stack.take_and_put(unpacked()); +} + +VALIDATE_INSTRUCTION(i8x16_replace_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto shape = Shape::I8x16; + constexpr auto max_lane = dimensions(); + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("extract lane"sv, arg.lane, 0, max_lane); + return stack.take_and_put(), ValueType::V128>(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_extract_lane_s) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto shape = Shape::I16x8; + constexpr auto max_lane = dimensions(); + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("extract lane"sv, arg.lane, 0, max_lane); + return stack.take_and_put(unpacked()); +} + +VALIDATE_INSTRUCTION(i16x8_extract_lane_u) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto shape = Shape::I16x8; + constexpr auto max_lane = dimensions(); + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("extract lane"sv, arg.lane, 0, max_lane); + return stack.take_and_put(unpacked()); +} + +VALIDATE_INSTRUCTION(i16x8_replace_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto shape = Shape::I16x8; + constexpr auto max_lane = dimensions(); + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("extract lane"sv, arg.lane, 0, max_lane); + return stack.take_and_put(), ValueType::V128>(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_extract_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto shape = Shape::I32x4; + constexpr auto max_lane = dimensions(); + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("extract lane"sv, arg.lane, 0, max_lane); + return stack.take_and_put(unpacked()); +} + +VALIDATE_INSTRUCTION(i32x4_replace_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto shape = Shape::I32x4; + constexpr auto max_lane = dimensions(); + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("extract lane"sv, arg.lane, 0, max_lane); + return stack.take_and_put(), ValueType::V128>(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_extract_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto shape = Shape::I64x2; + constexpr auto max_lane = dimensions(); + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("extract lane"sv, arg.lane, 0, max_lane); + return stack.take_and_put(unpacked()); +} + +VALIDATE_INSTRUCTION(i64x2_replace_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto shape = Shape::I64x2; + constexpr auto max_lane = dimensions(); + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("extract lane"sv, arg.lane, 0, max_lane); + return stack.take_and_put(), ValueType::V128>(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_extract_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto shape = Shape::F32x4; + constexpr auto max_lane = dimensions(); + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("extract lane"sv, arg.lane, 0, max_lane); + return stack.take_and_put(unpacked()); +} + +VALIDATE_INSTRUCTION(f32x4_replace_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto shape = Shape::F32x4; + constexpr auto max_lane = dimensions(); + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("extract lane"sv, arg.lane, 0, max_lane); + return stack.take_and_put(), ValueType::V128>(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_extract_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto shape = Shape::F64x2; + constexpr auto max_lane = dimensions(); + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("extract lane"sv, arg.lane, 0, max_lane); + return stack.take_and_put(unpacked()); +} + +VALIDATE_INSTRUCTION(f64x2_replace_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto shape = Shape::F64x2; + constexpr auto max_lane = dimensions(); + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("extract lane"sv, arg.lane, 0, max_lane); + return stack.take_and_put(), ValueType::V128>(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_eq) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_ne) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_lt_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_lt_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_gt_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_gt_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_le_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_le_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_ge_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_ge_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_eq) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_ne) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_lt_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_lt_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_gt_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_gt_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_le_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_le_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_ge_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_ge_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_eq) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_ne) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_lt_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_lt_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_gt_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_gt_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_le_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_le_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_ge_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_ge_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_eq) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_ne) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_lt) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_gt) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_le) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_ge) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_eq) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_ne) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_lt) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_gt) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_le) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_ge) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_not) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_and) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_andnot) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_or) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_xor) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_bitselect) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_any_true) +{ + return stack.take_and_put(ValueType::I32); +} + +VALIDATE_INSTRUCTION(v128_load8_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 8; + constexpr auto max_lane = 128 / N; + constexpr auto max_alignment = N / 8; + + if (arg.lane > max_lane) + return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.memory.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_load16_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 16; + constexpr auto max_lane = 128 / N; + constexpr auto max_alignment = N / 8; + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.memory.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_load32_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 32; + constexpr auto max_lane = 128 / N; + constexpr auto max_alignment = N / 8; + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.memory.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_load64_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 64; + constexpr auto max_lane = 128 / N; + constexpr auto max_alignment = N / 8; + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); + + TRY(validate(MemoryIndex { 0 })); + + if (arg.memory.align > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_store8_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 8; + constexpr auto max_lane = 128 / N; + constexpr auto max_alignment = N / 8; + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.memory.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_store16_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 16; + constexpr auto max_lane = 128 / N; + constexpr auto max_alignment = N / 8; + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.memory.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_store32_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 32; + constexpr auto max_lane = 128 / N; + constexpr auto max_alignment = N / 8; + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.memory.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_store64_lane) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 64; + constexpr auto max_lane = 128 / N; + constexpr auto max_alignment = N / 8; + + if (arg.lane >= max_lane) + return Errors::out_of_bounds("lane index"sv, arg.lane, 0u, max_lane); + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.memory.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.memory.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_load32_zero) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 32; + constexpr auto max_alignment = N / 8; + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(v128_load64_zero) +{ + auto const& arg = instruction.arguments().get(); + constexpr auto N = 64; + constexpr auto max_alignment = N / 8; + + TRY(validate(MemoryIndex { 0 })); + + if ((1 << arg.align) > max_alignment) + return Errors::out_of_bounds("memory op alignment"sv, 1 << arg.align, 0u, max_alignment); + + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_demote_f64x2_zero) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_promote_low_f32x4) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_abs) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_neg) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_popcnt) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_all_true) +{ + return stack.take_and_put(ValueType::I32); +} + +VALIDATE_INSTRUCTION(i8x16_bitmask) +{ + return stack.take_and_put(ValueType::I32); +} + +VALIDATE_INSTRUCTION(i8x16_narrow_i16x8_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_narrow_i16x8_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_ceil) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_floor) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_trunc) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_nearest) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_shl) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_shr_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_shr_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_add) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_add_sat_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_add_sat_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_sub) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_sub_sat_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_sub_sat_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_ceil) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_floor) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_min_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_min_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_max_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_max_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_trunc) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i8x16_avgr_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_extadd_pairwise_i8x16_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_extadd_pairwise_i8x16_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_extadd_pairwise_i16x8_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_extadd_pairwise_i16x8_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_abs) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_neg) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_q15mulr_sat_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_all_true) +{ + return stack.take_and_put(ValueType::I32); +} + +VALIDATE_INSTRUCTION(i16x8_bitmask) +{ + return stack.take_and_put(ValueType::I32); +} + +VALIDATE_INSTRUCTION(i16x8_narrow_i32x4_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_narrow_i32x4_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_extend_low_i8x16_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_extend_high_i8x16_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_extend_low_i8x16_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_extend_high_i8x16_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_shl) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_shr_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_shr_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_add) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_add_sat_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_add_sat_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_sub) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_sub_sat_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_sub_sat_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_nearest) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_mul) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_min_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_min_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_max_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_max_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_avgr_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_extmul_low_i8x16_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_extmul_high_i8x16_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_extmul_low_i8x16_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i16x8_extmul_high_i8x16_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_abs) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_neg) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_all_true) +{ + return stack.take_and_put(ValueType::I32); +} + +VALIDATE_INSTRUCTION(i32x4_bitmask) +{ + return stack.take_and_put(ValueType::I32); +} + +VALIDATE_INSTRUCTION(i32x4_extend_low_i16x8_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_extend_high_i16x8_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_extend_low_i16x8_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_extend_high_i16x8_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_shl) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_shr_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_shr_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_add) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_sub) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_mul) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_min_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_min_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_max_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_max_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_dot_i16x8_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_extmul_low_i16x8_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_extmul_high_i16x8_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_extmul_low_i16x8_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_extmul_high_i16x8_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_abs) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_neg) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_all_true) +{ + return stack.take_and_put(ValueType::I32); +} + +VALIDATE_INSTRUCTION(i64x2_bitmask) +{ + return stack.take_and_put(ValueType::I32); +} + +VALIDATE_INSTRUCTION(i64x2_extend_low_i32x4_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_extend_high_i32x4_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_extend_low_i32x4_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_extend_high_i32x4_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_shl) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_shr_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_shr_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_add) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_sub) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_mul) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_eq) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_ne) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_lt_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_gt_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_le_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_ge_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_extmul_low_i32x4_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_extmul_high_i32x4_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_extmul_low_i32x4_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i64x2_extmul_high_i32x4_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_abs) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_neg) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_sqrt) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_add) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_sub) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_mul) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_div) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_min) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_max) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_pmin) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_pmax) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_abs) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_neg) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_sqrt) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_add) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_sub) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_mul) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_div) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_min) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_max) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_pmin) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_pmax) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_trunc_sat_f32x4_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_trunc_sat_f32x4_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_convert_i32x4_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f32x4_convert_i32x4_u) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_trunc_sat_f64x2_s_zero) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(i32x4_trunc_sat_f64x2_u_zero) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_convert_low_i32x4_s) +{ + return stack.take_and_put(ValueType::V128); +} + +VALIDATE_INSTRUCTION(f64x2_convert_low_i32x4_u) +{ + return stack.take_and_put(ValueType::V128); +} + ErrorOr Validator::validate(Instruction const& instruction, Stack& stack, bool& is_constant) { switch (instruction.opcode().value()) { diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Validator.h b/Userland/Libraries/LibWasm/AbstractMachine/Validator.h index fd9c1fca8f..ad3710c398 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Validator.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/Validator.h @@ -221,6 +221,17 @@ public: return result; } + template + ErrorOr take_and_put(Wasm::ValueType::Kind kind, SourceLocation location = SourceLocation::current()) + { + ErrorOr result; + if (((result = take(Wasm::ValueType(kinds), location)).is_error(), ...)) { + return result; + } + append(Wasm::ValueType(kind)); + return result; + } + size_t actual_size() const { return Vector::size(); } size_t size() const { return m_did_insert_unknown_entry ? static_cast(-1) : actual_size(); } @@ -238,7 +249,7 @@ public: }; ErrorOr validate(Expression const&, Vector const&); ErrorOr validate(Instruction const& instruction, Stack& stack, bool& is_constant); - template + template ErrorOr validate_instruction(Instruction const&, Stack& stack, bool& is_constant); // Types diff --git a/Userland/Libraries/LibWasm/Constants.h b/Userland/Libraries/LibWasm/Constants.h index 5e2aaf58fb..3323a7ec26 100644 --- a/Userland/Libraries/LibWasm/Constants.h +++ b/Userland/Libraries/LibWasm/Constants.h @@ -15,6 +15,7 @@ static constexpr auto i32_tag = 0x7f; static constexpr auto i64_tag = 0x7e; static constexpr auto f32_tag = 0x7d; static constexpr auto f64_tag = 0x7c; +static constexpr auto v128_tag = 0x7b; static constexpr auto function_reference_tag = 0x70; static constexpr auto extern_reference_tag = 0x6f; diff --git a/Userland/Libraries/LibWasm/Opcode.h b/Userland/Libraries/LibWasm/Opcode.h index 0dda2b7f44..8381f11b04 100644 --- a/Userland/Libraries/LibWasm/Opcode.h +++ b/Userland/Libraries/LibWasm/Opcode.h @@ -10,7 +10,7 @@ namespace Wasm { -AK_TYPEDEF_DISTINCT_ORDERED_ID(u32, OpCode); +AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, OpCode); namespace Instructions { @@ -198,27 +198,263 @@ namespace Instructions { M(ref_func, 0xd2) // These are synthetic opcodes, they are _not_ seen in wasm with these values. -#define ENUMERATE_MULTI_BYTE_WASM_OPCODES(M) \ - M(i32_trunc_sat_f32_s, 0xfc00) \ - M(i32_trunc_sat_f32_u, 0xfc01) \ - M(i32_trunc_sat_f64_s, 0xfc02) \ - M(i32_trunc_sat_f64_u, 0xfc03) \ - M(i64_trunc_sat_f32_s, 0xfc04) \ - M(i64_trunc_sat_f32_u, 0xfc05) \ - M(i64_trunc_sat_f64_s, 0xfc06) \ - M(i64_trunc_sat_f64_u, 0xfc07) \ - M(memory_init, 0xfc08) \ - M(data_drop, 0xfc09) \ - M(memory_copy, 0xfc0a) \ - M(memory_fill, 0x0fc0b) \ - M(table_init, 0xfc0c) \ - M(elem_drop, 0xfc0d) \ - M(table_copy, 0xfc0e) \ - M(table_grow, 0xfc0f) \ - M(table_size, 0xfc10) \ - M(table_fill, 0xfc11) \ - M(structured_else, 0xff00) \ - M(structured_end, 0xff01) +#define ENUMERATE_MULTI_BYTE_WASM_OPCODES(M) \ + M(i32_trunc_sat_f32_s, 0xfc00000000000000ull) \ + M(i32_trunc_sat_f32_u, 0xfc00000000000001ull) \ + M(i32_trunc_sat_f64_s, 0xfc00000000000002ull) \ + M(i32_trunc_sat_f64_u, 0xfc00000000000003ull) \ + M(i64_trunc_sat_f32_s, 0xfc00000000000004ull) \ + M(i64_trunc_sat_f32_u, 0xfc00000000000005ull) \ + M(i64_trunc_sat_f64_s, 0xfc00000000000006ull) \ + M(i64_trunc_sat_f64_u, 0xfc00000000000007ull) \ + M(memory_init, 0xfc00000000000008ull) \ + M(data_drop, 0xfc00000000000009ull) \ + M(memory_copy, 0xfc0000000000000aull) \ + M(memory_fill, 0xfc0000000000000bull) \ + M(table_init, 0xfc0000000000000cull) \ + M(elem_drop, 0xfc0000000000000dull) \ + M(table_copy, 0xfc0000000000000eull) \ + M(table_grow, 0xfc0000000000000full) \ + M(table_size, 0xfc00000000000010ull) \ + M(table_fill, 0xfc00000000000011ull) \ + M(structured_else, 0xff00000000000000ull) \ + M(structured_end, 0xff00000000000001ull) \ + M(v128_load, 0xfd00000000000000ull) \ + M(v128_load8x8_s, 0xfd00000000000001ull) \ + M(v128_load8x8_u, 0xfd00000000000002ull) \ + M(v128_load16x4_s, 0xfd00000000000003ull) \ + M(v128_load16x4_u, 0xfd00000000000004ull) \ + M(v128_load32x2_s, 0xfd00000000000005ull) \ + M(v128_load32x2_u, 0xfd00000000000006ull) \ + M(v128_load8_splat, 0xfd00000000000007ull) \ + M(v128_load16_splat, 0xfd00000000000008ull) \ + M(v128_load32_splat, 0xfd00000000000009ull) \ + M(v128_load64_splat, 0xfd0000000000000aull) \ + M(v128_store, 0xfd0000000000000bull) \ + M(v128_const, 0xfd0000000000000cull) \ + M(i8x16_shuffle, 0xfd0000000000000dull) \ + M(i8x16_swizzle, 0xfd0000000000000eull) \ + M(i8x16_splat, 0xfd0000000000000full) \ + M(i16x8_splat, 0xfd00000000000010ull) \ + M(i32x4_splat, 0xfd00000000000011ull) \ + M(i64x2_splat, 0xfd00000000000012ull) \ + M(f32x4_splat, 0xfd00000000000013ull) \ + M(f64x2_splat, 0xfd00000000000014ull) \ + M(i8x16_extract_lane_s, 0xfd00000000000015ull) \ + M(i8x16_extract_lane_u, 0xfd00000000000016ull) \ + M(i8x16_replace_lane, 0xfd00000000000017ull) \ + M(i16x8_extract_lane_s, 0xfd00000000000018ull) \ + M(i16x8_extract_lane_u, 0xfd00000000000019ull) \ + M(i16x8_replace_lane, 0xfd0000000000001aull) \ + M(i32x4_extract_lane, 0xfd0000000000001bull) \ + M(i32x4_replace_lane, 0xfd0000000000001cull) \ + M(i64x2_extract_lane, 0xfd0000000000001dull) \ + M(i64x2_replace_lane, 0xfd0000000000001eull) \ + M(f32x4_extract_lane, 0xfd0000000000001full) \ + M(f32x4_replace_lane, 0xfd00000000000020ull) \ + M(f64x2_extract_lane, 0xfd00000000000021ull) \ + M(f64x2_replace_lane, 0xfd00000000000022ull) \ + M(i8x16_eq, 0xfd00000000000023ull) \ + M(i8x16_ne, 0xfd00000000000024ull) \ + M(i8x16_lt_s, 0xfd00000000000025ull) \ + M(i8x16_lt_u, 0xfd00000000000026ull) \ + M(i8x16_gt_s, 0xfd00000000000027ull) \ + M(i8x16_gt_u, 0xfd00000000000028ull) \ + M(i8x16_le_s, 0xfd00000000000029ull) \ + M(i8x16_le_u, 0xfd0000000000002aull) \ + M(i8x16_ge_s, 0xfd0000000000002bull) \ + M(i8x16_ge_u, 0xfd0000000000002cull) \ + M(i16x8_eq, 0xfd0000000000002dull) \ + M(i16x8_ne, 0xfd0000000000002eull) \ + M(i16x8_lt_s, 0xfd0000000000002full) \ + M(i16x8_lt_u, 0xfd00000000000030ull) \ + M(i16x8_gt_s, 0xfd00000000000031ull) \ + M(i16x8_gt_u, 0xfd00000000000032ull) \ + M(i16x8_le_s, 0xfd00000000000033ull) \ + M(i16x8_le_u, 0xfd00000000000034ull) \ + M(i16x8_ge_s, 0xfd00000000000035ull) \ + M(i16x8_ge_u, 0xfd00000000000036ull) \ + M(i32x4_eq, 0xfd00000000000037ull) \ + M(i32x4_ne, 0xfd00000000000038ull) \ + M(i32x4_lt_s, 0xfd00000000000039ull) \ + M(i32x4_lt_u, 0xfd0000000000003aull) \ + M(i32x4_gt_s, 0xfd0000000000003bull) \ + M(i32x4_gt_u, 0xfd0000000000003cull) \ + M(i32x4_le_s, 0xfd0000000000003dull) \ + M(i32x4_le_u, 0xfd0000000000003eull) \ + M(i32x4_ge_s, 0xfd0000000000003full) \ + M(i32x4_ge_u, 0xfd00000000000040ull) \ + M(f32x4_eq, 0xfd00000000000041ull) \ + M(f32x4_ne, 0xfd00000000000042ull) \ + M(f32x4_lt, 0xfd00000000000043ull) \ + M(f32x4_gt, 0xfd00000000000044ull) \ + M(f32x4_le, 0xfd00000000000045ull) \ + M(f32x4_ge, 0xfd00000000000046ull) \ + M(f64x2_eq, 0xfd00000000000047ull) \ + M(f64x2_ne, 0xfd00000000000048ull) \ + M(f64x2_lt, 0xfd00000000000049ull) \ + M(f64x2_gt, 0xfd0000000000004aull) \ + M(f64x2_le, 0xfd0000000000004bull) \ + M(f64x2_ge, 0xfd0000000000004cull) \ + M(v128_not, 0xfd0000000000004dull) \ + M(v128_and, 0xfd0000000000004eull) \ + M(v128_andnot, 0xfd0000000000004full) \ + M(v128_or, 0xfd00000000000050ull) \ + M(v128_xor, 0xfd00000000000051ull) \ + M(v128_bitselect, 0xfd00000000000052ull) \ + M(v128_any_true, 0xfd00000000000053ull) \ + M(v128_load8_lane, 0xfd00000000000054ull) \ + M(v128_load16_lane, 0xfd00000000000055ull) \ + M(v128_load32_lane, 0xfd00000000000056ull) \ + M(v128_load64_lane, 0xfd00000000000057ull) \ + M(v128_store8_lane, 0xfd00000000000058ull) \ + M(v128_store16_lane, 0xfd00000000000059ull) \ + M(v128_store32_lane, 0xfd0000000000005aull) \ + M(v128_store64_lane, 0xfd0000000000005bull) \ + M(v128_load32_zero, 0xfd0000000000005cull) \ + M(v128_load64_zero, 0xfd0000000000005dull) \ + M(f32x4_demote_f64x2_zero, 0xfd0000000000005eull) \ + M(f64x2_promote_low_f32x4, 0xfd0000000000005full) \ + M(i8x16_abs, 0xfd00000000000060ull) \ + M(i8x16_neg, 0xfd00000000000061ull) \ + M(i8x16_popcnt, 0xfd00000000000062ull) \ + M(i8x16_all_true, 0xfd00000000000063ull) \ + M(i8x16_bitmask, 0xfd00000000000064ull) \ + M(i8x16_narrow_i16x8_s, 0xfd00000000000065ull) \ + M(i8x16_narrow_i16x8_u, 0xfd00000000000066ull) \ + M(f32x4_ceil, 0xfd00000000000067ull) \ + M(f32x4_floor, 0xfd00000000000068ull) \ + M(f32x4_trunc, 0xfd00000000000069ull) \ + M(f32x4_nearest, 0xfd0000000000006aull) \ + M(i8x16_shl, 0xfd0000000000006bull) \ + M(i8x16_shr_s, 0xfd0000000000006cull) \ + M(i8x16_shr_u, 0xfd0000000000006dull) \ + M(i8x16_add, 0xfd0000000000006eull) \ + M(i8x16_add_sat_s, 0xfd0000000000006full) \ + M(i8x16_add_sat_u, 0xfd00000000000070ull) \ + M(i8x16_sub, 0xfd00000000000071ull) \ + M(i8x16_sub_sat_s, 0xfd00000000000072ull) \ + M(i8x16_sub_sat_u, 0xfd00000000000073ull) \ + M(f64x2_ceil, 0xfd00000000000074ull) \ + M(f64x2_floor, 0xfd00000000000075ull) \ + M(i8x16_min_s, 0xfd00000000000076ull) \ + M(i8x16_min_u, 0xfd00000000000077ull) \ + M(i8x16_max_s, 0xfd00000000000078ull) \ + M(i8x16_max_u, 0xfd00000000000079ull) \ + M(f64x2_trunc, 0xfd0000000000007aull) \ + M(i8x16_avgr_u, 0xfd0000000000007bull) \ + M(i16x8_extadd_pairwise_i8x16_s, 0xfd0000000000007cull) \ + M(i16x8_extadd_pairwise_i8x16_u, 0xfd0000000000007dull) \ + M(i32x4_extadd_pairwise_i16x8_s, 0xfd0000000000007eull) \ + M(i32x4_extadd_pairwise_i16x8_u, 0xfd0000000000007full) \ + M(i16x8_abs, 0xfd00000000000080ull) \ + M(i16x8_neg, 0xfd00000000000081ull) \ + M(i16x8_q15mulr_sat_s, 0xfd00000000000082ull) \ + M(i16x8_all_true, 0xfd00000000000083ull) \ + M(i16x8_bitmask, 0xfd00000000000084ull) \ + M(i16x8_narrow_i32x4_s, 0xfd00000000000085ull) \ + M(i16x8_narrow_i32x4_u, 0xfd00000000000086ull) \ + M(i16x8_extend_low_i8x16_s, 0xfd00000000000087ull) \ + M(i16x8_extend_high_i8x16_s, 0xfd00000000000088ull) \ + M(i16x8_extend_low_i8x16_u, 0xfd00000000000089ull) \ + M(i16x8_extend_high_i8x16_u, 0xfd0000000000008aull) \ + M(i16x8_shl, 0xfd0000000000008bull) \ + M(i16x8_shr_s, 0xfd0000000000008cull) \ + M(i16x8_shr_u, 0xfd0000000000008dull) \ + M(i16x8_add, 0xfd0000000000008eull) \ + M(i16x8_add_sat_s, 0xfd0000000000008full) \ + M(i16x8_add_sat_u, 0xfd00000000000090ull) \ + M(i16x8_sub, 0xfd00000000000091ull) \ + M(i16x8_sub_sat_s, 0xfd00000000000092ull) \ + M(i16x8_sub_sat_u, 0xfd00000000000093ull) \ + M(f64x2_nearest, 0xfd00000000000094ull) \ + M(i16x8_mul, 0xfd00000000000095ull) \ + M(i16x8_min_s, 0xfd00000000000096ull) \ + M(i16x8_min_u, 0xfd00000000000097ull) \ + M(i16x8_max_s, 0xfd00000000000098ull) \ + M(i16x8_max_u, 0xfd00000000000099ull) \ + M(i16x8_avgr_u, 0xfd0000000000009bull) \ + M(i16x8_extmul_low_i8x16_s, 0xfd0000000000009cull) \ + M(i16x8_extmul_high_i8x16_s, 0xfd0000000000009dull) \ + M(i16x8_extmul_low_i8x16_u, 0xfd0000000000009eull) \ + M(i16x8_extmul_high_i8x16_u, 0xfd0000000000009full) \ + M(i32x4_abs, 0xfd000000000000a0ull) \ + M(i32x4_neg, 0xfd000000000000a1ull) \ + M(i32x4_all_true, 0xfd000000000000a3ull) \ + M(i32x4_bitmask, 0xfd000000000000a4ull) \ + M(i32x4_extend_low_i16x8_s, 0xfd000000000000a7ull) \ + M(i32x4_extend_high_i16x8_s, 0xfd000000000000a8ull) \ + M(i32x4_extend_low_i16x8_u, 0xfd000000000000a9ull) \ + M(i32x4_extend_high_i16x8_u, 0xfd000000000000aaull) \ + M(i32x4_shl, 0xfd000000000000abull) \ + M(i32x4_shr_s, 0xfd000000000000acull) \ + M(i32x4_shr_u, 0xfd000000000000adull) \ + M(i32x4_add, 0xfd000000000000aeull) \ + M(i32x4_sub, 0xfd000000000000b1ull) \ + M(i32x4_mul, 0xfd000000000000b5ull) \ + M(i32x4_min_s, 0xfd000000000000b6ull) \ + M(i32x4_min_u, 0xfd000000000000b7ull) \ + M(i32x4_max_s, 0xfd000000000000b8ull) \ + M(i32x4_max_u, 0xfd000000000000b9ull) \ + M(i32x4_dot_i16x8_s, 0xfd000000000000baull) \ + M(i32x4_extmul_low_i16x8_s, 0xfd000000000000bcull) \ + M(i32x4_extmul_high_i16x8_s, 0xfd000000000000bdull) \ + M(i32x4_extmul_low_i16x8_u, 0xfd000000000000beull) \ + M(i32x4_extmul_high_i16x8_u, 0xfd000000000000bfull) \ + M(i64x2_abs, 0xfd000000000000c0ull) \ + M(i64x2_neg, 0xfd000000000000c1ull) \ + M(i64x2_all_true, 0xfd000000000000c3ull) \ + M(i64x2_bitmask, 0xfd000000000000c4ull) \ + M(i64x2_extend_low_i32x4_s, 0xfd000000000000c7ull) \ + M(i64x2_extend_high_i32x4_s, 0xfd000000000000c8ull) \ + M(i64x2_extend_low_i32x4_u, 0xfd000000000000c9ull) \ + M(i64x2_extend_high_i32x4_u, 0xfd000000000000caull) \ + M(i64x2_shl, 0xfd000000000000cbull) \ + M(i64x2_shr_s, 0xfd000000000000ccull) \ + M(i64x2_shr_u, 0xfd000000000000cdull) \ + M(i64x2_add, 0xfd000000000000ceull) \ + M(i64x2_sub, 0xfd000000000000d1ull) \ + M(i64x2_mul, 0xfd000000000000d5ull) \ + M(i64x2_eq, 0xfd000000000000d6ull) \ + M(i64x2_ne, 0xfd000000000000d7ull) \ + M(i64x2_lt_s, 0xfd000000000000d8ull) \ + M(i64x2_gt_s, 0xfd000000000000d9ull) \ + M(i64x2_le_s, 0xfd000000000000daull) \ + M(i64x2_ge_s, 0xfd000000000000dbull) \ + M(i64x2_extmul_low_i32x4_s, 0xfd000000000000dcull) \ + M(i64x2_extmul_high_i32x4_s, 0xfd000000000000ddull) \ + M(i64x2_extmul_low_i32x4_u, 0xfd000000000000deull) \ + M(i64x2_extmul_high_i32x4_u, 0xfd000000000000dfull) \ + M(f32x4_abs, 0xfd000000000000e0ull) \ + M(f32x4_neg, 0xfd000000000000e1ull) \ + M(f32x4_sqrt, 0xfd000000000000e3ull) \ + M(f32x4_add, 0xfd000000000000e4ull) \ + M(f32x4_sub, 0xfd000000000000e5ull) \ + M(f32x4_mul, 0xfd000000000000e6ull) \ + M(f32x4_div, 0xfd000000000000e7ull) \ + M(f32x4_min, 0xfd000000000000e8ull) \ + M(f32x4_max, 0xfd000000000000e9ull) \ + M(f32x4_pmin, 0xfd000000000000eaull) \ + M(f32x4_pmax, 0xfd000000000000ebull) \ + M(f64x2_abs, 0xfd000000000000ecull) \ + M(f64x2_neg, 0xfd000000000000edull) \ + M(f64x2_sqrt, 0xfd000000000000efull) \ + M(f64x2_add, 0xfd000000000000f0ull) \ + M(f64x2_sub, 0xfd000000000000f1ull) \ + M(f64x2_mul, 0xfd000000000000f2ull) \ + M(f64x2_div, 0xfd000000000000f3ull) \ + M(f64x2_min, 0xfd000000000000f4ull) \ + M(f64x2_max, 0xfd000000000000f5ull) \ + M(f64x2_pmin, 0xfd000000000000f6ull) \ + M(f64x2_pmax, 0xfd000000000000f7ull) \ + M(i32x4_trunc_sat_f32x4_s, 0xfd000000000000f8ull) \ + M(i32x4_trunc_sat_f32x4_u, 0xfd000000000000f9ull) \ + M(f32x4_convert_i32x4_s, 0xfd000000000000faull) \ + M(f32x4_convert_i32x4_u, 0xfd000000000000fbull) \ + M(i32x4_trunc_sat_f64x2_s_zero, 0xfd000000000000fcull) \ + M(i32x4_trunc_sat_f64x2_u_zero, 0xfd000000000000fdull) \ + M(f64x2_convert_low_i32x4_s, 0xfd000000000000feull) \ + M(f64x2_convert_low_i32x4_u, 0xfd000000000000ffull) #define ENUMERATE_WASM_OPCODES(M) \ ENUMERATE_SINGLE_BYTE_WASM_OPCODES(M) \ @@ -228,25 +464,6 @@ namespace Instructions { ENUMERATE_WASM_OPCODES(M) #undef M -static constexpr u32 i32_trunc_sat_f32_s_second = 0, - i32_trunc_sat_f32_u_second = 1, - i32_trunc_sat_f64_s_second = 2, - i32_trunc_sat_f64_u_second = 3, - i64_trunc_sat_f32_s_second = 4, - i64_trunc_sat_f32_u_second = 5, - i64_trunc_sat_f64_s_second = 6, - i64_trunc_sat_f64_u_second = 7, - memory_init_second = 8, - data_drop_second = 9, - memory_copy_second = 10, - memory_fill_second = 11, - table_init_second = 12, - elem_drop_second = 13, - table_copy_second = 14, - table_grow_second = 15, - table_size_second = 16, - table_fill_second = 17; - } } diff --git a/Userland/Libraries/LibWasm/Parser/Parser.cpp b/Userland/Libraries/LibWasm/Parser/Parser.cpp index 2a1292a8bb..17efb8eadd 100644 --- a/Userland/Libraries/LibWasm/Parser/Parser.cpp +++ b/Userland/Libraries/LibWasm/Parser/Parser.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace Wasm { @@ -138,6 +139,8 @@ ParseResult ValueType::parse(Stream& stream) return ValueType(F32); case Constants::f64_tag: return ValueType(F64); + case Constants::v128_tag: + return ValueType(V128); case Constants::function_reference_tag: return ValueType(FunctionReference); case Constants::extern_reference_tag: @@ -677,24 +680,27 @@ ParseResult> Instruction::parse(Stream& stream, InstructionP case Instructions::i64_extend32_s.value(): resulting_instructions.append(Instruction { opcode }); break; - case 0xfc: { + case 0xfc: + case 0xfd: { // These are multibyte instructions. auto selector_or_error = stream.read_value>(); if (selector_or_error.is_error()) return with_eof_check(stream, ParseError::InvalidInput); u32 selector = selector_or_error.release_value(); - switch (selector) { - case Instructions::i32_trunc_sat_f32_s_second: - case Instructions::i32_trunc_sat_f32_u_second: - case Instructions::i32_trunc_sat_f64_s_second: - case Instructions::i32_trunc_sat_f64_u_second: - case Instructions::i64_trunc_sat_f32_s_second: - case Instructions::i64_trunc_sat_f32_u_second: - case Instructions::i64_trunc_sat_f64_s_second: - case Instructions::i64_trunc_sat_f64_u_second: - resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector } }); + OpCode full_opcode = static_cast(opcode.value()) << 56 | selector; + + switch (full_opcode.value()) { + case Instructions::i32_trunc_sat_f32_s.value(): + case Instructions::i32_trunc_sat_f32_u.value(): + case Instructions::i32_trunc_sat_f64_s.value(): + case Instructions::i32_trunc_sat_f64_u.value(): + case Instructions::i64_trunc_sat_f32_s.value(): + case Instructions::i64_trunc_sat_f32_u.value(): + case Instructions::i64_trunc_sat_f64_s.value(): + case Instructions::i64_trunc_sat_f64_u.value(): + resulting_instructions.append(Instruction { full_opcode }); break; - case Instructions::memory_init_second: { + case Instructions::memory_init.value(): { auto index = GenericIndexParser::parse(stream); if (index.is_error()) return index.error(); @@ -705,17 +711,17 @@ ParseResult> Instruction::parse(Stream& stream, InstructionP auto unused = unused_or_error.release_value(); if (unused != 0x00) return ParseError::InvalidImmediate; - resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector }, index.release_value() }); + resulting_instructions.append(Instruction { full_opcode, index.release_value() }); break; } - case Instructions::data_drop_second: { + case Instructions::data_drop.value(): { auto index = GenericIndexParser::parse(stream); if (index.is_error()) return index.error(); - resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector }, index.release_value() }); + resulting_instructions.append(Instruction { full_opcode, index.release_value() }); break; } - case Instructions::memory_copy_second: { + case Instructions::memory_copy.value(): { for (size_t i = 0; i < 2; ++i) { auto unused_or_error = stream.read_value(); if (unused_or_error.is_error()) @@ -725,10 +731,10 @@ ParseResult> Instruction::parse(Stream& stream, InstructionP if (unused != 0x00) return ParseError::InvalidImmediate; } - resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector } }); + resulting_instructions.append(Instruction { full_opcode }); break; } - case Instructions::memory_fill_second: { + case Instructions::memory_fill.value(): { auto unused_or_error = stream.read_value(); if (unused_or_error.is_error()) return with_eof_check(stream, ParseError::InvalidInput); @@ -736,45 +742,341 @@ ParseResult> Instruction::parse(Stream& stream, InstructionP auto unused = unused_or_error.release_value(); if (unused != 0x00) return ParseError::InvalidImmediate; - resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector } }); + resulting_instructions.append(Instruction { full_opcode }); break; } - case Instructions::table_init_second: { + case Instructions::table_init.value(): { auto element_index = GenericIndexParser::parse(stream); if (element_index.is_error()) return element_index.error(); auto table_index = GenericIndexParser::parse(stream); if (table_index.is_error()) return table_index.error(); - resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector }, TableElementArgs { element_index.release_value(), table_index.release_value() } }); + resulting_instructions.append(Instruction { full_opcode, TableElementArgs { element_index.release_value(), table_index.release_value() } }); break; } - case Instructions::elem_drop_second: { + case Instructions::elem_drop.value(): { auto element_index = GenericIndexParser::parse(stream); if (element_index.is_error()) return element_index.error(); - resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector }, element_index.release_value() }); + resulting_instructions.append(Instruction { full_opcode, element_index.release_value() }); break; } - case Instructions::table_copy_second: { + case Instructions::table_copy.value(): { auto lhs = GenericIndexParser::parse(stream); if (lhs.is_error()) return lhs.error(); auto rhs = GenericIndexParser::parse(stream); if (rhs.is_error()) return rhs.error(); - resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector }, TableTableArgs { lhs.release_value(), rhs.release_value() } }); + resulting_instructions.append(Instruction { full_opcode, TableTableArgs { lhs.release_value(), rhs.release_value() } }); break; } - case Instructions::table_grow_second: - case Instructions::table_size_second: - case Instructions::table_fill_second: { + case Instructions::table_grow.value(): + case Instructions::table_size.value(): + case Instructions::table_fill.value(): { auto index = GenericIndexParser::parse(stream); if (index.is_error()) return index.error(); - resulting_instructions.append(Instruction { OpCode { 0xfc00 | selector }, index.release_value() }); + resulting_instructions.append(Instruction { full_opcode, index.release_value() }); break; } + case Instructions::v128_load.value(): + case Instructions::v128_load8x8_s.value(): + case Instructions::v128_load8x8_u.value(): + case Instructions::v128_load16x4_s.value(): + case Instructions::v128_load16x4_u.value(): + case Instructions::v128_load32x2_s.value(): + case Instructions::v128_load32x2_u.value(): + case Instructions::v128_load8_splat.value(): + case Instructions::v128_load16_splat.value(): + case Instructions::v128_load32_splat.value(): + case Instructions::v128_load64_splat.value(): + case Instructions::v128_store.value(): { + // op (align offset) + auto align_or_error = stream.read_value>(); + if (align_or_error.is_error()) + return with_eof_check(stream, ParseError::ExpectedIndex); + size_t align = align_or_error.release_value(); + auto offset_or_error = stream.read_value>(); + if (offset_or_error.is_error()) + return with_eof_check(stream, ParseError::ExpectedIndex); + size_t offset = offset_or_error.release_value(); + + resulting_instructions.append(Instruction { full_opcode, MemoryArgument { static_cast(align), static_cast(offset) } }); + break; + } + case Instructions::v128_load8_lane.value(): + case Instructions::v128_load16_lane.value(): + case Instructions::v128_load32_lane.value(): + case Instructions::v128_load64_lane.value(): + case Instructions::v128_store8_lane.value(): + case Instructions::v128_store16_lane.value(): + case Instructions::v128_store32_lane.value(): + case Instructions::v128_store64_lane.value(): { + // op (align offset) (index) + auto align_or_error = stream.read_value>(); + if (align_or_error.is_error()) + return with_eof_check(stream, ParseError::ExpectedIndex); + size_t align = align_or_error.release_value(); + auto offset_or_error = stream.read_value>(); + if (offset_or_error.is_error()) + return with_eof_check(stream, ParseError::ExpectedIndex); + size_t offset = offset_or_error.release_value(); + + auto index_or_error = stream.read_value(); + if (index_or_error.is_error()) + return with_eof_check(stream, ParseError::InvalidInput); + auto index = index_or_error.release_value(); + + resulting_instructions.append(Instruction { full_opcode, MemoryAndLaneArgument { { static_cast(align), static_cast(offset) }, index } }); + break; + } + case Instructions::v128_const.value(): { + // op (literal:16) + auto value_or_error = stream.read_value>(); + if (value_or_error.is_error()) + return with_eof_check(stream, ParseError::InvalidImmediate); + resulting_instructions.append(Instruction { full_opcode, value_or_error.release_value() }); + break; + } + case Instructions::i8x16_shuffle.value(): { + // op 16x(lane) + u8 lanes[16]; + for (size_t i = 0; i < 16; ++i) { + auto value_or_error = stream.read_value(); + if (value_or_error.is_error()) + return with_eof_check(stream, ParseError::InvalidInput); + lanes[i] = value_or_error.release_value(); + } + resulting_instructions.append(Instruction { full_opcode, ShuffleArgument(lanes) }); + break; + } + case Instructions::i8x16_extract_lane_s.value(): + case Instructions::i8x16_extract_lane_u.value(): + case Instructions::i8x16_replace_lane.value(): + case Instructions::i16x8_extract_lane_s.value(): + case Instructions::i16x8_extract_lane_u.value(): + case Instructions::i16x8_replace_lane.value(): + case Instructions::i32x4_extract_lane.value(): + case Instructions::i32x4_replace_lane.value(): + case Instructions::i64x2_extract_lane.value(): + case Instructions::i64x2_replace_lane.value(): + case Instructions::f32x4_extract_lane.value(): + case Instructions::f32x4_replace_lane.value(): + case Instructions::f64x2_extract_lane.value(): + case Instructions::f64x2_replace_lane.value(): { + // op (lane) + auto lane_or_error = stream.read_value(); + if (lane_or_error.is_error()) + return with_eof_check(stream, ParseError::InvalidInput); + auto lane = lane_or_error.release_value(); + resulting_instructions.append(Instruction { full_opcode, LaneIndex { lane } }); + break; + } + case Instructions::i8x16_swizzle.value(): + case Instructions::i8x16_splat.value(): + case Instructions::i16x8_splat.value(): + case Instructions::i32x4_splat.value(): + case Instructions::i64x2_splat.value(): + case Instructions::f32x4_splat.value(): + case Instructions::f64x2_splat.value(): + case Instructions::i8x16_eq.value(): + case Instructions::i8x16_ne.value(): + case Instructions::i8x16_lt_s.value(): + case Instructions::i8x16_lt_u.value(): + case Instructions::i8x16_gt_s.value(): + case Instructions::i8x16_gt_u.value(): + case Instructions::i8x16_le_s.value(): + case Instructions::i8x16_le_u.value(): + case Instructions::i8x16_ge_s.value(): + case Instructions::i8x16_ge_u.value(): + case Instructions::i16x8_eq.value(): + case Instructions::i16x8_ne.value(): + case Instructions::i16x8_lt_s.value(): + case Instructions::i16x8_lt_u.value(): + case Instructions::i16x8_gt_s.value(): + case Instructions::i16x8_gt_u.value(): + case Instructions::i16x8_le_s.value(): + case Instructions::i16x8_le_u.value(): + case Instructions::i16x8_ge_s.value(): + case Instructions::i16x8_ge_u.value(): + case Instructions::i32x4_eq.value(): + case Instructions::i32x4_ne.value(): + case Instructions::i32x4_lt_s.value(): + case Instructions::i32x4_lt_u.value(): + case Instructions::i32x4_gt_s.value(): + case Instructions::i32x4_gt_u.value(): + case Instructions::i32x4_le_s.value(): + case Instructions::i32x4_le_u.value(): + case Instructions::i32x4_ge_s.value(): + case Instructions::i32x4_ge_u.value(): + case Instructions::f32x4_eq.value(): + case Instructions::f32x4_ne.value(): + case Instructions::f32x4_lt.value(): + case Instructions::f32x4_gt.value(): + case Instructions::f32x4_le.value(): + case Instructions::f32x4_ge.value(): + case Instructions::f64x2_eq.value(): + case Instructions::f64x2_ne.value(): + case Instructions::f64x2_lt.value(): + case Instructions::f64x2_gt.value(): + case Instructions::f64x2_le.value(): + case Instructions::f64x2_ge.value(): + case Instructions::v128_not.value(): + case Instructions::v128_and.value(): + case Instructions::v128_andnot.value(): + case Instructions::v128_or.value(): + case Instructions::v128_xor.value(): + case Instructions::v128_bitselect.value(): + case Instructions::v128_any_true.value(): + case Instructions::v128_load32_zero.value(): + case Instructions::v128_load64_zero.value(): + case Instructions::f32x4_demote_f64x2_zero.value(): + case Instructions::f64x2_promote_low_f32x4.value(): + case Instructions::i8x16_abs.value(): + case Instructions::i8x16_neg.value(): + case Instructions::i8x16_popcnt.value(): + case Instructions::i8x16_all_true.value(): + case Instructions::i8x16_bitmask.value(): + case Instructions::i8x16_narrow_i16x8_s.value(): + case Instructions::i8x16_narrow_i16x8_u.value(): + case Instructions::f32x4_ceil.value(): + case Instructions::f32x4_floor.value(): + case Instructions::f32x4_trunc.value(): + case Instructions::f32x4_nearest.value(): + case Instructions::i8x16_shl.value(): + case Instructions::i8x16_shr_s.value(): + case Instructions::i8x16_shr_u.value(): + case Instructions::i8x16_add.value(): + case Instructions::i8x16_add_sat_s.value(): + case Instructions::i8x16_add_sat_u.value(): + case Instructions::i8x16_sub.value(): + case Instructions::i8x16_sub_sat_s.value(): + case Instructions::i8x16_sub_sat_u.value(): + case Instructions::f64x2_ceil.value(): + case Instructions::f64x2_floor.value(): + case Instructions::i8x16_min_s.value(): + case Instructions::i8x16_min_u.value(): + case Instructions::i8x16_max_s.value(): + case Instructions::i8x16_max_u.value(): + case Instructions::f64x2_trunc.value(): + case Instructions::i8x16_avgr_u.value(): + case Instructions::i16x8_extadd_pairwise_i8x16_s.value(): + case Instructions::i16x8_extadd_pairwise_i8x16_u.value(): + case Instructions::i32x4_extadd_pairwise_i16x8_s.value(): + case Instructions::i32x4_extadd_pairwise_i16x8_u.value(): + case Instructions::i16x8_abs.value(): + case Instructions::i16x8_neg.value(): + case Instructions::i16x8_q15mulr_sat_s.value(): + case Instructions::i16x8_all_true.value(): + case Instructions::i16x8_bitmask.value(): + case Instructions::i16x8_narrow_i32x4_s.value(): + case Instructions::i16x8_narrow_i32x4_u.value(): + case Instructions::i16x8_extend_low_i8x16_s.value(): + case Instructions::i16x8_extend_high_i8x16_s.value(): + case Instructions::i16x8_extend_low_i8x16_u.value(): + case Instructions::i16x8_extend_high_i8x16_u.value(): + case Instructions::i16x8_shl.value(): + case Instructions::i16x8_shr_s.value(): + case Instructions::i16x8_shr_u.value(): + case Instructions::i16x8_add.value(): + case Instructions::i16x8_add_sat_s.value(): + case Instructions::i16x8_add_sat_u.value(): + case Instructions::i16x8_sub.value(): + case Instructions::i16x8_sub_sat_s.value(): + case Instructions::i16x8_sub_sat_u.value(): + case Instructions::f64x2_nearest.value(): + case Instructions::i16x8_mul.value(): + case Instructions::i16x8_min_s.value(): + case Instructions::i16x8_min_u.value(): + case Instructions::i16x8_max_s.value(): + case Instructions::i16x8_max_u.value(): + case Instructions::i16x8_avgr_u.value(): + case Instructions::i16x8_extmul_low_i8x16_s.value(): + case Instructions::i16x8_extmul_high_i8x16_s.value(): + case Instructions::i16x8_extmul_low_i8x16_u.value(): + case Instructions::i16x8_extmul_high_i8x16_u.value(): + case Instructions::i32x4_abs.value(): + case Instructions::i32x4_neg.value(): + case Instructions::i32x4_all_true.value(): + case Instructions::i32x4_bitmask.value(): + case Instructions::i32x4_extend_low_i16x8_s.value(): + case Instructions::i32x4_extend_high_i16x8_s.value(): + case Instructions::i32x4_extend_low_i16x8_u.value(): + case Instructions::i32x4_extend_high_i16x8_u.value(): + case Instructions::i32x4_shl.value(): + case Instructions::i32x4_shr_s.value(): + case Instructions::i32x4_shr_u.value(): + case Instructions::i32x4_add.value(): + case Instructions::i32x4_sub.value(): + case Instructions::i32x4_mul.value(): + case Instructions::i32x4_min_s.value(): + case Instructions::i32x4_min_u.value(): + case Instructions::i32x4_max_s.value(): + case Instructions::i32x4_max_u.value(): + case Instructions::i32x4_dot_i16x8_s.value(): + case Instructions::i32x4_extmul_low_i16x8_s.value(): + case Instructions::i32x4_extmul_high_i16x8_s.value(): + case Instructions::i32x4_extmul_low_i16x8_u.value(): + case Instructions::i32x4_extmul_high_i16x8_u.value(): + case Instructions::i64x2_abs.value(): + case Instructions::i64x2_neg.value(): + case Instructions::i64x2_all_true.value(): + case Instructions::i64x2_bitmask.value(): + case Instructions::i64x2_extend_low_i32x4_s.value(): + case Instructions::i64x2_extend_high_i32x4_s.value(): + case Instructions::i64x2_extend_low_i32x4_u.value(): + case Instructions::i64x2_extend_high_i32x4_u.value(): + case Instructions::i64x2_shl.value(): + case Instructions::i64x2_shr_s.value(): + case Instructions::i64x2_shr_u.value(): + case Instructions::i64x2_add.value(): + case Instructions::i64x2_sub.value(): + case Instructions::i64x2_mul.value(): + case Instructions::i64x2_eq.value(): + case Instructions::i64x2_ne.value(): + case Instructions::i64x2_lt_s.value(): + case Instructions::i64x2_gt_s.value(): + case Instructions::i64x2_le_s.value(): + case Instructions::i64x2_ge_s.value(): + case Instructions::i64x2_extmul_low_i32x4_s.value(): + case Instructions::i64x2_extmul_high_i32x4_s.value(): + case Instructions::i64x2_extmul_low_i32x4_u.value(): + case Instructions::i64x2_extmul_high_i32x4_u.value(): + case Instructions::f32x4_abs.value(): + case Instructions::f32x4_neg.value(): + case Instructions::f32x4_sqrt.value(): + case Instructions::f32x4_add.value(): + case Instructions::f32x4_sub.value(): + case Instructions::f32x4_mul.value(): + case Instructions::f32x4_div.value(): + case Instructions::f32x4_min.value(): + case Instructions::f32x4_max.value(): + case Instructions::f32x4_pmin.value(): + case Instructions::f32x4_pmax.value(): + case Instructions::f64x2_abs.value(): + case Instructions::f64x2_neg.value(): + case Instructions::f64x2_sqrt.value(): + case Instructions::f64x2_add.value(): + case Instructions::f64x2_sub.value(): + case Instructions::f64x2_mul.value(): + case Instructions::f64x2_div.value(): + case Instructions::f64x2_min.value(): + case Instructions::f64x2_max.value(): + case Instructions::f64x2_pmin.value(): + case Instructions::f64x2_pmax.value(): + case Instructions::i32x4_trunc_sat_f32x4_s.value(): + case Instructions::i32x4_trunc_sat_f32x4_u.value(): + case Instructions::f32x4_convert_i32x4_s.value(): + case Instructions::f32x4_convert_i32x4_u.value(): + case Instructions::i32x4_trunc_sat_f64x2_s_zero.value(): + case Instructions::i32x4_trunc_sat_f64x2_u_zero.value(): + case Instructions::f64x2_convert_low_i32x4_s.value(): + case Instructions::f64x2_convert_low_i32x4_u.value(): + // op + resulting_instructions.append(Instruction { full_opcode }); + break; default: return ParseError::UnknownInstruction; } diff --git a/Userland/Libraries/LibWasm/Printer/Printer.cpp b/Userland/Libraries/LibWasm/Printer/Printer.cpp index 0432d1c415..167aea0377 100644 --- a/Userland/Libraries/LibWasm/Printer/Printer.cpp +++ b/Userland/Libraries/LibWasm/Printer/Printer.cpp @@ -433,6 +433,15 @@ void Printer::print(Wasm::Instruction const& instruction) [&](TableIndex const& index) { print("(table index {})", index.value()); }, [&](Instruction::IndirectCallArgs const& args) { print("(indirect (type index {}) (table index {}))", args.type.value(), args.table.value()); }, [&](Instruction::MemoryArgument const& args) { print("(memory (align {}) (offset {}))", args.align, args.offset); }, + [&](Instruction::MemoryAndLaneArgument const& args) { print("(memory (align {}) (offset {})) (lane {})", args.memory.align, args.memory.offset, args.lane); }, + [&](Instruction::LaneIndex const& args) { print("(lane {})", args.lane); }, + [&](Instruction::ShuffleArgument const& args) { + print("{{ {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} }}", + args.lanes[0], args.lanes[1], args.lanes[2], args.lanes[3], + args.lanes[4], args.lanes[5], args.lanes[6], args.lanes[7], + args.lanes[8], args.lanes[9], args.lanes[10], args.lanes[11], + args.lanes[12], args.lanes[13], args.lanes[14], args.lanes[15]); + }, [&](Instruction::StructuredInstructionArgs const& args) { print("(structured\n"); TemporaryChange change { m_indent, m_indent + 1 }; @@ -637,14 +646,17 @@ void Printer::print(Wasm::Value const& value) { print_indent(); print("{} ", value.value().visit([&](T const& value) { - if constexpr (IsSame) + if constexpr (IsSame) { return DeprecatedString::formatted( "addr({})", value.ref().visit( [](Wasm::Reference::Null const&) { return DeprecatedString("null"); }, [](auto const& ref) { return DeprecatedString::number(ref.address.value()); })); - else + } else if constexpr (IsSame) { + return DeprecatedString::formatted("v128({:x})", value); + } else { return DeprecatedString::formatted("{}", value); + } })); TemporaryChange change { m_indent, 0 }; print(value.type()); @@ -861,6 +873,242 @@ HashMap Wasm::Names::instruction_names { { Instructions::table_grow, "table.grow" }, { Instructions::table_size, "table.size" }, { Instructions::table_fill, "table.fill" }, + { Instructions::v128_load, "v128.load" }, + { Instructions::v128_load8x8_s, "v128.load8x8_s" }, + { Instructions::v128_load8x8_u, "v128.load8x8_u" }, + { Instructions::v128_load16x4_s, "v128.load16x4_s" }, + { Instructions::v128_load16x4_u, "v128.load16x4_u" }, + { Instructions::v128_load32x2_s, "v128.load32x2_s" }, + { Instructions::v128_load32x2_u, "v128.load32x2_u" }, + { Instructions::v128_load8_splat, "v128.load8_splat" }, + { Instructions::v128_load16_splat, "v128.load16_splat" }, + { Instructions::v128_load32_splat, "v128.load32_splat" }, + { Instructions::v128_load64_splat, "v128.load64_splat" }, + { Instructions::v128_store, "v128.store" }, + { Instructions::v128_const, "v128.const" }, + { Instructions::i8x16_shuffle, "i8x16.shuffle" }, + { Instructions::i8x16_swizzle, "i8x16.swizzle" }, + { Instructions::i8x16_splat, "i8x16.splat" }, + { Instructions::i16x8_splat, "i16x8.splat" }, + { Instructions::i32x4_splat, "i32x4.splat" }, + { Instructions::i64x2_splat, "i64x2.splat" }, + { Instructions::f32x4_splat, "f32x4.splat" }, + { Instructions::f64x2_splat, "f64x2.splat" }, + { Instructions::i8x16_extract_lane_s, "i8x16.extract_lane_s" }, + { Instructions::i8x16_extract_lane_u, "i8x16.extract_lane_u" }, + { Instructions::i8x16_replace_lane, "i8x16.replace_lane" }, + { Instructions::i16x8_extract_lane_s, "i16x8.extract_lane_s" }, + { Instructions::i16x8_extract_lane_u, "i16x8.extract_lane_u" }, + { Instructions::i16x8_replace_lane, "i16x8.replace_lane" }, + { Instructions::i32x4_extract_lane, "i32x4.extract_lane" }, + { Instructions::i32x4_replace_lane, "i32x4.replace_lane" }, + { Instructions::i64x2_extract_lane, "i64x2.extract_lane" }, + { Instructions::i64x2_replace_lane, "i64x2.replace_lane" }, + { Instructions::f32x4_extract_lane, "f32x4.extract_lane" }, + { Instructions::f32x4_replace_lane, "f32x4.replace_lane" }, + { Instructions::f64x2_extract_lane, "f64x2.extract_lane" }, + { Instructions::f64x2_replace_lane, "f64x2.replace_lane" }, + { Instructions::i8x16_eq, "i8x16.eq" }, + { Instructions::i8x16_ne, "i8x16.ne" }, + { Instructions::i8x16_lt_s, "i8x16.lt_s" }, + { Instructions::i8x16_lt_u, "i8x16.lt_u" }, + { Instructions::i8x16_gt_s, "i8x16.gt_s" }, + { Instructions::i8x16_gt_u, "i8x16.gt_u" }, + { Instructions::i8x16_le_s, "i8x16.le_s" }, + { Instructions::i8x16_le_u, "i8x16.le_u" }, + { Instructions::i8x16_ge_s, "i8x16.ge_s" }, + { Instructions::i8x16_ge_u, "i8x16.ge_u" }, + { Instructions::i16x8_eq, "i16x8.eq" }, + { Instructions::i16x8_ne, "i16x8.ne" }, + { Instructions::i16x8_lt_s, "i16x8.lt_s" }, + { Instructions::i16x8_lt_u, "i16x8.lt_u" }, + { Instructions::i16x8_gt_s, "i16x8.gt_s" }, + { Instructions::i16x8_gt_u, "i16x8.gt_u" }, + { Instructions::i16x8_le_s, "i16x8.le_s" }, + { Instructions::i16x8_le_u, "i16x8.le_u" }, + { Instructions::i16x8_ge_s, "i16x8.ge_s" }, + { Instructions::i16x8_ge_u, "i16x8.ge_u" }, + { Instructions::i32x4_eq, "i32x4.eq" }, + { Instructions::i32x4_ne, "i32x4.ne" }, + { Instructions::i32x4_lt_s, "i32x4.lt_s" }, + { Instructions::i32x4_lt_u, "i32x4.lt_u" }, + { Instructions::i32x4_gt_s, "i32x4.gt_s" }, + { Instructions::i32x4_gt_u, "i32x4.gt_u" }, + { Instructions::i32x4_le_s, "i32x4.le_s" }, + { Instructions::i32x4_le_u, "i32x4.le_u" }, + { Instructions::i32x4_ge_s, "i32x4.ge_s" }, + { Instructions::i32x4_ge_u, "i32x4.ge_u" }, + { Instructions::f32x4_eq, "f32x4.eq" }, + { Instructions::f32x4_ne, "f32x4.ne" }, + { Instructions::f32x4_lt, "f32x4.lt" }, + { Instructions::f32x4_gt, "f32x4.gt" }, + { Instructions::f32x4_le, "f32x4.le" }, + { Instructions::f32x4_ge, "f32x4.ge" }, + { Instructions::f64x2_eq, "f64x2.eq" }, + { Instructions::f64x2_ne, "f64x2.ne" }, + { Instructions::f64x2_lt, "f64x2.lt" }, + { Instructions::f64x2_gt, "f64x2.gt" }, + { Instructions::f64x2_le, "f64x2.le" }, + { Instructions::f64x2_ge, "f64x2.ge" }, + { Instructions::v128_not, "v128.not" }, + { Instructions::v128_and, "v128.and" }, + { Instructions::v128_andnot, "v128.andnot" }, + { Instructions::v128_or, "v128.or" }, + { Instructions::v128_xor, "v128.xor" }, + { Instructions::v128_bitselect, "v128.bitselect" }, + { Instructions::v128_any_true, "v128.any_true" }, + { Instructions::v128_load8_lane, "v128.load8_lane" }, + { Instructions::v128_load16_lane, "v128.load16_lane" }, + { Instructions::v128_load32_lane, "v128.load32_lane" }, + { Instructions::v128_load64_lane, "v128.load64_lane" }, + { Instructions::v128_store8_lane, "v128.store8_lane" }, + { Instructions::v128_store16_lane, "v128.store16_lane" }, + { Instructions::v128_store32_lane, "v128.store32_lane" }, + { Instructions::v128_store64_lane, "v128.store64_lane" }, + { Instructions::v128_load32_zero, "v128.load32_zero" }, + { Instructions::v128_load64_zero, "v128.load64_zero" }, + { Instructions::f32x4_demote_f64x2_zero, "f32x4.demote_f64x2_zero" }, + { Instructions::f64x2_promote_low_f32x4, "f64x2.promote_low_f32x4" }, + { Instructions::i8x16_abs, "i8x16.abs" }, + { Instructions::i8x16_neg, "i8x16.neg" }, + { Instructions::i8x16_popcnt, "i8x16.popcnt" }, + { Instructions::i8x16_all_true, "i8x16.all_true" }, + { Instructions::i8x16_bitmask, "i8x16.bitmask" }, + { Instructions::i8x16_narrow_i16x8_s, "i8x16.narrow_i16x8_s" }, + { Instructions::i8x16_narrow_i16x8_u, "i8x16.narrow_i16x8_u" }, + { Instructions::f32x4_ceil, "f32x4.ceil" }, + { Instructions::f32x4_floor, "f32x4.floor" }, + { Instructions::f32x4_trunc, "f32x4.trunc" }, + { Instructions::f32x4_nearest, "f32x4.nearest" }, + { Instructions::i8x16_shl, "i8x16.shl" }, + { Instructions::i8x16_shr_s, "i8x16.shr_s" }, + { Instructions::i8x16_shr_u, "i8x16.shr_u" }, + { Instructions::i8x16_add, "i8x16.add" }, + { Instructions::i8x16_add_sat_s, "i8x16.add_sat_s" }, + { Instructions::i8x16_add_sat_u, "i8x16.add_sat_u" }, + { Instructions::i8x16_sub, "i8x16.sub" }, + { Instructions::i8x16_sub_sat_s, "i8x16.sub_sat_s" }, + { Instructions::i8x16_sub_sat_u, "i8x16.sub_sat_u" }, + { Instructions::f64x2_ceil, "f64x2.ceil" }, + { Instructions::f64x2_floor, "f64x2.floor" }, + { Instructions::i8x16_min_s, "i8x16.min_s" }, + { Instructions::i8x16_min_u, "i8x16.min_u" }, + { Instructions::i8x16_max_s, "i8x16.max_s" }, + { Instructions::i8x16_max_u, "i8x16.max_u" }, + { Instructions::f64x2_trunc, "f64x2.trunc" }, + { Instructions::i8x16_avgr_u, "i8x16.avgr_u" }, + { Instructions::i16x8_extadd_pairwise_i8x16_s, "i16x8.extadd_pairwise_i8x16_s" }, + { Instructions::i16x8_extadd_pairwise_i8x16_u, "i16x8.extadd_pairwise_i8x16_u" }, + { Instructions::i32x4_extadd_pairwise_i16x8_s, "i32x4.extadd_pairwise_i16x8_s" }, + { Instructions::i32x4_extadd_pairwise_i16x8_u, "i32x4.extadd_pairwise_i16x8_u" }, + { Instructions::i16x8_abs, "i16x8.abs" }, + { Instructions::i16x8_neg, "i16x8.neg" }, + { Instructions::i16x8_q15mulr_sat_s, "i16x8.q15mulr_sat_s" }, + { Instructions::i16x8_all_true, "i16x8.all_true" }, + { Instructions::i16x8_bitmask, "i16x8.bitmask" }, + { Instructions::i16x8_narrow_i32x4_s, "i16x8.narrow_i32x4_s" }, + { Instructions::i16x8_narrow_i32x4_u, "i16x8.narrow_i32x4_u" }, + { Instructions::i16x8_extend_low_i8x16_s, "i16x8.extend_low_i8x16_s" }, + { Instructions::i16x8_extend_high_i8x16_s, "i16x8.extend_high_i8x16_s" }, + { Instructions::i16x8_extend_low_i8x16_u, "i16x8.extend_low_i8x16_u" }, + { Instructions::i16x8_extend_high_i8x16_u, "i16x8.extend_high_i8x16_u" }, + { Instructions::i16x8_shl, "i16x8.shl" }, + { Instructions::i16x8_shr_s, "i16x8.shr_s" }, + { Instructions::i16x8_shr_u, "i16x8.shr_u" }, + { Instructions::i16x8_add, "i16x8.add" }, + { Instructions::i16x8_add_sat_s, "i16x8.add_sat_s" }, + { Instructions::i16x8_add_sat_u, "i16x8.add_sat_u" }, + { Instructions::i16x8_sub, "i16x8.sub" }, + { Instructions::i16x8_sub_sat_s, "i16x8.sub_sat_s" }, + { Instructions::i16x8_sub_sat_u, "i16x8.sub_sat_u" }, + { Instructions::f64x2_nearest, "f64x2.nearest" }, + { Instructions::i16x8_mul, "i16x8.mul" }, + { Instructions::i16x8_min_s, "i16x8.min_s" }, + { Instructions::i16x8_min_u, "i16x8.min_u" }, + { Instructions::i16x8_max_s, "i16x8.max_s" }, + { Instructions::i16x8_max_u, "i16x8.max_u" }, + { Instructions::i16x8_avgr_u, "i16x8.avgr_u" }, + { Instructions::i16x8_extmul_low_i8x16_s, "i16x8.extmul_low_i8x16_s" }, + { Instructions::i16x8_extmul_high_i8x16_s, "i16x8.extmul_high_i8x16_s" }, + { Instructions::i16x8_extmul_low_i8x16_u, "i16x8.extmul_low_i8x16_u" }, + { Instructions::i16x8_extmul_high_i8x16_u, "i16x8.extmul_high_i8x16_u" }, + { Instructions::i32x4_abs, "i32x4.abs" }, + { Instructions::i32x4_neg, "i32x4.neg" }, + { Instructions::i32x4_all_true, "i32x4.all_true" }, + { Instructions::i32x4_bitmask, "i32x4.bitmask" }, + { Instructions::i32x4_extend_low_i16x8_s, "i32x4.extend_low_i16x8_s" }, + { Instructions::i32x4_extend_high_i16x8_s, "i32x4.extend_high_i16x8_s" }, + { Instructions::i32x4_extend_low_i16x8_u, "i32x4.extend_low_i16x8_u" }, + { Instructions::i32x4_extend_high_i16x8_u, "i32x4.extend_high_i16x8_u" }, + { Instructions::i32x4_shl, "i32x4.shl" }, + { Instructions::i32x4_shr_s, "i32x4.shr_s" }, + { Instructions::i32x4_shr_u, "i32x4.shr_u" }, + { Instructions::i32x4_add, "i32x4.add" }, + { Instructions::i32x4_sub, "i32x4.sub" }, + { Instructions::i32x4_mul, "i32x4.mul" }, + { Instructions::i32x4_min_s, "i32x4.min_s" }, + { Instructions::i32x4_min_u, "i32x4.min_u" }, + { Instructions::i32x4_max_s, "i32x4.max_s" }, + { Instructions::i32x4_max_u, "i32x4.max_u" }, + { Instructions::i32x4_dot_i16x8_s, "i32x4.dot_i16x8_s" }, + { Instructions::i32x4_extmul_low_i16x8_s, "i32x4.extmul_low_i16x8_s" }, + { Instructions::i32x4_extmul_high_i16x8_s, "i32x4.extmul_high_i16x8_s" }, + { Instructions::i32x4_extmul_low_i16x8_u, "i32x4.extmul_low_i16x8_u" }, + { Instructions::i32x4_extmul_high_i16x8_u, "i32x4.extmul_high_i16x8_u" }, + { Instructions::i64x2_abs, "i64x2.abs" }, + { Instructions::i64x2_neg, "i64x2.neg" }, + { Instructions::i64x2_all_true, "i64x2.all_true" }, + { Instructions::i64x2_bitmask, "i64x2.bitmask" }, + { Instructions::i64x2_extend_low_i32x4_s, "i64x2.extend_low_i32x4_s" }, + { Instructions::i64x2_extend_high_i32x4_s, "i64x2.extend_high_i32x4_s" }, + { Instructions::i64x2_extend_low_i32x4_u, "i64x2.extend_low_i32x4_u" }, + { Instructions::i64x2_extend_high_i32x4_u, "i64x2.extend_high_i32x4_u" }, + { Instructions::i64x2_shl, "i64x2.shl" }, + { Instructions::i64x2_shr_s, "i64x2.shr_s" }, + { Instructions::i64x2_shr_u, "i64x2.shr_u" }, + { Instructions::i64x2_add, "i64x2.add" }, + { Instructions::i64x2_sub, "i64x2.sub" }, + { Instructions::i64x2_mul, "i64x2.mul" }, + { Instructions::i64x2_eq, "i64x2.eq" }, + { Instructions::i64x2_ne, "i64x2.ne" }, + { Instructions::i64x2_lt_s, "i64x2.lt_s" }, + { Instructions::i64x2_gt_s, "i64x2.gt_s" }, + { Instructions::i64x2_le_s, "i64x2.le_s" }, + { Instructions::i64x2_ge_s, "i64x2.ge_s" }, + { Instructions::i64x2_extmul_low_i32x4_s, "i64x2.extmul_low_i32x4_s" }, + { Instructions::i64x2_extmul_high_i32x4_s, "i64x2.extmul_high_i32x4_s" }, + { Instructions::i64x2_extmul_low_i32x4_u, "i64x2.extmul_low_i32x4_u" }, + { Instructions::i64x2_extmul_high_i32x4_u, "i64x2.extmul_high_i32x4_u" }, + { Instructions::f32x4_abs, "f32x4.abs" }, + { Instructions::f32x4_neg, "f32x4.neg" }, + { Instructions::f32x4_sqrt, "f32x4.sqrt" }, + { Instructions::f32x4_add, "f32x4.add" }, + { Instructions::f32x4_sub, "f32x4.sub" }, + { Instructions::f32x4_mul, "f32x4.mul" }, + { Instructions::f32x4_div, "f32x4.div" }, + { Instructions::f32x4_min, "f32x4.min" }, + { Instructions::f32x4_max, "f32x4.max" }, + { Instructions::f32x4_pmin, "f32x4.pmin" }, + { Instructions::f32x4_pmax, "f32x4.pmax" }, + { Instructions::f64x2_abs, "f64x2.abs" }, + { Instructions::f64x2_neg, "f64x2.neg" }, + { Instructions::f64x2_sqrt, "f64x2.sqrt" }, + { Instructions::f64x2_add, "f64x2.add" }, + { Instructions::f64x2_sub, "f64x2.sub" }, + { Instructions::f64x2_mul, "f64x2.mul" }, + { Instructions::f64x2_div, "f64x2.div" }, + { Instructions::f64x2_min, "f64x2.min" }, + { Instructions::f64x2_max, "f64x2.max" }, + { Instructions::f64x2_pmin, "f64x2.pmin" }, + { Instructions::f64x2_pmax, "f64x2.pmax" }, + { Instructions::i32x4_trunc_sat_f32x4_s, "i32x4.trunc_sat_f32x4_s" }, + { Instructions::i32x4_trunc_sat_f32x4_u, "i32x4.trunc_sat_f32x4_u" }, + { Instructions::f32x4_convert_i32x4_s, "f32x4.convert_i32x4_s" }, + { Instructions::f32x4_convert_i32x4_u, "f32x4.convert_i32x4_u" }, + { Instructions::i32x4_trunc_sat_f64x2_s_zero, "i32x4.trunc_sat_f64x2_s_zero" }, + { Instructions::i32x4_trunc_sat_f64x2_u_zero, "i32x4.trunc_sat_f64x2_u_zero" }, + { Instructions::f64x2_convert_low_i32x4_s, "f64x2.convert_low_i32x4_s" }, + { Instructions::f64x2_convert_low_i32x4_u, "f64x2.convert_low_i32x4_u" }, { Instructions::structured_else, "synthetic:else" }, { Instructions::structured_end, "synthetic:end" }, }; diff --git a/Userland/Libraries/LibWasm/Types.h b/Userland/Libraries/LibWasm/Types.h index c12f0bb8d9..ffba0ffb2c 100644 --- a/Userland/Libraries/LibWasm/Types.h +++ b/Userland/Libraries/LibWasm/Types.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -143,6 +145,7 @@ public: I64, F32, F64, + V128, FunctionReference, ExternReference, NullFunctionReference, @@ -157,7 +160,8 @@ public: bool operator==(ValueType const&) const = default; auto is_reference() const { return m_kind == ExternReference || m_kind == FunctionReference || m_kind == NullExternReference || m_kind == NullFunctionReference; } - auto is_numeric() const { return !is_reference(); } + auto is_vector() const { return m_kind == V128; } + auto is_numeric() const { return !is_reference() && !is_vector(); } auto kind() const { return m_kind; } static ParseResult parse(Stream& stream); @@ -173,6 +177,8 @@ public: return "f32"; case F64: return "f64"; + case V128: + return "v128"; case FunctionReference: return "funcref"; case ExternReference: @@ -394,6 +400,27 @@ public: u32 offset; }; + struct MemoryAndLaneArgument { + MemoryArgument memory; + u8 lane; + }; + + struct LaneIndex { + u8 lane; + }; + + struct ShuffleArgument { + explicit ShuffleArgument(u8 (&lanes)[16]) + : lanes { + lanes[0], lanes[1], lanes[2], lanes[3], lanes[4], lanes[5], lanes[6], lanes[7], + lanes[8], lanes[9], lanes[10], lanes[11], lanes[12], lanes[13], lanes[14], lanes[15] + } + { + } + + u8 lanes[16]; + }; + template explicit Instruction(OpCode opcode, T argument) : m_opcode(opcode) @@ -417,9 +444,12 @@ private: GlobalIndex, IndirectCallArgs, LabelIndex, + LaneIndex, LocalIndex, MemoryArgument, + MemoryAndLaneArgument, StructuredInstructionArgs, + ShuffleArgument, TableBranchArgs, TableElementArgs, TableIndex, @@ -430,6 +460,7 @@ private: float, i32, i64, + u128, u8 // Empty state > m_arguments; // clang-format on diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp index d6092354ae..db1090acdb 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp @@ -416,6 +416,8 @@ JS::ThrowCompletionOr to_webassembly_value(JS::VM& vm, JS::Value va case Wasm::ValueType::ExternReference: case Wasm::ValueType::NullExternReference: TODO(); + case Wasm::ValueType::V128: + return vm.throw_completion("Cannot convert a vector value to a javascript value"sv); } VERIFY_NOT_REACHED(); @@ -438,6 +440,7 @@ JS::Value to_js_value(JS::VM& vm, Wasm::Value& wasm_value) return create_native_function(vm, wasm_value.to().value().address, "FIXME_IHaveNoIdeaWhatThisShouldBeCalled"); case Wasm::ValueType::NullFunctionReference: return JS::js_null(); + case Wasm::ValueType::V128: case Wasm::ValueType::ExternReference: case Wasm::ValueType::NullExternReference: TODO();