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

Clean up Fortran __float128 configure-time checks #4649

Merged
merged 13 commits into from
Jul 15, 2024
102 changes: 60 additions & 42 deletions config/cmake/ConfigureChecks.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,15 @@ endif ()

## Check for non-standard extension quadmath.h

CHECK_INCLUDE_FILES(quadmath.h C_HAVE_QUADMATH)
if (C_HAVE_QUADMATH)
set(${HDF_PREFIX}_HAVE_QUADMATH_H 1)
# gcc puts symbols like FLT128_DIG in quadmath.h instead of float.h, so
# check for that. This is only used by the build system and doesn't need
# to be exported to H5pubconf.h.
CHECK_INCLUDE_FILES("quadmath.h" INCLUDE_QUADMATH_H)
# Convert TRUE/FALSE to 0/1 for preprocessor values in test code, below
if (${INCLUDE_QUADMATH_H})
set(C_INCLUDE_QUADMATH_H 1)
else ()
set(${HDF_PREFIX}_HAVE_QUADMATH_H 0)
set(C_INCLUDE_QUADMATH_H 0)
endif ()

if (CYGWIN)
Expand Down Expand Up @@ -646,22 +650,38 @@ endif()
#-----------------------------------------------------------------------------

if (HDF5_BUILD_FORTRAN)
HDF_CHECK_TYPE_SIZE(__float128 _SIZEOF___FLOAT128)
if (_SIZEOF___FLOAT128)
set (${HDF_PREFIX}_HAVE_FLOAT128 1)
set (${HDF_PREFIX}_SIZEOF___FLOAT128 ${_SIZEOF___FLOAT128})
else ()
set (${HDF_PREFIX}_HAVE_FLOAT128 0)
set (${HDF_PREFIX}_SIZEOF___FLOAT128 0)
endif ()
# ----------------------------------------------------------------------
# __float128 checks
#
# If __float128 exists and we can determine its precision, we will use
# it in the Fortran interface. The checks for this require that the
# precision be specified via a symbol named FLT128_DIG, which might be
# found in quadmath.h.
#
# The checks here are based on the GNU __float128 extension type from
# libquadmath, which is now part of gcc. Other compilers (clang, Intel)
# also expose __float128 and/or __float128 may be an alias for some
# other 128-bit floating point type.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sentence above and also in configure.ac might be worth clarifying; I think I understand it's related to the first paragraph in the comment, but only after having read through all of the PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to go over this code with Scot when he gets back. We can revise then.

#
# 128-bit floating-point math is usually handled in software and is thus
# orders of magnitude slower than hardware-supported floating-point math.
#

HDF_CHECK_TYPE_SIZE(_Quad _SIZEOF__QUAD)
if (NOT _SIZEOF__QUAD)
set (${HDF_PREFIX}_SIZEOF__QUAD 0)
#-----------------------------------------------------------------------------
# Is the __float128 type available?
#-----------------------------------------------------------------------------
HDF_FUNCTION_TEST (HAVE___FLOAT128)
# Convert TRUE/FALSE to 0/1 for preprocessor values in test code, below
if (${HAVE___FLOAT128})
set(C_HAVE_FLOAT128 1)
else ()
set (${HDF_PREFIX}_SIZEOF__QUAD ${_SIZEOF__QUAD})
set(C_HAVE_FLOAT128 0)
endif ()

