Skip to content
This repository was archived by the owner on May 24, 2025. It is now read-only.
This repository was archived by the owner on May 24, 2025. It is now read-only.

Implementation feedback: x86/x64 lacks float64 <> float16 instructions #12

@syg

Description

@syg

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 and Float16ViaFloat32Array (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 doubles 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions