summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJordan Henderson <jhenderson@hdfgroup.org>2024-03-01 23:20:49 (GMT)
committerJordan Henderson <jhenderson@hdfgroup.org>2024-03-01 23:30:49 (GMT)
commit6965049700fa367d0cfe6fba211bac0ff53263ba (patch)
tree5a5305f3cae380a1619ce76003e62efc031d22e0 /src
parenta793f30e2c5885d92d31484dc3d7319374c4d58b (diff)
downloadhdf5-6965049700fa367d0cfe6fba211bac0ff53263ba.zip
hdf5-6965049700fa367d0cfe6fba211bac0ff53263ba.tar.gz
hdf5-6965049700fa367d0cfe6fba211bac0ff53263ba.tar.bz2
Fixed some _Float16 support issues
Fixed some conversion issues with Clang due to problematic undefined behavior when casting a negative floating-point value to an integer Fixed a bug in the library's software integer to floating-point conversion function where a user's conversion exception function returning H5T_CONV_UNHANDLED in the case of overflows would result in incorrect data after conversion Added configure checks for functions and macros related to _Float16 usage since some compilers expose the datatype but not the functions or macros Fixed a dt_arith test failure when H5_WANT_DCONV_EXCEPTION isn't defined Fixed a few warnings from not explicitly casting some _Float16 variables upwards
Diffstat (limited to 'src')
-rw-r--r--src/H5Tconv.c35
-rw-r--r--src/H5private.h30
2 files changed, 52 insertions, 13 deletions
diff --git a/src/H5Tconv.c b/src/H5Tconv.c
index 33852a9..d1cc307 100644
--- a/src/H5Tconv.c
+++ b/src/H5Tconv.c
@@ -753,14 +753,38 @@
{ \
if (*(S) > (ST)(D_MAX)) \
*(D) = H5_GLUE3(H5T_NATIVE_, DTYPE, _POS_INF_g); \
- else if (*(S) < (ST)(D_MIN)) \
- *(D) = H5_GLUE3(H5T_NATIVE_, DTYPE, _NEG_INF_g); \
- else \
- *(D) = (DT)(*(S)); \
+ else { \
+ intmax_t s_cast = (intmax_t)(*(S)); \
+ intmax_t d_cast = (intmax_t)(D_MAX); \
+ \
+ /* Check if source value would underflow destination. Do NOT do this \
+ * by comparing against D_MIN casted to type ST here, as this will \
+ * generally be undefined behavior (casting negative float value <= 1.0 \
+ * to integer) for all floating point types and some compilers optimize \
+ * this in a way that causes unexpected behavior. Instead, grab the \
+ * absolute value of the source value first, then compare it to D_MAX. \
+ */ \
+ if (s_cast != INTMAX_MIN) \
+ s_cast = imaxabs(s_cast); \
+ else { \
+ /* Handle two's complement integer representations where abs(INTMAX_MIN) \
+ * can't be represented. Other representations will fall here as well, \
+ * but this should be fine. \
+ */ \
+ s_cast = INTMAX_MAX; \
+ d_cast -= 1; \
+ } \
+ \
+ if (s_cast > d_cast) \
+ *(D) = H5_GLUE3(H5T_NATIVE_, DTYPE, _NEG_INF_g); \
+ else \
+ *(D) = (DT)(*(S)); \
+ } \
}
#define H5T_CONV_Xf(STYPE, DTYPE, ST, DT, D_MIN, D_MAX) \
do { \
+ HDcompile_assert(sizeof(ST) >= sizeof(DT)); \
H5T_CONV(H5T_CONV_Xf, STYPE, DTYPE, ST, DT, D_MIN, D_MAX, Y) \
} while (0)
@@ -9141,7 +9165,8 @@ H5T__conv_i_f(hid_t src_id, hid_t dst_id, H5T_cdata_t *cdata, size_t nelmts, siz
goto padding;
}
}
- else {
+
+ if (!cb_struct.func || (except_ret == H5T_CONV_UNHANDLED)) {
/*make destination infinity by setting exponent to maximal number and
*mantissa to zero.*/
expo = expo_max;
diff --git a/src/H5private.h b/src/H5private.h
index 0cbda2e..e47dbb3 100644
--- a/src/H5private.h
+++ b/src/H5private.h
@@ -27,7 +27,6 @@
#include <errno.h>
#include <fcntl.h>
#include <fenv.h>
-#include <math.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
@@ -38,6 +37,7 @@
/* Define __STDC_WANT_IEC_60559_TYPES_EXT__ for _FloatN support, if available */
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h>
+#include <math.h>
/* POSIX headers */
#ifdef H5_HAVE_SYS_TIME_H
@@ -462,10 +462,26 @@
#define H5_DBL_ABS_EQUAL(X, Y) (fabs((X) - (Y)) < DBL_EPSILON)
#define H5_LDBL_ABS_EQUAL(X, Y) (fabsl((X) - (Y)) < LDBL_EPSILON)
+#ifdef H5_HAVE__FLOAT16
+#ifdef H5_HAVE_FABSF16
+#define H5_FLT16_ABS_EQUAL(X, Y) (fabsf16((X) - (Y)) < FLT16_EPSILON)
+#else
+#define H5_FLT16_ABS_EQUAL(X, Y) H5_FLT_ABS_EQUAL((float)X, (float)Y)
+#endif
+#endif
+
#define H5_FLT_REL_EQUAL(X, Y, M) (fabsf(((Y) - (X)) / (X)) < (M))
#define H5_DBL_REL_EQUAL(X, Y, M) (fabs(((Y) - (X)) / (X)) < (M))
#define H5_LDBL_REL_EQUAL(X, Y, M) (fabsl(((Y) - (X)) / (X)) < (M))
+#ifdef H5_HAVE__FLOAT16
+#ifdef H5_HAVE_FABSF16
+#define H5_FLT16_REL_EQUAL(X, Y, M) (fabsf16(((Y) - (X)) / (X)) < (M))
+#else
+#define H5_FLT16_REL_EQUAL(X, Y, M) H5_FLT_REL_EQUAL((float)X, (float)Y, M)
+#endif
+#endif
+
/* KiB, MiB, GiB, TiB, PiB, EiB - Used in profiling and timing code */
#define H5_KB (1024.0F)
#define H5_MB (1024.0F * 1024.0F)
@@ -543,16 +559,14 @@
#define H5_GCC_CLANG_DIAG_ON(x)
#endif
-/* Create a typedef for library usage of the _Float16 type
- * to avoid issues when compiling the library with the
- * -pedantic flag or similar where we get warnings about
- * _Float16 not being an ISO C type.
+/* If necessary, create a typedef for library usage of the
+ * _Float16 type to avoid issues when compiling the library
+ * with the -pedantic flag or similar where we get warnings
+ * about _Float16 not being an ISO C type.
*/
#ifdef H5_HAVE__FLOAT16
#if defined(__GNUC__)
__extension__ typedef _Float16 H5__Float16;
-#elif defined(__clang__)
-/* TODO */
#else
typedef _Float16 H5__Float16;
#endif
@@ -893,7 +907,7 @@ H5_DLL H5_ATTR_CONST int Nflock(int fd, int operation);
#ifdef H5_HAVE_VASPRINTF
#define HDvasprintf(RET, FMT, A) vasprintf(RET, FMT, A)
#else
-H5_DLL int HDvasprintf(char **bufp, const char *fmt, va_list _ap);
+H5_DLL int HDvasprintf(char **bufp, const char *fmt, va_list _ap);
#endif
#endif