Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for _Float16 16-bit floating point type #4065

Merged
merged 15 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 80 additions & 3 deletions config/cmake/ConfigureChecks.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,8 @@ macro (H5ConversionTests TEST def msg)
${CMAKE_BINARY_DIR}
${HDF_RESOURCES_DIR}/ConversionTests.c
CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=-D${TEST}_TEST
OUTPUT_VARIABLE OUTPUT
COMPILE_OUTPUT_VARIABLE ${TEST}_COMPILE_OUTPUT
RUN_OUTPUT_VARIABLE ${TEST}_RUN_OUTPUT
)
if (${TEST}_COMPILE)
if (${TEST}_RUN EQUAL "0")
Expand All @@ -901,14 +902,17 @@ macro (H5ConversionTests TEST def msg)
set (${TEST} "" CACHE INTERNAL ${msg})
message (VERBOSE "${msg}... no")
file (APPEND ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeError.log
"Test ${TEST} Run failed with the following output and exit code:\n ${OUTPUT}\n"
"Test ${TEST} Compile succeeded with the following output:\n ${${TEST}_COMPILE_OUTPUT}\n"
)
file (APPEND ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeError.log
"Test ${TEST} Run failed with exit code ${${TEST}_RUN} and with the following output:\n ${${TEST}_RUN_OUTPUT}\n"
)
endif ()
else ()
set (${TEST} "" CACHE INTERNAL ${msg})
message (VERBOSE "${msg}... no")
file (APPEND ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeError.log
"Test ${TEST} Compile failed with the following output:\n ${OUTPUT}\n"
"Test ${TEST} Compile failed with the following output:\n ${${TEST}_COMPILE_OUTPUT}\n"
)
endif ()
else ()
Expand Down Expand Up @@ -970,3 +974,76 @@ H5ConversionTests (${HDF_PREFIX}_LLONG_TO_LDOUBLE_CORRECT TRUE "Checking IF corr
# some long double values
#-----------------------------------------------------------------------------
H5ConversionTests (${HDF_PREFIX}_DISABLE_SOME_LDOUBLE_CONV FALSE "Checking IF the cpu is power9 and cannot correctly converting long double values")

#-----------------------------------------------------------------------------
# Check if _Float16 type is available
#-----------------------------------------------------------------------------
message (STATUS "Checking if _Float16 support is available")
set (${HDF_PREFIX}_HAVE__FLOAT16 0)
HDF_CHECK_TYPE_SIZE (_Float16 ${HDF_PREFIX}_SIZEOF__FLOAT16)
if (${HDF_PREFIX}_SIZEOF__FLOAT16)
# Request _Float16 support
set (CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} "-D__STDC_WANT_IEC_60559_TYPES_EXT__")

# Some compilers expose the _Float16 datatype, but not the macros and
# functions used with the datatype. We need the macros for proper
# datatype conversion support. Check for these here.
CHECK_SYMBOL_EXISTS (FLT16_EPSILON "float.h" h5_have_flt16_epsilon)
CHECK_SYMBOL_EXISTS (FLT16_MIN "float.h" h5_have_flt16_min)
CHECK_SYMBOL_EXISTS (FLT16_MAX "float.h" h5_have_flt16_max)
CHECK_SYMBOL_EXISTS (FLT16_MIN_10_EXP "float.h" h5_have_flt16_min_10_exp)
CHECK_SYMBOL_EXISTS (FLT16_MAX_10_EXP "float.h" h5_have_flt16_max_10_exp)
CHECK_SYMBOL_EXISTS (FLT16_MANT_DIG "float.h" h5_have_flt16_mant_dig)

if (h5_have_flt16_epsilon AND h5_have_flt16_min AND
h5_have_flt16_max AND h5_have_flt16_min_10_exp AND
h5_have_flt16_max_10_exp AND h5_have_flt16_mant_dig)
# Some compilers like OneAPI on Windows appear to detect _Float16 support
# properly up to this point, and, in the absence of any architecture-specific
# tuning compiler flags, will generate code for H5Tconv.c that performs
# software conversions on _Float16 variables with compiler-internal functions
# such as __extendhfsf2, __truncsfhf2, or __truncdfhf2. However, these
# compilers will fail to link these functions into the build for currently
# unknown reasons and cause the build to fail. Since these are compiler-internal
# functions that we don't appear to have much control over, let's try to
# compile a program that will generate these functions to check for _Float16
# support. If we fail to compile this program, we will simply disable
# _Float16 support for the time being.
H5ConversionTests (
${HDF_PREFIX}_FLOAT16_CONVERSION_FUNCS_LINK
FALSE
"Checking if compiler can convert _Float16 type with casts"
)

