-
-/*============================================================================
-
+/*
+ * QEMU float support
+ *
+ * The code in this source file is derived from release 2a of the SoftFloat
+ * IEC/IEEE Floating-point Arithmetic Package. Those parts of the code (and
+ * some later contributions) are provided under that license, as detailed below.
+ * It has subsequently been modified by contributors to the QEMU Project,
+ * so some portions are provided under:
+ * the SoftFloat-2a license
+ * the BSD license
+ * GPL-v2-or-later
+ *
+ * Any future contributions to this file after December 1st 2014 will be
+ * taken to be licensed under the Softfloat-2a license unless specifically
+ * indicated otherwise.
+ */
+
+/*
+===============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
-Arithmetic Package, Release 2b.
+Arithmetic Package, Release 2a.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
-is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
+is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
arithmetic/SoftFloat.html'.
-THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
-been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
-RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
-AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
-COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
-EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
-INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
-OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
Derivative works are acceptable, even for commercial purposes, so long as
-(1) the source code for the derivative work includes prominent notice that
-the work is derivative, and (2) the source code includes prominent notice with
-these four paragraphs for those parts of this code that are retained.
+(1) they include prominent notice that the work is derivative, and (2) they
+include prominent notice akin to these four paragraphs for those parts of
+this code that are retained.
+
+===============================================================================
+*/
+
+/* BSD licensing:
+ * Copyright (c) 2006, Fabrice Bellard
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Portions of this work are licensed under the terms of the GNU GPL,
+ * version 2 or later. See the COPYING file in the top-level directory.
+ */
+
+/* Does the target distinguish signaling NaNs from non-signaling NaNs
+ * by setting the most significant bit of the mantissa for a signaling NaN?
+ * (The more common choice is to have it be zero for SNaN and one for QNaN.)
+ */
+#if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
+#define SNAN_BIT_IS_ONE 1
+#else
+#define SNAN_BIT_IS_ONE 0
+#endif
+
+#if defined(TARGET_XTENSA)
+/* Define for architectures which deviate from IEEE in not supporting
+ * signaling NaNs (so all NaNs are treated as quiet).
+ */
+#define NO_SIGNALING_NANS 1
+#endif
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated half-precision NaN.
+*----------------------------------------------------------------------------*/
+#if defined(TARGET_ARM)
+const float16 float16_default_nan = const_float16(0x7E00);
+#elif SNAN_BIT_IS_ONE
+const float16 float16_default_nan = const_float16(0x7DFF);
+#else
+const float16 float16_default_nan = const_float16(0xFE00);
+#endif
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated single-precision NaN.
+*----------------------------------------------------------------------------*/
+#if defined(TARGET_SPARC)
+const float32 float32_default_nan = const_float32(0x7FFFFFFF);
+#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
+ defined(TARGET_XTENSA) || defined(TARGET_S390X)
+const float32 float32_default_nan = const_float32(0x7FC00000);
+#elif SNAN_BIT_IS_ONE
+const float32 float32_default_nan = const_float32(0x7FBFFFFF);
+#else
+const float32 float32_default_nan = const_float32(0xFFC00000);
+#endif
-=============================================================================*/
+/*----------------------------------------------------------------------------
+| The pattern for a default generated double-precision NaN.
+*----------------------------------------------------------------------------*/
+#if defined(TARGET_SPARC)
+const float64 float64_default_nan = const_float64(LIT64( 0x7FFFFFFFFFFFFFFF ));
+#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \
+ defined(TARGET_S390X)
+const float64 float64_default_nan = const_float64(LIT64( 0x7FF8000000000000 ));
+#elif SNAN_BIT_IS_ONE
+const float64 float64_default_nan = const_float64(LIT64(0x7FF7FFFFFFFFFFFF));
+#else
+const float64 float64_default_nan = const_float64(LIT64( 0xFFF8000000000000 ));
+#endif
-#if defined(TARGET_MIPS) || defined(TARGET_SH4)
-#define SNAN_BIT_IS_ONE 1
+/*----------------------------------------------------------------------------
+| The pattern for a default generated extended double-precision NaN.
+*----------------------------------------------------------------------------*/
+#if SNAN_BIT_IS_ONE
+#define floatx80_default_nan_high 0x7FFF
+#define floatx80_default_nan_low LIT64(0xBFFFFFFFFFFFFFFF)
#else
-#define SNAN_BIT_IS_ONE 0
+#define floatx80_default_nan_high 0xFFFF
+#define floatx80_default_nan_low LIT64( 0xC000000000000000 )
#endif
+const floatx80 floatx80_default_nan
+ = make_floatx80_init(floatx80_default_nan_high, floatx80_default_nan_low);
+
+/*----------------------------------------------------------------------------
+| The pattern for a default generated quadruple-precision NaN. The `high' and
+| `low' values hold the most- and least-significant bits, respectively.
+*----------------------------------------------------------------------------*/
+#if SNAN_BIT_IS_ONE
+#define float128_default_nan_high LIT64(0x7FFF7FFFFFFFFFFF)
+#define float128_default_nan_low LIT64(0xFFFFFFFFFFFFFFFF)
+#elif defined(TARGET_S390X)
+#define float128_default_nan_high LIT64( 0x7FFF800000000000 )
+#define float128_default_nan_low LIT64( 0x0000000000000000 )
+#else
+#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
+#define float128_default_nan_low LIT64( 0x0000000000000000 )
+#endif
+
+const float128 float128_default_nan
+ = make_float128_init(float128_default_nan_high, float128_default_nan_low);
+
/*----------------------------------------------------------------------------
| Raises the exceptions specified by `flags'. Floating-point traps can be
| defined here if desired. It is currently not possible for such a trap
| should be simply `float_exception_flags |= flags;'.
*----------------------------------------------------------------------------*/
-void float_raise( int8 flags STATUS_PARAM )
+void float_raise(int8 flags, float_status *status)
{
- STATUS(float_exception_flags) |= flags;
+ status->float_exception_flags |= flags;
}
/*----------------------------------------------------------------------------
*----------------------------------------------------------------------------*/
typedef struct {
flag sign;
- bits64 high, low;
+ uint64_t high, low;
} commonNaNT;
+#ifdef NO_SIGNALING_NANS
+int float16_is_quiet_nan(float16 a_)
+{
+ return float16_is_any_nan(a_);
+}
+
+int float16_is_signaling_nan(float16 a_)
+{
+ return 0;
+}
+#else
/*----------------------------------------------------------------------------
-| The pattern for a default generated single-precision NaN.
+| Returns 1 if the half-precision floating-point value `a' is a quiet
+| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
-#if defined(TARGET_SPARC)
-#define float32_default_nan make_float32(0x7FFFFFFF)
-#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
-#define float32_default_nan make_float32(0x7FC00000)
-#elif SNAN_BIT_IS_ONE
-#define float32_default_nan make_float32(0x7FBFFFFF)
+
+int float16_is_quiet_nan(float16 a_)
+{
+ uint16_t a = float16_val(a_);
+#if SNAN_BIT_IS_ONE
+ return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF);
+#else
+ return ((a & ~0x8000) >= 0x7c80);
+#endif
+}
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the half-precision floating-point value `a' is a signaling
+| NaN; otherwise returns 0.
+*----------------------------------------------------------------------------*/
+
+int float16_is_signaling_nan(float16 a_)
+{
+ uint16_t a = float16_val(a_);
+#if SNAN_BIT_IS_ONE
+ return ((a & ~0x8000) >= 0x7c80);
+#else
+ return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF);
+#endif
+}
+#endif
+
+/*----------------------------------------------------------------------------
+| Returns a quiet NaN if the half-precision floating point value `a' is a
+| signaling NaN; otherwise returns `a'.
+*----------------------------------------------------------------------------*/
+float16 float16_maybe_silence_nan(float16 a_)
+{
+ if (float16_is_signaling_nan(a_)) {
+#if SNAN_BIT_IS_ONE
+# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
+ return float16_default_nan;
+# else
+# error Rules for silencing a signaling NaN are target-specific
+# endif
#else
-#define float32_default_nan make_float32(0xFFC00000)
+ uint16_t a = float16_val(a_);
+ a |= (1 << 9);
+ return make_float16(a);
#endif
+ }
+ return a_;
+}
+
+/*----------------------------------------------------------------------------
+| Returns the result of converting the half-precision floating-point NaN
+| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
+| exception is raised.
+*----------------------------------------------------------------------------*/
+
+static commonNaNT float16ToCommonNaN(float16 a, float_status *status)
+{
+ commonNaNT z;
+
+ if (float16_is_signaling_nan(a)) {
+ float_raise(float_flag_invalid, status);
+ }
+ z.sign = float16_val(a) >> 15;
+ z.low = 0;
+ z.high = ((uint64_t) float16_val(a))<<54;
+ return z;
+}
+/*----------------------------------------------------------------------------
+| Returns the result of converting the canonical NaN `a' to the half-
+| precision floating-point format.
+*----------------------------------------------------------------------------*/
+
+static float16 commonNaNToFloat16(commonNaNT a, float_status *status)
+{
+ uint16_t mantissa = a.high>>54;
+
+ if (status->default_nan_mode) {
+ return float16_default_nan;
+ }
+
+ if (mantissa) {
+ return make_float16(((((uint16_t) a.sign) << 15)
+ | (0x1F << 10) | mantissa));
+ } else {
+ return float16_default_nan;
+ }
+}
+
+#ifdef NO_SIGNALING_NANS
+int float32_is_quiet_nan(float32 a_)
+{
+ return float32_is_any_nan(a_);
+}
+
+int float32_is_signaling_nan(float32 a_)
+{
+ return 0;
+}
+#else
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a quiet
| NaN; otherwise returns 0.
{
uint32_t a = float32_val(a_);
#if SNAN_BIT_IS_ONE
- return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
+ return (((a >> 22) & 0x1ff) == 0x1fe) && (a & 0x003fffff);
#else
- return ( 0xFF800000 <= (bits32) ( a<<1 ) );
+ return ((uint32_t)(a << 1) >= 0xff800000);
#endif
}
{
uint32_t a = float32_val(a_);
#if SNAN_BIT_IS_ONE
- return ( 0xFF800000 <= (bits32) ( a<<1 ) );
+ return ((uint32_t)(a << 1) >= 0xff800000);
#else
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
#endif
}
+#endif
/*----------------------------------------------------------------------------
| Returns a quiet NaN if the single-precision floating point value `a' is a
{
if (float32_is_signaling_nan(a_)) {
#if SNAN_BIT_IS_ONE
-# if defined(TARGET_MIPS) || defined(TARGET_SH4)
+# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
return float32_default_nan;
# else
# error Rules for silencing a signaling NaN are target-specific
# endif
#else
- bits32 a = float32_val(a_);
+ uint32_t a = float32_val(a_);
a |= (1 << 22);
return make_float32(a);
#endif
| exception is raised.
*----------------------------------------------------------------------------*/
-static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM )
+static commonNaNT float32ToCommonNaN(float32 a, float_status *status)
{
commonNaNT z;
- if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR );
+ if (float32_is_signaling_nan(a)) {
+ float_raise(float_flag_invalid, status);
+ }
z.sign = float32_val(a)>>31;
z.low = 0;
- z.high = ( (bits64) float32_val(a) )<<41;
+ z.high = ( (uint64_t) float32_val(a) )<<41;
return z;
}
| precision floating-point format.
*----------------------------------------------------------------------------*/
-static float32 commonNaNToFloat32( commonNaNT a )
+static float32 commonNaNToFloat32(commonNaNT a, float_status *status)
{
- bits32 mantissa = a.high>>41;
+ uint32_t mantissa = a.high>>41;
+
+ if (status->default_nan_mode) {
+ return float32_default_nan;
+ }
+
if ( mantissa )
return make_float32(
- ( ( (bits32) a.sign )<<31 ) | 0x7F800000 | ( a.high>>41 ) );
+ ( ( (uint32_t) a.sign )<<31 ) | 0x7F800000 | ( a.high>>41 ) );
else
return float32_default_nan;
}
return 1;
}
}
-#elif defined(TARGET_PPC)
+#elif defined(TARGET_PPC) || defined(TARGET_XTENSA)
static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
flag aIsLargerSignificand)
{
}
#endif
+/*----------------------------------------------------------------------------
+| Select which NaN to propagate for a three-input operation.
+| For the moment we assume that no CPU needs the 'larger significand'
+| information.
+| Return values : 0 : a; 1 : b; 2 : c; 3 : default-NaN
+*----------------------------------------------------------------------------*/
+#if defined(TARGET_ARM)
+static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+ flag cIsQNaN, flag cIsSNaN, flag infzero,
+ float_status *status)
+{
+ /* For ARM, the (inf,zero,qnan) case sets InvalidOp and returns
+ * the default NaN
+ */
+ if (infzero && cIsQNaN) {
+ float_raise(float_flag_invalid, status);
+ return 3;
+ }
+
+ /* This looks different from the ARM ARM pseudocode, because the ARM ARM
+ * puts the operands to a fused mac operation (a*b)+c in the order c,a,b.
+ */
+ if (cIsSNaN) {
+ return 2;
+ } else if (aIsSNaN) {
+ return 0;
+ } else if (bIsSNaN) {
+ return 1;
+ } else if (cIsQNaN) {
+ return 2;
+ } else if (aIsQNaN) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+#elif defined(TARGET_MIPS)
+static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+ flag cIsQNaN, flag cIsSNaN, flag infzero,
+ float_status *status)
+{
+ /* For MIPS, the (inf,zero,qnan) case sets InvalidOp and returns
+ * the default NaN
+ */
+ if (infzero) {
+ float_raise(float_flag_invalid, status);
+ return 3;
+ }
+
+ /* Prefer sNaN over qNaN, in the a, b, c order. */
+ if (aIsSNaN) {
+ return 0;
+ } else if (bIsSNaN) {
+ return 1;
+ } else if (cIsSNaN) {
+ return 2;
+ } else if (aIsQNaN) {
+ return 0;
+ } else if (bIsQNaN) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+#elif defined(TARGET_PPC)
+static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+ flag cIsQNaN, flag cIsSNaN, flag infzero,
+ float_status *status)
+{
+ /* For PPC, the (inf,zero,qnan) case sets InvalidOp, but we prefer
+ * to return an input NaN if we have one (ie c) rather than generating
+ * a default NaN
+ */
+ if (infzero) {
+ float_raise(float_flag_invalid, status);
+ return 2;
+ }
+
+ /* If fRA is a NaN return it; otherwise if fRB is a NaN return it;
+ * otherwise return fRC. Note that muladd on PPC is (fRA * fRC) + frB
+ */
+ if (aIsSNaN || aIsQNaN) {
+ return 0;
+ } else if (cIsSNaN || cIsQNaN) {
+ return 2;
+ } else {
+ return 1;
+ }
+}
+#else
+/* A default implementation: prefer a to b to c.
+ * This is unlikely to actually match any real implementation.
+ */
+static int pickNaNMulAdd(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+ flag cIsQNaN, flag cIsSNaN, flag infzero,
+ float_status *status)
+{
+ if (aIsSNaN || aIsQNaN) {
+ return 0;
+ } else if (bIsSNaN || bIsQNaN) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+#endif
+
/*----------------------------------------------------------------------------
| Takes two single-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
-static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM)
+static float32 propagateFloat32NaN(float32 a, float32 b, float_status *status)
{
flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
flag aIsLargerSignificand;
- bits32 av, bv;
+ uint32_t av, bv;
aIsQuietNaN = float32_is_quiet_nan( a );
aIsSignalingNaN = float32_is_signaling_nan( a );
av = float32_val(a);
bv = float32_val(b);
- if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
+ if (aIsSignalingNaN | bIsSignalingNaN) {
+ float_raise(float_flag_invalid, status);
+ }
- if ( STATUS(default_nan_mode) )
+ if (status->default_nan_mode)
return float32_default_nan;
- if ((bits32)(av<<1) < (bits32)(bv<<1)) {
+ if ((uint32_t)(av<<1) < (uint32_t)(bv<<1)) {
aIsLargerSignificand = 0;
- } else if ((bits32)(bv<<1) < (bits32)(av<<1)) {
+ } else if ((uint32_t)(bv<<1) < (uint32_t)(av<<1)) {
aIsLargerSignificand = 1;
} else {
aIsLargerSignificand = (av < bv) ? 1 : 0;
}
/*----------------------------------------------------------------------------
-| The pattern for a default generated double-precision NaN.
+| Takes three single-precision floating-point values `a', `b' and `c', one of
+| which is a NaN, and returns the appropriate NaN result. If any of `a',
+| `b' or `c' is a signaling NaN, the invalid exception is raised.
+| The input infzero indicates whether a*b was 0*inf or inf*0 (in which case
+| obviously c is a NaN, and whether to propagate c or some other NaN is
+| implementation defined).
*----------------------------------------------------------------------------*/
-#if defined(TARGET_SPARC)
-#define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF ))
-#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA)
-#define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 ))
-#elif SNAN_BIT_IS_ONE
-#define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF ))
-#else
-#define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 ))
-#endif
+static float32 propagateFloat32MulAddNaN(float32 a, float32 b,
+ float32 c, flag infzero,
+ float_status *status)
+{
+ flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
+ cIsQuietNaN, cIsSignalingNaN;
+ int which;
+
+ aIsQuietNaN = float32_is_quiet_nan(a);
+ aIsSignalingNaN = float32_is_signaling_nan(a);
+ bIsQuietNaN = float32_is_quiet_nan(b);
+ bIsSignalingNaN = float32_is_signaling_nan(b);
+ cIsQuietNaN = float32_is_quiet_nan(c);
+ cIsSignalingNaN = float32_is_signaling_nan(c);
+
+ if (aIsSignalingNaN | bIsSignalingNaN | cIsSignalingNaN) {
+ float_raise(float_flag_invalid, status);
+ }
+
+ which = pickNaNMulAdd(aIsQuietNaN, aIsSignalingNaN,
+ bIsQuietNaN, bIsSignalingNaN,
+ cIsQuietNaN, cIsSignalingNaN, infzero, status);
+
+ if (status->default_nan_mode) {
+ /* Note that this check is after pickNaNMulAdd so that function
+ * has an opportunity to set the Invalid flag.
+ */
+ return float32_default_nan;
+ }
+
+ switch (which) {
+ case 0:
+ return float32_maybe_silence_nan(a);
+ case 1:
+ return float32_maybe_silence_nan(b);
+ case 2:
+ return float32_maybe_silence_nan(c);
+ case 3:
+ default:
+ return float32_default_nan;
+ }
+}
+
+#ifdef NO_SIGNALING_NANS
+int float64_is_quiet_nan(float64 a_)
+{
+ return float64_is_any_nan(a_);
+}
+
+int float64_is_signaling_nan(float64 a_)
+{
+ return 0;
+}
+#else
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a quiet
| NaN; otherwise returns 0.
int float64_is_quiet_nan( float64 a_ )
{
- bits64 a = float64_val(a_);
+ uint64_t a = float64_val(a_);
#if SNAN_BIT_IS_ONE
- return
- ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
- && ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
+ return (((a >> 51) & 0xfff) == 0xffe)
+ && (a & 0x0007ffffffffffffULL);
#else
- return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) );
+ return ((a << 1) >= 0xfff0000000000000ULL);
#endif
}
int float64_is_signaling_nan( float64 a_ )
{
- bits64 a = float64_val(a_);
+ uint64_t a = float64_val(a_);
#if SNAN_BIT_IS_ONE
- return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) );
+ return ((a << 1) >= 0xfff0000000000000ULL);
#else
return
( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
&& ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
#endif
}
+#endif
/*----------------------------------------------------------------------------
| Returns a quiet NaN if the double-precision floating point value `a' is a
{
if (float64_is_signaling_nan(a_)) {
#if SNAN_BIT_IS_ONE
-# if defined(TARGET_MIPS) || defined(TARGET_SH4)
+# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
return float64_default_nan;
# else
# error Rules for silencing a signaling NaN are target-specific
# endif
#else
- bits64 a = float64_val(a_);
+ uint64_t a = float64_val(a_);
a |= LIT64( 0x0008000000000000 );
return make_float64(a);
#endif
| exception is raised.
*----------------------------------------------------------------------------*/
-static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM)
+static commonNaNT float64ToCommonNaN(float64 a, float_status *status)
{
commonNaNT z;
- if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
+ if (float64_is_signaling_nan(a)) {
+ float_raise(float_flag_invalid, status);
+ }
z.sign = float64_val(a)>>63;
z.low = 0;
z.high = float64_val(a)<<12;
| precision floating-point format.
*----------------------------------------------------------------------------*/
-static float64 commonNaNToFloat64( commonNaNT a )
+static float64 commonNaNToFloat64(commonNaNT a, float_status *status)
{
- bits64 mantissa = a.high>>12;
+ uint64_t mantissa = a.high>>12;
+
+ if (status->default_nan_mode) {
+ return float64_default_nan;
+ }
if ( mantissa )
return make_float64(
- ( ( (bits64) a.sign )<<63 )
+ ( ( (uint64_t) a.sign )<<63 )
| LIT64( 0x7FF0000000000000 )
| ( a.high>>12 ));
else
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
-static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM)
+static float64 propagateFloat64NaN(float64 a, float64 b, float_status *status)
{
flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
flag aIsLargerSignificand;
- bits64 av, bv;
+ uint64_t av, bv;
aIsQuietNaN = float64_is_quiet_nan( a );
aIsSignalingNaN = float64_is_signaling_nan( a );
av = float64_val(a);
bv = float64_val(b);
- if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
+ if (aIsSignalingNaN | bIsSignalingNaN) {
+ float_raise(float_flag_invalid, status);
+ }
- if ( STATUS(default_nan_mode) )
+ if (status->default_nan_mode)
return float64_default_nan;
- if ((bits64)(av<<1) < (bits64)(bv<<1)) {
+ if ((uint64_t)(av<<1) < (uint64_t)(bv<<1)) {
aIsLargerSignificand = 0;
- } else if ((bits64)(bv<<1) < (bits64)(av<<1)) {
+ } else if ((uint64_t)(bv<<1) < (uint64_t)(av<<1)) {
aIsLargerSignificand = 1;
} else {
aIsLargerSignificand = (av < bv) ? 1 : 0;
}
}
-#ifdef FLOATX80
-
/*----------------------------------------------------------------------------
-| The pattern for a default generated extended double-precision NaN. The
-| `high' and `low' values hold the most- and least-significant bits,
-| respectively.
+| Takes three double-precision floating-point values `a', `b' and `c', one of
+| which is a NaN, and returns the appropriate NaN result. If any of `a',
+| `b' or `c' is a signaling NaN, the invalid exception is raised.
+| The input infzero indicates whether a*b was 0*inf or inf*0 (in which case
+| obviously c is a NaN, and whether to propagate c or some other NaN is
+| implementation defined).
*----------------------------------------------------------------------------*/
-#if SNAN_BIT_IS_ONE
-#define floatx80_default_nan_high 0x7FFF
-#define floatx80_default_nan_low LIT64( 0xBFFFFFFFFFFFFFFF )
-#else
-#define floatx80_default_nan_high 0xFFFF
-#define floatx80_default_nan_low LIT64( 0xC000000000000000 )
-#endif
+static float64 propagateFloat64MulAddNaN(float64 a, float64 b,
+ float64 c, flag infzero,
+ float_status *status)
+{
+ flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN,
+ cIsQuietNaN, cIsSignalingNaN;
+ int which;
+
+ aIsQuietNaN = float64_is_quiet_nan(a);
+ aIsSignalingNaN = float64_is_signaling_nan(a);
+ bIsQuietNaN = float64_is_quiet_nan(b);
+ bIsSignalingNaN = float64_is_signaling_nan(b);
+ cIsQuietNaN = float64_is_quiet_nan(c);
+ cIsSignalingNaN = float64_is_signaling_nan(c);
+
+ if (aIsSignalingNaN | bIsSignalingNaN | cIsSignalingNaN) {
+ float_raise(float_flag_invalid, status);
+ }
+
+ which = pickNaNMulAdd(aIsQuietNaN, aIsSignalingNaN,
+ bIsQuietNaN, bIsSignalingNaN,
+ cIsQuietNaN, cIsSignalingNaN, infzero, status);
+
+ if (status->default_nan_mode) {
+ /* Note that this check is after pickNaNMulAdd so that function
+ * has an opportunity to set the Invalid flag.
+ */
+ return float64_default_nan;
+ }
+
+ switch (which) {
+ case 0:
+ return float64_maybe_silence_nan(a);
+ case 1:
+ return float64_maybe_silence_nan(b);
+ case 2:
+ return float64_maybe_silence_nan(c);
+ case 3:
+ default:
+ return float64_default_nan;
+ }
+}
+
+#ifdef NO_SIGNALING_NANS
+int floatx80_is_quiet_nan(floatx80 a_)
+{
+ return floatx80_is_any_nan(a_);
+}
+
+int floatx80_is_signaling_nan(floatx80 a_)
+{
+ return 0;
+}
+#else
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| quiet NaN; otherwise returns 0. This slightly differs from the same
int floatx80_is_quiet_nan( floatx80 a )
{
#if SNAN_BIT_IS_ONE
- bits64 aLow;
+ uint64_t aLow;
- aLow = a.low & ~ LIT64( 0x4000000000000000 );
- return
- ( ( a.high & 0x7FFF ) == 0x7FFF )
- && (bits64) ( aLow<<1 )
- && ( a.low == aLow );
+ aLow = a.low & ~0x4000000000000000ULL;
+ return ((a.high & 0x7fff) == 0x7fff)
+ && (aLow << 1)
+ && (a.low == aLow);
#else
return ( ( a.high & 0x7FFF ) == 0x7FFF )
- && (LIT64( 0x8000000000000000 ) <= ((bits64) ( a.low<<1 )));
+ && (LIT64( 0x8000000000000000 ) <= ((uint64_t) ( a.low<<1 )));
#endif
}
int floatx80_is_signaling_nan( floatx80 a )
{
#if SNAN_BIT_IS_ONE
- return ( ( a.high & 0x7FFF ) == 0x7FFF )
- && (LIT64( 0x8000000000000000 ) <= ((bits64) ( a.low<<1 )));
+ return ((a.high & 0x7fff) == 0x7fff)
+ && ((a.low << 1) >= 0x8000000000000000ULL);
#else
- bits64 aLow;
+ uint64_t aLow;
aLow = a.low & ~ LIT64( 0x4000000000000000 );
return
( ( a.high & 0x7FFF ) == 0x7FFF )
- && (bits64) ( aLow<<1 )
+ && (uint64_t) ( aLow<<1 )
&& ( a.low == aLow );
#endif
}
+#endif
/*----------------------------------------------------------------------------
| Returns a quiet NaN if the extended double-precision floating point value
{
if (floatx80_is_signaling_nan(a)) {
#if SNAN_BIT_IS_ONE
-# if defined(TARGET_MIPS) || defined(TARGET_SH4)
+# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
a.low = floatx80_default_nan_low;
a.high = floatx80_default_nan_high;
# else
| invalid exception is raised.
*----------------------------------------------------------------------------*/
-static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM)
+static commonNaNT floatx80ToCommonNaN(floatx80 a, float_status *status)
{
commonNaNT z;
- if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
- z.sign = a.high>>15;
- z.low = 0;
- z.high = a.low;
+ if (floatx80_is_signaling_nan(a)) {
+ float_raise(float_flag_invalid, status);
+ }
+ if ( a.low >> 63 ) {
+ z.sign = a.high >> 15;
+ z.low = 0;
+ z.high = a.low << 1;
+ } else {
+ z.sign = floatx80_default_nan_high >> 15;
+ z.low = 0;
+ z.high = floatx80_default_nan_low << 1;
+ }
return z;
}
| double-precision floating-point format.
*----------------------------------------------------------------------------*/
-static floatx80 commonNaNToFloatx80( commonNaNT a )
+static floatx80 commonNaNToFloatx80(commonNaNT a, float_status *status)
{
floatx80 z;
- if (a.high)
- z.low = a.high;
- else
+ if (status->default_nan_mode) {
z.low = floatx80_default_nan_low;
- z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
+ z.high = floatx80_default_nan_high;
+ return z;
+ }
+
+ if (a.high >> 1) {
+ z.low = LIT64( 0x8000000000000000 ) | a.high >> 1;
+ z.high = ( ( (uint16_t) a.sign )<<15 ) | 0x7FFF;
+ } else {
+ z.low = floatx80_default_nan_low;
+ z.high = floatx80_default_nan_high;
+ }
+
return z;
}
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
-static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM)
+static floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b,
+ float_status *status)
{
flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
flag aIsLargerSignificand;
bIsQuietNaN = floatx80_is_quiet_nan( b );
bIsSignalingNaN = floatx80_is_signaling_nan( b );
- if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
+ if (aIsSignalingNaN | bIsSignalingNaN) {
+ float_raise(float_flag_invalid, status);
+ }
- if ( STATUS(default_nan_mode) ) {
+ if (status->default_nan_mode) {
a.low = floatx80_default_nan_low;
a.high = floatx80_default_nan_high;
return a;
}
}
-#endif
-
-#ifdef FLOAT128
+#ifdef NO_SIGNALING_NANS
+int float128_is_quiet_nan(float128 a_)
+{
+ return float128_is_any_nan(a_);
+}
-/*----------------------------------------------------------------------------
-| The pattern for a default generated quadruple-precision NaN. The `high' and
-| `low' values hold the most- and least-significant bits, respectively.
-*----------------------------------------------------------------------------*/
-#if SNAN_BIT_IS_ONE
-#define float128_default_nan_high LIT64( 0x7FFF7FFFFFFFFFFF )
-#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
+int float128_is_signaling_nan(float128 a_)
+{
+ return 0;
+}
#else
-#define float128_default_nan_high LIT64( 0xFFFF800000000000 )
-#define float128_default_nan_low LIT64( 0x0000000000000000 )
-#endif
-
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a quiet
| NaN; otherwise returns 0.
int float128_is_quiet_nan( float128 a )
{
#if SNAN_BIT_IS_ONE
- return
- ( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
- && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
+ return (((a.high >> 47) & 0xffff) == 0xfffe)
+ && (a.low || (a.high & 0x00007fffffffffffULL));
#else
return
- ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
- && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
+ ((a.high << 1) >= 0xffff000000000000ULL)
+ && (a.low || (a.high & 0x0000ffffffffffffULL));
#endif
}
{
#if SNAN_BIT_IS_ONE
return
- ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) )
- && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) );
+ ((a.high << 1) >= 0xffff000000000000ULL)
+ && (a.low || (a.high & 0x0000ffffffffffffULL));
#else
return
( ( ( a.high>>47 ) & 0xFFFF ) == 0xFFFE )
&& ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) );
#endif
}
+#endif
/*----------------------------------------------------------------------------
| Returns a quiet NaN if the quadruple-precision floating point value `a' is
{
if (float128_is_signaling_nan(a)) {
#if SNAN_BIT_IS_ONE
-# if defined(TARGET_MIPS) || defined(TARGET_SH4)
+# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32)
a.low = float128_default_nan_low;
a.high = float128_default_nan_high;
# else
| exception is raised.
*----------------------------------------------------------------------------*/
-static commonNaNT float128ToCommonNaN( float128 a STATUS_PARAM)
+static commonNaNT float128ToCommonNaN(float128 a, float_status *status)
{
commonNaNT z;
- if ( float128_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR);
+ if (float128_is_signaling_nan(a)) {
+ float_raise(float_flag_invalid, status);
+ }
z.sign = a.high>>63;
shortShift128Left( a.high, a.low, 16, &z.high, &z.low );
return z;
| precision floating-point format.
*----------------------------------------------------------------------------*/
-static float128 commonNaNToFloat128( commonNaNT a )
+static float128 commonNaNToFloat128(commonNaNT a, float_status *status)
{
float128 z;
+ if (status->default_nan_mode) {
+ z.low = float128_default_nan_low;
+ z.high = float128_default_nan_high;
+ return z;
+ }
+
shift128Right( a.high, a.low, 16, &z.high, &z.low );
- z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF000000000000 );
+ z.high |= ( ( (uint64_t) a.sign )<<63 ) | LIT64( 0x7FFF000000000000 );
return z;
}
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
-static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM)
+static float128 propagateFloat128NaN(float128 a, float128 b,
+ float_status *status)
{
flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN;
flag aIsLargerSignificand;
bIsQuietNaN = float128_is_quiet_nan( b );
bIsSignalingNaN = float128_is_signaling_nan( b );
- if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
+ if (aIsSignalingNaN | bIsSignalingNaN) {
+ float_raise(float_flag_invalid, status);
+ }
- if ( STATUS(default_nan_mode) ) {
+ if (status->default_nan_mode) {
a.low = float128_default_nan_low;
a.high = float128_default_nan_high;
return a;
}
}
-#endif