Is there a CPU half data type?

The GPU can use 16-bit floats by using the "half" data type. Do the CPU have a 16-bit float?


My actual issue is that I want to use "half" in my GPU uniform structs - how can I initialize such values on the CPU?

Answered by wcm in 137903022

For storage, you can use the

__fp16
type, or any type that has the same size and alignment as
half
, such as
uint16_t
.


Assignments from

float
to
__fp16
will emit the appropriate
fcvt
instruction or intrinsic, depending on the target platform.


If you elect to use

uint16_t
as your storage type, you can still type-pun through the
__fp16
type to load and store:


static float loadFromF16(const uint16_t *pointer) { return *(const __fp16 *)pointer; } 
static void storeAsF16(float value, uint16_t *pointer) { *(__fp16 *)pointer = value; }


If you have a long list of floats you need to convert to half, rather than a few struct members, using the

vImageConvert_PlanarFtoPlanar16F
function may be more efficient.
Accepted Answer

For storage, you can use the

__fp16
type, or any type that has the same size and alignment as
half
, such as
uint16_t
.


Assignments from

float
to
__fp16
will emit the appropriate
fcvt
instruction or intrinsic, depending on the target platform.


If you elect to use

uint16_t
as your storage type, you can still type-pun through the
__fp16
type to load and store:


static float loadFromF16(const uint16_t *pointer) { return *(const __fp16 *)pointer; } 
static void storeAsF16(float value, uint16_t *pointer) { *(__fp16 *)pointer = value; }


If you have a long list of floats you need to convert to half, rather than a few struct members, using the

vImageConvert_PlanarFtoPlanar16F
function may be more efficient.

hi Jakob,


You might also be interested in the OpenEXR project's Half type which a C++ class representing a half precision float.. http://www.openexr.com


OpenEXR is focused on the image file format of that name but the Half type and the associated utilities (in the Ilmbase library) can be used entirely separately from the OpenEXR library which is built on top of that.


Cheers,

- James

How to do it in Swift? Should Swift have a 16 bit float type?

Note that _fp16 will only emit the hardware conversion on Intel if you pass -mf16c to the compiler. Fortunately, all BigSur supported machines support the conversion, but I don't believe it is on by default yet for x8664 targeting that OS. It is an IvyBridge or later instruction. If you don't pass -mf16c, then you'll get a software conversion, which is not very cheap.

On Apple Silicon, the appropriate instructions have been there since Cortex A9 and should be there on any arm64 machine.

If you need to convert a whole bunch of half float values in an array, please see vImageConvertPlanarFtoPlanar16F and vImageConvertPlanar16FtoPlanarF.

If you need to test to see if the machine supports the instruction, you can use sysctlbyname( "hw.optional.f16c", ...)

So where should we set -mf16c in the compile settings? The vector instruction setting only takes SSE4.2, AVX, AVX2. This corresponds with an x86 named compile setting (really x64) and translates to say "-march avx2". For some bizarre reason, Xcode leaves f16c disabled if AVX or AVX2 are set. This is a major slowdown for macOS Intel apps. This despite AVX/AVX2 being tied into the f16c instructions.

So then Apple Silicon nicely ignores the -march setting. But if you set -mf16c anywhere in the other compile flags, then the universal build complains that is an unused argument.

Is there a CPU half data type?
 
 
Q