DLR-FT / wasm-interpreter

A minimal in-place WebAssembly interpreter, written in Rust, almost without use of external dependencies
https://dlr-ft.github.io/wasm-interpreter/main/
Apache License 2.0
4 stars 4 forks source link

Discussion: float no_std unsupported methods #50

Open nerodesu017 opened 3 months ago

nerodesu017 commented 3 months ago

As the title says, there are a few methods for f32 (and I assume for f64, as well), that are only in the std library: abs, ceil, floor, trunc, round, sqrt and copysign.

The only alternative I could find, until now, was the libm library. Sadly, it has a major number of 0, which means breaking changes might appear on any new update. We could lock it at a version or maybe just use from its source what's needed, since licenses are Apache 2 and MIT

florianhartung commented 3 months ago

Including libm as a dependency is not an option IIRC. Although not mentioned in the requirements, we want to minimize the use of external dependencies. The closest matching requirement would be: https://github.com/DLR-FT/wasm-interpreter/blob/256e3cd31c7f52033373a5aec69fd8dc5de86fa2/requirements/requirements.sdoc#L18-L26

florianhartung commented 3 months ago

@wucke13

nerodesu017 commented 3 months ago

So what solution would you guys propose?

wucke13 commented 3 months ago

I' immediately aware of https://docs.rs/libm/latest/libm/ and https://crates.io/crates/num-traits . Num internally relies on libm, but it uses the same names like std::f64, thus it is more familiar. Both have a minimal dependency tree, i.e. libm depends on nothing, and num-traits depends only on libm. Other than that, we could implement these by hand. here would be the most basic example for abs:

pub fn abs64(x: f64) -> f64 {
    f64::from_bits(x.to_bits() & (i64::MAX as u64))
}
pub fn abs32(x: f32) -> f32 {
    f32::from_bits(x.to_bits() & (i32::MAX as u32))
}

ceil and floor require some comparison with the exponent and the mantissa, should be easy enough. Really the only non-trivial issue is sqrt. We could write a newton iteration for that, but it is not guaranteed to complete in a fixed time, i.e. it would be a loop with an unstable termination condition. Here I'd much prefer to use the respective hardware instruction.

In short, I think it is mostly feasible to implement this by hand, but I believe it would be wise to tap into num-traits and be done with it.

nerodesu017 commented 3 months ago

We agreed to use libm, but not num-crates

nerodesu017 commented 3 months ago

As requested by @wucke13 here is the link that talks about some architectures silently altering floats:

https://github.com/bytecodealliance/wasmtime/pull/2251#discussion_r498508646

wucke13 commented 2 months ago

That is an interesting read. IIUC, the TL;DR of it is: bit representation (and especially the case distinctions) for NaN are not handled identical on all architectures. Hence wasmtime chose to implement these themselves. I'm still in favor of just using libm for now, and revisit this issue some-time later, as I do not expect immediate issue with this in-determinism w/r/t NaN representations. However, I do not have a strong opinion on this.

valexandru commented 2 months ago

Specifically talking about NaNs, I think it is not a critical problem, but I would keep in mind to fix it later in a similar manner to wasmtime.