/* Fallback implementation of issignaling macro. Copyright (C) 2022 Free Software Foundation, Inc. Contributed by Francois-Xavier Coudert This file is part of the GNU Fortran runtime library (libgfortran). Libgfortran is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. Libgfortran is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Under Section 7 of GPL version 3, you are granted additional permissions described in the GCC Runtime Library Exception, version 3.1, as published by the Free Software Foundation. You should have received a copy of the GNU General Public License and a copy of the GCC Runtime Library Exception along with this program; see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ #include "libgfortran.h" /* This header provides an implementation of the type-generic issignaling macro. Some points of note: - This header is only included if the issignaling macro is not defined. - All targets for which Fortran IEEE modules are supported currently have the high-order bit of the NaN mantissa clear for signaling (and set for quiet), as recommended by IEEE. - We use the __*_IS_IEC_60559__ macros to make sure we only deal with formats we know. For other floating-point formats, we consider all NaNs as quiet. */ typedef union { float value; uint32_t word; } ieee_float_shape_type; static inline int __issignalingf (float x) { #if __FLT_IS_IEC_60559__ uint32_t xi; ieee_float_shape_type u; u.value = x; xi = u.word; xi ^= 0x00400000; return (xi & 0x7fffffff) > 0x7fc00000; #else return 0; #endif } typedef union { double value; uint64_t word; } ieee_double_shape_type; static inline int __issignaling (double x) { #if __DBL_IS_IEC_60559__ ieee_double_shape_type u; uint64_t xi; u.value = x; xi = u.word; xi ^= UINT64_C (0x0008000000000000); return (xi & UINT64_C (0x7fffffffffffffff)) > UINT64_C (0x7ff8000000000000); #else return 0; #endif } #if __LDBL_DIG__ == __DBL_DIG__ /* Long double is the same as double. */ static inline int __issignalingl (long double x) { return __issignaling (x); } #elif (__LDBL_DIG__ == 18) && __LDBL_IS_IEC_60559__ /* Long double is x86 extended type. */ typedef union { long double value; struct { #if __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__ int sign_exponent:16; unsigned int empty:16; uint32_t msw; uint32_t lsw; #elif __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__ uint32_t lsw; uint32_t msw; int sign_exponent:16; unsigned int empty:16; #endif } parts; } ieee_long_double_shape_type; static inline int __issignalingl (long double x) { int ret; uint32_t exi, hxi, lxi; ieee_long_double_shape_type u; u.value = x; exi = u.parts.sign_exponent; hxi = u.parts.msw; lxi = u.parts.lsw; /* Pseudo numbers on x86 are always signaling. */ ret = (exi & 0x7fff) && ((hxi & 0x80000000) == 0); hxi ^= 0x40000000; hxi |= (lxi | -lxi) >> 31; return ret || (((exi & 0x7fff) == 0x7fff) && (hxi > 0xc0000000)); } #elif (__LDBL_DIG__ == 31) /* Long double is 128-bit IBM extended type. */ static inline int __issignalingl (long double x) { union { long double value; double parts[2]; } u; u.value = x; return __issignaling (u.parts[0]); } #elif (__LDBL_DIG__ == 33) && __LDBL_IS_IEC_60559__ /* Long double is 128-bit type. */ typedef union { long double value; struct { #if __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__ uint64_t msw; uint64_t lsw; #elif __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__ uint64_t lsw; uint64_t msw; #endif } parts64; } ieee854_long_double_shape_type; static inline int __issignalingl (long double x) { uint64_t hxi, lxi; ieee854_long_double_shape_type u; u.value = x; hxi = u.parts64.msw; lxi = u.parts64.lsw; hxi ^= UINT64_C (0x0000800000000000); hxi |= (lxi | -lxi) >> 63; return (hxi & UINT64_C (0x7fffffffffffffff)) > UINT64_C (0x7fff800000000000); } #else static inline int __issignalingl (long double x) { return 0; } #endif #if defined(GFC_REAL_16_IS_FLOAT128) /* We have a __float128 type. */ typedef union { __float128 value; struct { #if __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__ uint64_t msw; uint64_t lsw; #elif __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__ uint64_t lsw; uint64_t msw; #endif } parts64; } ieee854_float128_shape_type; static inline int __issignalingf128 (__float128 x) { uint64_t hxi, lxi; ieee854_float128_shape_type u; u.value = x; hxi = u.parts64.msw; lxi = u.parts64.lsw; hxi ^= UINT64_C (0x0000800000000000); hxi |= (lxi | -lxi) >> 63; return (hxi & UINT64_C (0x7fffffffffffffff)) > UINT64_C (0x7fff800000000000); } #endif /* Define the type-generic macro based on the functions above. */ #if defined(GFC_REAL_16_IS_FLOAT128) # define issignaling(X) \ _Generic ((X), \ __float128: __issignalingf128, \ float: __issignalingf, \ double: __issignaling, \ long double: __issignalingl)(X) #else # define issignaling(X) \ _Generic ((X), \ float: __issignalingf, \ double: __issignaling, \ long double: __issignalingl)(X) #endif