-
Notifications
You must be signed in to change notification settings - Fork 4
Implementation feedback: x86/x64 lacks float64 <> float16 instructions #12
Description
Currently, Math.f16round
and assigning into Float16Array
does a conversion from float64 to float16 using the roundTiesToEven mode.
On x86/x64, as far as V8 can tell there are no generally available instructions to directly narrow float64 to float16. There are two extensions that supports float16. F16C, an SSE extension, which has been available since 2007. And AVX512-FP16, which is much newer and is currently only available on the latest Sapphire Rapids Xeon chips. Both extensions only support converting float32 to float16. F16C only supports converting float32 to float16. AVX512-FP16 does support float64 to float16 but is only on newest Xeons.
(On ARM such instructions exist, this is an x86-only issue.)
Notably, using roundTiesToEven, narrowing float64 to float16 is not equivalent to narrowing float64 to float32 to float16. This means that on x86/x64, there is no efficient codegen possible for float16 rounding in the foreseeable future. There is only efficient codegen possible by first converting to float32, e.g. Math.f16round(Math.fround(n))
and f16a[idx] = Math.fround(n)
.
The main problem is that the obvious code you want to write is slow because it requires software emulation.
There are alternatives, but each one is kind of unsavory in its own way.
- We could spec float64 to float16 conversion directly as float64 to float32 to float16, under roundTiesToEven. This is unsavory because
Math.f16round
sure doesn't sound like it should be doing an intermediate narrowing first. - We could spec float64 to float16 conversion as using roundTiesToZero, in which case it's unobservable if you first round to a float32 intermediate. This is unsavory because all other floating point operations in JS use roundTiesToEven.
- We could add a new
f16via32round
andFloat16ViaFloat32Array
(names up to bikeshedding) that do an intermediate round.
For comparison, this is probably less of an issue for other languages that are adding float16 because float32s are already a primitive type in those languages. In C++, this would only come up if you're actually converting double
s to halfs. Similar for Wasm.
But for JS, since the only number type we have is double
, it'll end up being a very common operation whether intentional or not. I think there's also a question whether real world code tend to go from float64 to float16 directly, or they're mostly going from float32 (that is, maybe x86 doesn't have instructions for it because there's no demand).
Thoughts from other implementers @dminor @msaboff?
h/t @SPY