#-----------------------------------------------------------------------------
# Get the max decimal precision in C, checking both long double and
# __float128 (if available)
#-----------------------------------------------------------------------------
if (NOT CMAKE_CROSSCOMPILING)
#-----------------------------------------------------------------------------
# The provided CMake C macros don't provide a general compile/run function
Expand All @@ -682,7 +702,6 @@ if (HDF5_BUILD_FORTRAN)
TRY_RUN (RUN_RESULT_VAR COMPILE_RESULT_VAR
${CMAKE_BINARY_DIR}
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testCCompiler1.c
COMPILE_DEFINITIONS "-D_SIZEOF___FLOAT128=${H5_SIZEOF___FLOAT128};-D_HAVE_QUADMATH_H=${H5_HAVE_QUADMATH_H}"
COMPILE_OUTPUT_VARIABLE COMPILEOUT
${_RUN_OUTPUT_VARIABLE} OUTPUT_VAR
)
Expand Down Expand Up @@ -719,43 +738,42 @@ if (HDF5_BUILD_FORTRAN)
"
#include <float.h>\n\
#include <stdio.h>\n\
#define CHECK_FLOAT128 _SIZEOF___FLOAT128\n\
#if CHECK_FLOAT128!=0\n\
#if _HAVE_QUADMATH_H!=0\n\
#include <quadmath.h>\n\
#endif\n\
#ifdef FLT128_DIG\n\
#define C_FLT128_DIG FLT128_DIG\n\
#else\n\
#define C_FLT128_DIG 0\n\
#endif\n\
#if ${C_HAVE_FLOAT128}\n\
# if ${C_INCLUDE_QUADMATH_H}\n\
# include <quadmath.h>\n\
# endif\n\
# ifdef FLT128_DIG\n\
# define C_FLT128_DIG FLT128_DIG\n\
# else\n\
# define C_FLT128_DIG 0\n\
# endif\n\
#else\n\
#define C_FLT128_DIG 0\n\
# define C_FLT128_DIG 0\n\
#endif\n\
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L\n\
#define C_LDBL_DIG DECIMAL_DIG\n\
#else\n\
#define C_LDBL_DIG LDBL_DIG\n\
#endif\n\nint main(void) {\nprintf(\"\\%d\\\;\\%d\\\;\", C_LDBL_DIG, C_FLT128_DIG)\\\;\n\nreturn 0\\\;\n}\n
"
\n\
int main(void) {\nprintf(\"\\%d\\\;\\%d\\\;\", C_LDBL_DIG, C_FLT128_DIG)\\\;\n\nreturn 0\\\;\n}\n
"
)

C_RUN ("maximum decimal precision for C" ${PROG_SRC} PROG_RES PROG_OUTPUT4)
message (STATUS "Testing maximum decimal precision for C - ${PROG_OUTPUT4}")

# dnl The output from the above program will be:
# dnl -- long double decimal precision -- __float128 decimal precision
# The output from the above program will be:
# -- long double decimal precision -- __float128 decimal precision

list (GET PROG_OUTPUT4 0 H5_LDBL_DIG)
list (GET PROG_OUTPUT4 1 H5_FLT128_DIG)
list (GET PROG_OUTPUT4 0 MY_LDBL_DIG)
list (GET PROG_OUTPUT4 1 MY_FLT128_DIG)

if (${HDF_PREFIX}_SIZEOF___FLOAT128 EQUAL "0" OR FLT128_DIG EQUAL "0")
set (${HDF_PREFIX}_HAVE_FLOAT128 0)
set (${HDF_PREFIX}_SIZEOF___FLOAT128 0)
set (_PAC_C_MAX_REAL_PRECISION ${H5_LDBL_DIG})
# Set configure output and behavior
if (${HAVE___FLOAT128} AND (${MY_FLT128_DIG} GREATER ${MY_LDBL_DIG}))
set (${HDF_PREFIX}_HAVE_FLOAT128 1)
set (_PAC_C_MAX_REAL_PRECISION ${MY_FLT128_DIG})
else ()
set (_PAC_C_MAX_REAL_PRECISION ${H5_FLT128_DIG})
# No __float128 or the precision of __float128 <= that of long double
set (_PAC_C_MAX_REAL_PRECISION ${MY_LDBL_DIG})
endif ()

if (NOT ${_PAC_C_MAX_REAL_PRECISION})
set (${HDF_PREFIX}_PAC_C_MAX_REAL_PRECISION 0)
else ()
Expand Down
11 changes: 1 addition & 10 deletions config/cmake/H5pubconf.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@
/* Determine if _Float16 is available */
#cmakedefine H5_HAVE__FLOAT16 @H5_HAVE__FLOAT16@

/* Determine if __float128 is available */
/* Determine if __float128 will be used in the Fortran wrappers */
#cmakedefine H5_HAVE_FLOAT128 @H5_HAVE_FLOAT128@

/* Define to 1 if you have the `flock' function. */
Expand Down Expand Up @@ -270,9 +270,6 @@
/* Define to 1 if you have the <pwd.h> header file. */
#cmakedefine H5_HAVE_PWD_H @H5_HAVE_PWD_H@

/* Define to 1 if you have the <quadmath.h> header file. */
#cmakedefine H5_HAVE_QUADMATH_H @H5_HAVE_QUADMATH_H@

/* Define whether the Read-Only S3 virtual file driver (VFD) should be
compiled */
#cmakedefine H5_HAVE_ROS3_VFD @H5_HAVE_ROS3_VFD@
Expand Down Expand Up @@ -586,15 +583,9 @@
/* The size of `unsigned', as computed by sizeof. */
#cmakedefine H5_SIZEOF_UNSIGNED @H5_SIZEOF_UNSIGNED@

/* 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@

/* Define if strict file format checks are enabled */
#cmakedefine H5_STRICT_FORMAT_CHECKS @H5_STRICT_FORMAT_CHECKS@

Expand Down
23 changes: 11 additions & 12 deletions config/cmake/HDF5UseFortran.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -363,13 +363,13 @@ set (PROG_SRC3
"
)
FORTRAN_RUN ("SIZEOF NATIVE KINDs" ${PROG_SRC3} XX YY PAC_SIZEOF_NATIVE_KINDS_RESULT PROG_OUTPUT3)
# dnl The output from the above program will be:
# dnl -- LINE 1 -- sizeof INTEGER
# dnl -- LINE 2 -- kind of INTEGER
# dnl -- LINE 3 -- sizeof REAL
# dnl -- LINE 4 -- kind of REAL
# dnl -- LINE 5 -- sizeof DOUBLE PRECISION
# dnl -- LINE 6 -- kind of DOUBLE PRECISION
# The output from the above program will be:
# -- LINE 1 -- sizeof INTEGER
# -- LINE 2 -- kind of INTEGER
# -- LINE 3 -- sizeof REAL
# -- LINE 4 -- kind of REAL
# -- LINE 5 -- sizeof DOUBLE PRECISION
# -- LINE 6 -- kind of DOUBLE PRECISION
#
# Convert the string to a list of strings by replacing the carriage return with a semicolon
string (REGEX REPLACE "[\r\n]+" ";" PROG_OUTPUT3 "${PROG_OUTPUT3}")
Expand Down Expand Up @@ -402,11 +402,10 @@ endif ()

set (${HDF_PREFIX}_FORTRAN_SIZEOF_LONG_DOUBLE ${${HDF_PREFIX}_SIZEOF_LONG_DOUBLE})

# remove the invalid kind from the list
if (NOT(${${HDF_PREFIX}_SIZEOF___FLOAT128} EQUAL 0))
if (NOT(${${HDF_PREFIX}_SIZEOF___FLOAT128} EQUAL ${max_real_fortran_sizeof})
AND NOT(${${HDF_PREFIX}_FORTRAN_SIZEOF_LONG_DOUBLE} EQUAL ${max_real_fortran_sizeof})
# account for the fact that the C compiler can have 16-byte __float128 and the fortran compiler only has 8-byte doubles,
# Remove the invalid kind from the list
if (${${HDF_PREFIX}_HAVE_FLOAT128})
if (NOT(16 EQUAL ${max_real_fortran_sizeof}) AND NOT(${${HDF_PREFIX}_FORTRAN_SIZEOF_LONG_DOUBLE} EQUAL ${max_real_fortran_sizeof})
# Account for the fact that the C compiler can have 16-byte __float128 and the fortran compiler only has 8-byte doubles,
# so we don't want to remove the 8-byte fortran doubles.
AND NOT(${PAC_FORTRAN_NATIVE_DOUBLE_SIZEOF} EQUAL ${max_real_fortran_sizeof}))
message (WARNING "
Expand Down
12 changes: 12 additions & 0 deletions config/cmake/HDFTests.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@
/* A simple test program to see if a function "works" */
#define SIMPLE_TEST(x) int main(void){ x; return 0; }

#ifdef HAVE___FLOAT128

/* Check if __float128 works (only used in the Fortran interface) */
int
main ()
{
__float128 x;

return 0;
}

#endif /* HAVE___FLOAT128 */

#ifdef HAVE_BUILTIN_EXPECT

Expand Down
88 changes: 67 additions & 21 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -793,41 +793,87 @@ AC_MSG_RESULT([$HDF_FORTRAN])

if test "X$HDF_FORTRAN" = "Xyes"; then

## ----------------------------------------------------------------------
## Check for non-standard extension __FLOAT128
##
HAVE_FLOAT128=0
HAVE_QUADMATH=0
FLT128_DIG=0
LDBL_DIG=0

AC_CHECK_SIZEOF([__float128])
AC_CHECK_SIZEOF([_Quad])
AC_CHECK_HEADERS([quadmath.h], [HAVE_QUADMATH=1], [])
## ----------------------------------------------------------------------
## __float128 checks
##
## If __float128 exists and we can determine its precision, we will use
## it in the Fortran interface. The checks for this require that the
## precision be specified via a symbol named FLT128_DIG, which might be
## found in quadmath.h.
##
## The checks here are based on the GNU __float128 extension type from
## libquadmath, which is now part of gcc. Other compilers (clang, Intel)
## also expose __float128 and/or __float128 may be an alias for some
## other 128-bit floating point type.
##
## 128-bit floating-point math is usually handled in software and is thus
## orders of magnitude slower than hardware-supported floating-point math.
##
AC_MSG_CHECKING([if __float128 exists])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],[[__float128 x; return 0;]])],
[HAVE___FLOAT128=1; AC_MSG_RESULT([yes])],
[HAVE___FLOAT128=0; AC_MSG_RESULT([no])]
)

## gcc puts symbols like FLT128_DIG in quadmath.h instead of float.h,
## so check for that before running the precision macro. Note that
## using AC_CHECK_HEADER instead of AC_CHECK_HEADERS keeps the
## H5_HAVE_QUADMATH_H symbol out of the public config header.
##
AC_CHECK_HEADER([quadmath.h], [INCLUDE_QUADMATH_H=1], [INCLUDE_QUADMATH_H=0])

## ----------------------------------------------------------------------
## Get the max decimal precision in C, checking both long double and
## __float128 (if available)
##
AC_MSG_CHECKING([maximum decimal precision for C])

MY_FLT128_DIG=0
MY_LDBL_DIG=0

## Macro to compare long double and __float128 to see which has higher precision
PAC_FC_LDBL_DIG

## Set results
if test "$MY_FLT128_DIG" -gt "$MY_LDBL_DIG" ; then
PAC_C_MAX_REAL_PRECISION=$MY_FLT128_DIG
PRECISION_TYPE="(__float128)"
else
PAC_C_MAX_REAL_PRECISION=$MY_LDBL_DIG
PRECISION_TYPE="(long double)"
fi
AC_MSG_RESULT([$PAC_C_MAX_REAL_PRECISION $PRECISION_TYPE])

## Store results in config file
AC_SUBST([PAC_C_MAX_REAL_PRECISION])
AC_DEFINE_UNQUOTED([PAC_C_MAX_REAL_PRECISION], $PAC_C_MAX_REAL_PRECISION, [Determine the maximum decimal precision in C])

## Are we going to use __float128?
AC_MSG_CHECKING([if __float128 will be used in the Fortran wrappers])

if test "$ac_cv_sizeof___float128" != 0 && test "$FLT128_DIG" != 0 ; then
AC_DEFINE([HAVE_FLOAT128], [1], [Determine if __float128 is available])
PAC_C_MAX_REAL_PRECISION=$FLT128_DIG
if test "$MY_FLT128_DIG" -gt "$MY_LDBL_DIG" ; then
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_FLOAT128], [1], [Determine if __float128 will be used in the Fortran wrappers])
else
PAC_C_MAX_REAL_PRECISION=$LDBL_DIG
## Can't use __float128, but write an undef line anyway
AC_MSG_RESULT([no])
AH_TEMPLATE([HAVE_FLOAT128], [Determine if __float128 will be used in the Fortran wrappers])
fi
AC_DEFINE_UNQUOTED([PAC_C_MAX_REAL_PRECISION], $PAC_C_MAX_REAL_PRECISION, [Determine the maximum decimal precision in C])
AC_MSG_RESULT([$PAC_C_MAX_REAL_PRECISION])

## ----------------------------------------------------------------------
## Define interface version
##
VERS_MAJOR=`cat $srcdir/src/H5public.h | sed -n 's/^#define H5_VERS_MAJOR //p'`
VERS_MINOR=`cat $srcdir/src/H5public.h | sed -n 's/^#define H5_VERS_MINOR //p'`
VERS_RELEASE=`cat $srcdir/src/H5public.h | sed -n 's/^#define H5_VERS_RELEASE //p'`
AC_DEFINE_UNQUOTED([VERS_MAJOR_TMP], $VERS_MAJOR, [Define major library version])
AC_DEFINE_UNQUOTED([VERS_MINOR_TMP], $VERS_MINOR, [Define minor library version])
AC_DEFINE_UNQUOTED([VERS_RELEASE_TMP], $VERS_RELEASE, [Define release library version])

## We will output an include file for Fortran, H5config_f.inc which
## contains various configure definitions used by the Fortran Library.
## Prepend H5_ to all macro names. This avoids name conflict between HDF5 macro
## names and those generated by another software package that uses the HDF5 library.
## We will output an include file for Fortran, H5config_f.inc which
## contains various configure definitions used by the Fortran Library.
## Prepend H5_ to all macro names. This avoids name conflict between HDF5 macro
## names and those generated by another software package that uses the HDF5 library.
AC_CONFIG_HEADERS([fortran/src/H5config_f.inc],
[cat fortran/src/H5config_f.inc | sed '1d;s%^/\* \(.*\) \*/%\1%;s/#define /#define H5_/;s/#undef /#undef H5_/' >fortran/src/H5config_f.inc.tmp; sed -i 's\_TMP\\g' fortran/src/H5config_f.inc.tmp; mv -f fortran/src/H5config_f.inc.tmp fortran/src/H5config_f.inc])

Expand Down
4 changes: 0 additions & 4 deletions fortran/test/tH5T_F03.F90
Original file line number Diff line number Diff line change
Expand Up @@ -1090,10 +1090,8 @@ SUBROUTINE test_h5kind_to_type(total_error)
CALL check("H5Dcreate_f",error, total_error)
CALL H5Dcreate_f(file_id, dsetnamer8, h5kind_to_type(real_kind_15,H5_REAL_KIND), dspace_id, dset_idr8, error)
CALL check("H5Dcreate_f",error, total_error)
!#ifdef H5_HAVE_FLOAT128
CALL H5Dcreate_f(file_id, dsetnamer16, h5kind_to_type(real_kind_31,H5_REAL_KIND), dspace_id, dset_idr16, error)
CALL check("H5Dcreate_f",error, total_error)
!#endif
!
! Write the dataset.
!
Expand Down Expand Up @@ -1123,11 +1121,9 @@ SUBROUTINE test_h5kind_to_type(total_error)
f_ptr = C_LOC(dset_data_r15(1))
CALL h5dwrite_f(dset_idr8, h5kind_to_type(real_kind_15,H5_REAL_KIND), f_ptr, error)
CALL check("H5Dwrite_f",error, total_error)
!#ifdef H5_HAVE_FLOAT128
f_ptr = C_LOC(dset_data_r31(1))
CALL h5dwrite_f(dset_idr16, h5kind_to_type(real_kind_31,H5_REAL_KIND), f_ptr, error)
CALL check("H5Dwrite_f",error, total_error)
!#endif
!
! Close the file
!
Expand Down
Loading
Loading