diff options
author | Ali Mohammad Pur <ali.mpfard@gmail.com> | 2021-05-18 01:19:40 +0430 |
---|---|---|
committer | Ali Mohammad Pur <Ali.mpfard@gmail.com> | 2021-05-26 15:34:13 +0430 |
commit | a21ebae6521b2310b18a3a777575d9f479133f02 (patch) | |
tree | f77db38a3c59f4c78a8552d8627fbf66e18f4dea /Userland/Libraries/LibWasm | |
parent | 59e01e28131c5e60d508a7df949f7abfc98e068e (diff) | |
download | serenity-a21ebae6521b2310b18a3a777575d9f479133f02.zip |
LibWasm: Implement checked truncation instructions
This implements the 8 i<n>.truncate.f<n>_<s> instructions.
Diffstat (limited to 'Userland/Libraries/LibWasm')
3 files changed, 86 insertions, 10 deletions
diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h index 42646df276..315d6cee8d 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h @@ -115,6 +115,8 @@ public: [&](auto value) { if constexpr (IsSame<T, decltype(value)>) result = value; + else if constexpr (!IsFloatingPoint<T> && IsSame<decltype(value), MakeSigned<T>>) + result = value; }, [&](const FunctionAddress& address) { if constexpr (IsSame<T, FunctionAddress>) diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp b/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp index 6e789c8671..68312a5f3c 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp @@ -274,6 +274,51 @@ struct ConvertToRaw<double> { } }; +template<typename V, typename T> +MakeSigned<T> Interpreter::checked_signed_truncate(V value) +{ + if (isnan(value) || isinf(value)) { // "undefined", let's just trap. + m_do_trap = true; + return 0; + } + + double truncated; + if constexpr (IsSame<float, V>) + truncated = truncf(value); + else + truncated = trunc(value); + + using SignedT = MakeSigned<T>; + if (NumericLimits<SignedT>::min() <= truncated && static_cast<double>(NumericLimits<SignedT>::max()) >= truncated) + return static_cast<SignedT>(truncated); + + dbgln_if(WASM_TRACE_DEBUG, "Truncate out of range error"); + m_do_trap = true; + return true; +} + +template<typename V, typename T> +MakeUnsigned<T> Interpreter::checked_unsigned_truncate(V value) +{ + if (isnan(value) || isinf(value)) { // "undefined", let's just trap. + m_do_trap = true; + return 0; + } + double truncated; + if constexpr (IsSame<float, V>) + truncated = truncf(value); + else + truncated = trunc(value); + + using UnsignedT = MakeUnsigned<T>; + if (NumericLimits<UnsignedT>::min() <= truncated && static_cast<double>(NumericLimits<UnsignedT>::max()) >= truncated) + return static_cast<UnsignedT>(truncated); + + dbgln_if(WASM_TRACE_DEBUG, "Truncate out of range error"); + m_do_trap = true; + return true; +} + Vector<NonnullOwnPtr<Value>> Interpreter::pop_values(Configuration& configuration, size_t count) { Vector<NonnullOwnPtr<Value>> results; @@ -753,20 +798,42 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip BINARY_PREFIX_NUMERIC_OPERATION(double, copysign, double); case Instructions::i32_wrap_i64.value(): UNARY_MAP(i64, i32, i32); - case Instructions::i32_trunc_sf32.value(): - case Instructions::i32_trunc_uf32.value(): - case Instructions::i32_trunc_sf64.value(): - case Instructions::i32_trunc_uf64.value(): - goto unimplemented; + case Instructions::i32_trunc_sf32.value(): { + auto fn = [this](auto& v) { return checked_signed_truncate<float, i32>(v); }; + UNARY_MAP(float, fn, i32); + } + case Instructions::i32_trunc_uf32.value(): { + auto fn = [this](auto& value) { return checked_unsigned_truncate<float, i32>(value); }; + UNARY_MAP(float, fn, i32); + } + case Instructions::i32_trunc_sf64.value(): { + auto fn = [this](auto& value) { return checked_signed_truncate<double, i32>(value); }; + UNARY_MAP(double, fn, i32); + } + case Instructions::i32_trunc_uf64.value(): { + auto fn = [this](auto& value) { return checked_unsigned_truncate<double, i32>(value); }; + UNARY_MAP(double, fn, i32); + } + case Instructions::i64_trunc_sf32.value(): { + auto fn = [this](auto& value) { return checked_signed_truncate<float, i64>(value); }; + UNARY_MAP(float, fn, i64); + } + case Instructions::i64_trunc_uf32.value(): { + auto fn = [this](auto& value) { return checked_unsigned_truncate<float, i64>(value); }; + UNARY_MAP(float, fn, i64); + } + case Instructions::i64_trunc_sf64.value(): { + auto fn = [this](auto& value) { return checked_signed_truncate<double, i64>(value); }; + UNARY_MAP(double, fn, i64); + } + case Instructions::i64_trunc_uf64.value(): { + auto fn = [this](auto& value) { return checked_unsigned_truncate<double, i64>(value); }; + UNARY_MAP(double, fn, i64); + } case Instructions::i64_extend_si32.value(): UNARY_MAP(i32, i64, i64); case Instructions::i64_extend_ui32.value(): UNARY_MAP(u32, i64, i64); - case Instructions::i64_trunc_sf32.value(): - case Instructions::i64_trunc_uf32.value(): - case Instructions::i64_trunc_sf64.value(): - case Instructions::i64_trunc_uf64.value(): - goto unimplemented; case Instructions::f32_convert_si32.value(): UNARY_MAP(i32, float, float); case Instructions::f32_convert_ui32.value(): diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.h b/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.h index e78f8f462d..0e06650bf5 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.h +++ b/Userland/Libraries/LibWasm/AbstractMachine/Interpreter.h @@ -20,6 +20,13 @@ private: ReadonlyBytes load_from_memory(Configuration&, const Instruction&, size_t); void store_to_memory(Configuration&, const Instruction&, ReadonlyBytes data); void call_address(Configuration&, FunctionAddress); + + template<typename V, typename T> + MakeUnsigned<T> checked_unsigned_truncate(V); + + template<typename V, typename T> + MakeSigned<T> checked_signed_truncate(V); + Vector<NonnullOwnPtr<Value>> pop_values(Configuration& configuration, size_t count); bool trap_if_not(bool value) { |