if (${${HDF_PREFIX}_FLOAT16_CONVERSION_FUNCS_LINK})
# Finally, MacOS 13 appears to have a bug specifically when converting
# long double values to _Float16. Release builds of the dt_arith test
# would cause any assignments to a _Float16 variable to be elided,
# whereas Debug builds would perform incorrect hardware conversions by
# simply chopping off all the bytes of the value except for the first 2.
# These tests pass on MacOS 14, so let's perform a quick test to check
# if the hardware conversion is done correctly.
H5ConversionTests (
${HDF_PREFIX}_LDOUBLE_TO_FLOAT16_CORRECT
TRUE
"Checking if correctly converting long double to _Float16 values"
)

if (NOT ${${HDF_PREFIX}_LDOUBLE_TO_FLOAT16_CORRECT})
message (VERBOSE "Conversions from long double to _Float16 appear to be incorrect. These will be emulated through a soft conversion function.")
endif ()

set (${HDF_PREFIX}_HAVE__FLOAT16 1)

# Check if we can use fabsf16
CHECK_FUNCTION_EXISTS (fabsf16 ${HDF_PREFIX}_HAVE_FABSF16)
else ()
message (STATUS "_Float16 support has been disabled because the compiler couldn't compile and run a test program for _Float16 conversions")
message (STATUS "Check ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeError.log for information on why the test program couldn't be compiled/run")
endif ()
else ()
message (STATUS "_Float16 support has been disabled since the required macros (FLT16_MAX, FLT16_EPSILON, etc. were not found)")
endif ()
else ()
message (STATUS "_Float16 support has been disabled since the _Float16 type was not found")
endif ()
122 changes: 122 additions & 0 deletions config/cmake/ConversionTests.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,125 @@ int HDF_NO_UBSAN main(void)
}

#endif

#ifdef H5_FLOAT16_CONVERSION_FUNCS_LINK_TEST

#define __STDC_WANT_IEC_60559_TYPES_EXT__

#include <stdlib.h>
#include <float.h>

int HDF_NO_UBSAN main(void)
{
_Float16 fl16_var;
signed char sc;
unsigned char usc;
short s;
unsigned short us;
int i;
unsigned int ui;
long l;
unsigned long ul;
long long ll;
unsigned long long ull;
float f;
double d;
long double ld;
int ret = 0;

/*
* Cast the _Float16 type between all the different C datatypes
* we support conversions for in H5Tconv.c to check if the compiler
* properly links any software conversion functions it may generate
* for the casts, such as __extendhfsf2 or __truncdfhf2.
*/

fl16_var = 3.0f16;

sc = (signed char)fl16_var;
usc = (unsigned char)fl16_var;
s = (short)fl16_var;
us = (unsigned short)fl16_var;
i = (int)fl16_var;
ui = (unsigned int)fl16_var;
l = (long)fl16_var;
ul = (unsigned long)fl16_var;
ll = (long long)fl16_var;
ull = (unsigned long long)fl16_var;
f = (float)fl16_var;
d = (double)fl16_var;
ld = (long double)fl16_var;

sc = (signed char)3;
fl16_var = (_Float16)sc;

usc = (unsigned char)3;
fl16_var = (_Float16)usc;

s = (short)3;
fl16_var = (_Float16)s;

us = (unsigned short)3;
fl16_var = (_Float16)us;

i = (int)3;
fl16_var = (_Float16)i;

ui = (unsigned int)3;
fl16_var = (_Float16)ui;

l = (long)3;
fl16_var = (_Float16)l;

ul = (unsigned long)3;
fl16_var = (_Float16)ul;

ll = (long long)3;
fl16_var = (_Float16)ll;

ull = (unsigned long long)3;
fl16_var = (_Float16)ull;

f = (float)3.0f;
fl16_var = (_Float16)f;

d = (double)3.0;
fl16_var = (_Float16)d;

ld = (long double)3.0l;
fl16_var = (_Float16)ld;

done:
exit(ret);
}

#endif

#ifdef H5_LDOUBLE_TO_FLOAT16_CORRECT_TEST

#define __STDC_WANT_IEC_60559_TYPES_EXT__

#include <stdlib.h>
#include <float.h>
#include <math.h>
#include <limits.h>

int HDF_NO_UBSAN main(void)
{
long double ld;
_Float16 half;
int ret = 1;

ld = 32.0L;
half = 64.0f16;

half = (_Float16)ld;

if (fabsl(ld - (long double)half) < LDBL_EPSILON)
ret = 0;

done:
exit(ret);
}

#endif
12 changes: 12 additions & 0 deletions config/cmake/H5pubconf.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@
/* Define if library information should be embedded in the executables */
#cmakedefine H5_HAVE_EMBEDDED_LIBINFO @H5_HAVE_EMBEDDED_LIBINFO@

/* Define to 1 if you have the `fabsf16' function. */
#cmakedefine H5_HAVE_FABSF16 @H5_HAVE_FABSF16@

/* Define to 1 if you have the `fcntl' function. */
#cmakedefine H5_HAVE_FCNTL @H5_HAVE_FCNTL@

Expand All @@ -140,6 +143,9 @@
/* Define if support for szip filter is enabled */
#cmakedefine H5_HAVE_FILTER_SZIP @H5_HAVE_FILTER_SZIP@

/* Determine if _Float16 is available */
#cmakedefine H5_HAVE__FLOAT16 @H5_HAVE__FLOAT16@

/* Determine if __float128 is available */
#cmakedefine H5_HAVE_FLOAT128 @H5_HAVE_FLOAT128@

Expand Down Expand Up @@ -387,6 +393,9 @@
/* Define if new-style references should be used with dimension scales */
#cmakedefine H5_DIMENSION_SCALES_WITH_NEW_REF @H5_DIMENSION_SCALES_WITH_NEW_REF@

/* Define if your system can convert long double to _Float16 values correctly. */
#cmakedefine H5_LDOUBLE_TO_FLOAT16_CORRECT @H5_LDOUBLE_TO_FLOAT16_CORRECT@

/* Define if your system can convert long double to (unsigned) long long
values correctly. */
#cmakedefine H5_LDOUBLE_TO_LLONG_ACCURATE @H5_LDOUBLE_TO_LLONG_ACCURATE@
Expand Down Expand Up @@ -592,6 +601,9 @@
/* The size of `_Quad', as computed by sizeof. */
#define H5_SIZEOF__QUAD @H5_SIZEOF__QUAD@

/* The size of `_Float16', as computed by sizeof. */
#define H5_SIZEOF__FLOAT16 @H5_SIZEOF__FLOAT16@

/* The size of `__float128', as computed by sizeof. */
#define H5_SIZEOF___FLOAT128 @H5_SIZEOF___FLOAT128@

Expand Down
103 changes: 103 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,109 @@ AC_CHECK_SIZEOF([float])
AC_CHECK_SIZEOF([double])
AC_CHECK_SIZEOF([long double])

## ----------------------------------------------------------------------
## Check if _Float16 support is available
##
AC_MSG_NOTICE([checking if _Float16 support is available])
HAVE__FLOAT16="no"
AC_CHECK_SIZEOF([_Float16])
if test "$ac_cv_sizeof__Float16" != 0; then
# Some compilers expose the _Float16 datatype, but not the macros and
# functions used with the datatype. We need the macros for proper
# datatype conversion support. Check for these here.
AC_CHECK_DECL([FLT16_EPSILON], [], [], [[
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h>]])
AC_CHECK_DECL([FLT16_MIN], [], [], [[
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h>]])
AC_CHECK_DECL([FLT16_MAX], [], [], [[
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h>]])
AC_CHECK_DECL([FLT16_MIN_10_EXP], [], [], [[
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h>]])
AC_CHECK_DECL([FLT16_MAX_10_EXP], [], [], [[
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h>]])
AC_CHECK_DECL([FLT16_MANT_DIG], [], [], [[
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h>]])

if test "X$ac_cv_have_decl_FLT16_EPSILON" = "Xyes" &&
test "X$ac_cv_have_decl_FLT16_MIN" = "Xyes" &&
test "X$ac_cv_have_decl_FLT16_MAX" = "Xyes" &&
test "X$ac_cv_have_decl_FLT16_MIN_10_EXP" = "Xyes" &&
test "X$ac_cv_have_decl_FLT16_MAX_10_EXP" = "Xyes" &&
test "X$ac_cv_have_decl_FLT16_MANT_DIG" = "Xyes" ; then
# Some compilers like OneAPI on Windows appear to detect _Float16 support
# properly up to this point, and, in the absence of any architecture-specific
# tuning compiler flags, will generate code for H5Tconv.c that performs
# software conversions on _Float16 variables with compiler-internal functions
# such as __extendhfsf2, __truncsfhf2, or __truncdfhf2. However, these
# compilers will fail to link these functions into the build for currently
# unknown reasons and cause the build to fail. Since these are compiler-internal
# functions that we don't appear to have much control over, let's try to
# compile a program that will generate these functions to check for _Float16
# support. If we fail to compile this program, we will simply disable
# _Float16 support for the time being.
AC_MSG_CHECKING([if compiler can correctly compile and run a test program which converts _Float16 to other types with casts])
TEST_SRC="`(echo \"#define H5_FLOAT16_CONVERSION_FUNCS_LINK_TEST 1\"; cat $srcdir/config/cmake/ConversionTests.c)`"
AC_CACHE_VAL([hdf5_cv_float16_conversion_funcs_link],
[AC_RUN_IFELSE(
[AC_LANG_SOURCE([$TEST_SRC])],
[hdf5_cv_float16_conversion_funcs_link=yes], [hdf5_cv_float16_conversion_funcs_link=no], [hdf5_cv_float16_conversion_funcs_link=no])])

if test ${hdf5_cv_float16_conversion_funcs_link} = "yes"; then
AC_MSG_RESULT([yes])

# Finally, MacOS 13 appears to have a bug specifically when converting
# long double values to _Float16. Release builds of the dt_arith test
# would cause any assignments to a _Float16 variable to be elided,
# whereas Debug builds would perform incorrect hardware conversions by
# simply chopping off all the bytes of the value except for the first 2.
# These tests pass on MacOS 14, so let's perform a quick test to check
# if the hardware conversion is done correctly.
AC_MSG_CHECKING([if compiler can correctly convert long double values to _Float16])
TEST_SRC="`(echo \"#define H5_LDOUBLE_TO_FLOAT16_CORRECT_TEST 1\"; cat $srcdir/config/cmake/ConversionTests.c)`"
if test ${ac_cv_sizeof_long_double} = 0; then
hdf5_cv_ldouble_to_float16_correct=${hdf5_cv_ldouble_to_float16_correct=no}
else
AC_CACHE_VAL([hdf5_cv_ldouble_to_float16_correct],
[AC_RUN_IFELSE(
[AC_LANG_SOURCE([$TEST_SRC])],
[hdf5_cv_ldouble_to_float16_correct=yes], [hdf5_cv_ldouble_to_float16_correct=no], [hdf5_cv_ldouble_to_float16_correct=yes])])
fi

if test ${hdf5_cv_ldouble_to_float16_correct} = "yes"; then
AC_DEFINE([LDOUBLE_TO_FLOAT16_CORRECT], [1],
[Define if your system can convert long double to _Float16 values correctly.])
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
AC_MSG_NOTICE([Conversions from long double to _Float16 appear to be incorrect. These will be emulated through a soft conversion function.])
fi

HAVE__FLOAT16="yes"

# Check if we can use fabsf16
AC_CHECK_FUNC([fabsf16], [AC_DEFINE([HAVE_FABSF16], [1],
[Define if has fabsf16 function])], [])

# Define HAVE__FLOAT16 macro for H5pubconf.h if _Float16 is available.
AC_DEFINE([HAVE__FLOAT16], [1], [Determine if _Float16 is available])
else
AC_MSG_RESULT([no])
fi
fi

AC_MSG_CHECKING([if _Float16 support is enabled])
AC_MSG_RESULT([$HAVE__FLOAT16])
fi

# Define HAVE__FLOAT16 value to substitute into other files for conditional testing
AC_SUBST([HAVE__FLOAT16])

## ----------------------------------------------------------------------
## Check if the Fortran interface should be enabled
##
Expand Down
5 changes: 5 additions & 0 deletions doxygen/dox/LearnBasics2.dox
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,11 @@ into a long integer buffer.)
<th span="3"><strong>Float</strong></th>
</tr>
<tr>
<td>_Float16</td>
<td>#H5T_NATIVE_FLOAT16</td>
<td>#H5T_IEEE_F16BE or #H5T_IEEE_F16LE</td>
</tr>
<tr>
<td>float</td>
<td>#H5T_NATIVE_FLOAT</td>
<td>#H5T_IEEE_F32BE or #H5T_IEEE_F32LE</td>
Expand Down
Loading
Loading