mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 08:57:34 +00:00
LibWasm: Implement checked truncation instructions
This implements the 8 i<n>.truncate.f<n>_<s> instructions.
This commit is contained in:
parent
59e01e2813
commit
a21ebae652
3 changed files with 86 additions and 10 deletions
|
@ -115,6 +115,8 @@ public:
|
||||||
[&](auto value) {
|
[&](auto value) {
|
||||||
if constexpr (IsSame<T, decltype(value)>)
|
if constexpr (IsSame<T, decltype(value)>)
|
||||||
result = value;
|
result = value;
|
||||||
|
else if constexpr (!IsFloatingPoint<T> && IsSame<decltype(value), MakeSigned<T>>)
|
||||||
|
result = value;
|
||||||
},
|
},
|
||||||
[&](const FunctionAddress& address) {
|
[&](const FunctionAddress& address) {
|
||||||
if constexpr (IsSame<T, FunctionAddress>)
|
if constexpr (IsSame<T, FunctionAddress>)
|
||||||
|
|
|
@ -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>> Interpreter::pop_values(Configuration& configuration, size_t count)
|
||||||
{
|
{
|
||||||
Vector<NonnullOwnPtr<Value>> results;
|
Vector<NonnullOwnPtr<Value>> results;
|
||||||
|
@ -753,20 +798,42 @@ void Interpreter::interpret(Configuration& configuration, InstructionPointer& ip
|
||||||
BINARY_PREFIX_NUMERIC_OPERATION(double, copysign, double);
|
BINARY_PREFIX_NUMERIC_OPERATION(double, copysign, double);
|
||||||
case Instructions::i32_wrap_i64.value():
|
case Instructions::i32_wrap_i64.value():
|
||||||
UNARY_MAP(i64, i32, i32);
|
UNARY_MAP(i64, i32, i32);
|
||||||
case Instructions::i32_trunc_sf32.value():
|
case Instructions::i32_trunc_sf32.value(): {
|
||||||
case Instructions::i32_trunc_uf32.value():
|
auto fn = [this](auto& v) { return checked_signed_truncate<float, i32>(v); };
|
||||||
case Instructions::i32_trunc_sf64.value():
|
UNARY_MAP(float, fn, i32);
|
||||||
case Instructions::i32_trunc_uf64.value():
|
}
|
||||||
goto unimplemented;
|
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():
|
case Instructions::i64_extend_si32.value():
|
||||||
UNARY_MAP(i32, i64, i64);
|
UNARY_MAP(i32, i64, i64);
|
||||||
case Instructions::i64_extend_ui32.value():
|
case Instructions::i64_extend_ui32.value():
|
||||||
UNARY_MAP(u32, i64, i64);
|
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():
|
case Instructions::f32_convert_si32.value():
|
||||||
UNARY_MAP(i32, float, float);
|
UNARY_MAP(i32, float, float);
|
||||||
case Instructions::f32_convert_ui32.value():
|
case Instructions::f32_convert_ui32.value():
|
||||||
|
|
|
@ -20,6 +20,13 @@ private:
|
||||||
ReadonlyBytes load_from_memory(Configuration&, const Instruction&, size_t);
|
ReadonlyBytes load_from_memory(Configuration&, const Instruction&, size_t);
|
||||||
void store_to_memory(Configuration&, const Instruction&, ReadonlyBytes data);
|
void store_to_memory(Configuration&, const Instruction&, ReadonlyBytes data);
|
||||||
void call_address(Configuration&, FunctionAddress);
|
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);
|
Vector<NonnullOwnPtr<Value>> pop_values(Configuration& configuration, size_t count);
|
||||||
bool trap_if_not(bool value)
|
bool trap_if_not(bool value)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue