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 6 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
1 change: 0 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,3 @@ jobs:
name: "CMake Workflows"
uses: ./.github/workflows/cmake.yml
if: "!contains(github.event.head_commit.message, 'skip-ci')"

74 changes: 71 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,67 @@ 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
#-----------------------------------------------------------------------------
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. The main function we're interested in
# is fabsf16. 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 MSVC appear to just be broken, as support
# for _Float16 and its macros can be detected properly, but then code is
# generated that uses the __truncsfhf2, __truncdfhf2, __extendhfsf2 functions,
# which end up being unresolved with MSVC. Let's try to compile a program
# that will generate these functions to check for _Float16 support.
message (STATUS "Compiling test program to check for _Float16 support")
try_compile (
h5_compiled_float16_test
${CMAKE_BINARY_DIR}
${HDF_RESOURCES_DIR}/HDFTests.c
COMPILE_DEFINITIONS "-DCHECK_FLOAT16"
C_STANDARD 99
)

if (${h5_compiled_float16_test})
# 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"
)

set (${HDF_PREFIX}_HAVE__FLOAT16 1)

# Check if we can use fabsf16
CHECK_FUNCTION_EXISTS (fabsf16 ${HDF_PREFIX}_HAVE_FABSF16)
else ()
message (STATUS "Failed to compile test program to check for _Float16 support")
endif ()
else ()
set (${HDF_PREFIX}_HAVE__FLOAT16 0)
endif ()
else ()
set (${HDF_PREFIX}_HAVE__FLOAT16 0)
endif ()
29 changes: 29 additions & 0 deletions config/cmake/ConversionTests.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,32 @@ int HDF_NO_UBSAN main(void)
}

#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
33 changes: 33 additions & 0 deletions config/cmake/HDFTests.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,36 @@ int main ()
}

#endif /* HAVE_IOEO */

#ifdef CHECK_FLOAT16

#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h>

int
main(int argc, char **argv)
{
signed char a;
_Float16 b;
double c;

/* Convert signed char to _Float16 */
a = 1;
b = (_Float16)a;

/* Convert back */
b = 3.0f16;
a = (signed char)b;

/* Convert double to _Float16 */
c = 5.0;
b = (_Float16)c;

/* Convert back */
b = 3.0f16;
c = (double)b;

return 0;
}

#endif /* CHECK_FLOAT16 */
114 changes: 114 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,120 @@ AC_CHECK_SIZEOF([float])
AC_CHECK_SIZEOF([double])
AC_CHECK_SIZEOF([long double])

## ----------------------------------------------------------------------
## Check 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. The main function we're interested in
# is fabsf16. 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 MSVC appear to just be broken, as support
# for _Float16 and its macros can be detected properly, but then code is
# generated that uses the __truncsfhf2, __truncdfhf2, __extendhfsf2 functions,
# which end up being unresolved with MSVC. Let's try to compile a program
# that will generate these functions to check for _Float16 support.
AC_MSG_CHECKING([if _Float16 program can be compiled])
AC_CACHE_VAL([hdf5_cv_float16_prog_compiled],
[AC_RUN_IFELSE(
[AC_LANG_PROGRAM([
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h>
],[
signed char a;
_Float16 b;
double c;
/* Convert signed char to _Float16 */
a = 1;
b = (_Float16)a;
/* Convert back */
b = 3.0f16;
a = (signed char)b;
/* Convert double to _Float16 */
c = 5.0;
b = (_Float16)c;
/* Convert back */
b = 3.0f16;
c = (double)b;
])]
, [hdf5_cv_float16_prog_compiled=yes], [hdf5_cv_float16_prog_compiled=no], [hdf5_cv_float16_prog_compiled=no])])

if test ${hdf5_cv_float16_prog_compiled} = "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])
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 available])
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
12 changes: 12 additions & 0 deletions doxygen/examples/tables/predefinedDatatypes.dox
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@
<th>Description</th>
</tr>
<tr>
<td>#H5T_IEEE_F16BE</td>
<td>16-bit big-endian IEEE floating point</td>
</tr>
<tr>
<td>#H5T_IEEE_F16LE</td>
<td>16-bit little-endian IEEE floating point</td>
</tr>
<tr>
<td>#H5T_IEEE_F32BE</td>
<td>32-bit big-endian IEEE floating point</td>
</tr>
Expand Down Expand Up @@ -465,6 +473,10 @@
<td>C-style unsigned long long</td>
</tr>
<tr>
<td>#H5T_NATIVE_FLOAT16</td>
<td>C-style _Float16 (May be H5I_INVALID_HID if platform doesn't support _Float16 type)</td>
</tr>
<tr>
<td>#H5T_NATIVE_FLOAT</td>
<td>C-style float</td>
</tr>
Expand Down
13 changes: 12 additions & 1 deletion hl/src/H5LT.c
Original file line number Diff line number Diff line change
Expand Up @@ -2287,7 +2287,13 @@ H5LT_dtype_to_text(hid_t dtype, char *dt_str, H5LT_lang_t lang, size_t *slen, bo

break;
case H5T_FLOAT:
if (H5Tequal(dtype, H5T_IEEE_F32BE)) {
if (H5Tequal(dtype, H5T_IEEE_F16BE)) {
snprintf(dt_str, *slen, "H5T_IEEE_F16BE");
}
else if (H5Tequal(dtype, H5T_IEEE_F16LE)) {
snprintf(dt_str, *slen, "H5T_IEEE_F16LE");
}
else if (H5Tequal(dtype, H5T_IEEE_F32BE)) {
snprintf(dt_str, *slen, "H5T_IEEE_F32BE");
}
else if (H5Tequal(dtype, H5T_IEEE_F32LE)) {
Expand All @@ -2299,6 +2305,11 @@ H5LT_dtype_to_text(hid_t dtype, char *dt_str, H5LT_lang_t lang, size_t *slen, bo
else if (H5Tequal(dtype, H5T_IEEE_F64LE)) {
snprintf(dt_str, *slen, "H5T_IEEE_F64LE");
}
#ifdef H5_HAVE__FLOAT16
else if (H5Tequal(dtype, H5T_NATIVE_FLOAT16)) {
snprintf(dt_str, *slen, "H5T_NATIVE_FLOAT16");
}
#endif
else if (H5Tequal(dtype, H5T_NATIVE_FLOAT)) {
snprintf(dt_str, *slen, "H5T_NATIVE_FLOAT");
}
Expand Down
Loading
Loading