summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibWasm
diff options
context:
space:
mode:
authorAli Mohammad Pur <ali.mpfard@gmail.com>2021-05-18 01:19:40 +0430
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2021-05-26 15:34:13 +0430
commita21ebae6521b2310b18a3a777575d9f479133f02 (patch)
treef77db38a3c59f4c78a8552d8627fbf66e18f4dea /Userland/Libraries/LibWasm
parent59e01e28131c5e60d508a7df949f7abfc98e068e (diff)
downloadserenity-a21ebae6521b2310b18a3a777575d9f479133f02.zip
LibWasm: Implement checked truncation instructions
This implements the 8 i<n>.truncate.f<n>_<s> instructions.
Diffstat (limited to 'Userland/Libraries/LibWasm')
-rw-r--r--Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.h2
-rw-r--r--Userland/Libraries/LibWasm/AbstractMachine/Interpreter.cpp87
-rw-r--r--Userland/Libraries/LibWasm/AbstractMachine/Interpreter.h7
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)
{