blob: 98b0b2819acf0db3d29301ef36a1a7a7803b6e4d [file] [log] [blame]
/* Fallback implementation of issignaling macro.
Copyright (C) 2022 Free Software Foundation, Inc.
Contributed by Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
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
<http://www.gnu.org/licenses/>. */
#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