diff mbox

WIP flush-to-zero patch [was: Re: [Qemu-devel] QEMU state of ARM NEON support.]

Message ID 20100325140011.GT16726@codesourcery.com
State New
Headers show

Commit Message

Nathan Froyd March 25, 2010, 2 p.m. UTC
On Thu, Mar 25, 2010 at 08:52:39AM +0100, Juha.Riihimaki@nokia.com wrote:
> - Using subnormal floating point input values yields wrong results
> (this is visible in your vceq/vcgt/vcle tests against zero), I guess
> this would need to be corrected in the softfloat library which QEMU
> uses.

FWIW, below is a WIP progress patch to implement flush-to-zero better.
The motivating observation is that many chips feature separate
flush-input and flush-output flags and QEMU's fpu/ library only
implements flush-output.  So the bulk of the patch is:

- replacing the ad-hoc unpacking of float values into (sign, exponent,
  significand) with a centralized routine that will apply flush-to-zero
  on input values;

- splitting float_status.flush_to_zero into separate input/output flags;

- modifying targets to set input/output flags appropriately.

The float_flag_input_denormal is entirely optional; I thought it might
make sense for chips that may raise exceptions on denormal inputs
(e.g. many MIPS chips).  Perhaps it makes more sense to provide
floatZZ_is_denormal and let chip emulation handle those cases
themselves.

The patch is untested, and likely won't work for NEON as-is, since NEON
uses a separate float_status control.  But extending the patch to work
with NEON should be straightforward.

-Nathan

Comments

Richard Henderson March 25, 2010, 4:11 p.m. UTC | #1
On 03/25/2010 07:00 AM, Nathan Froyd wrote:
> FWIW, below is a WIP progress patch to implement flush-to-zero better.
> The motivating observation is that many chips feature separate
> flush-input and flush-output flags and QEMU's fpu/ library only
> implements flush-output.  So the bulk of the patch is:
> 
> - replacing the ad-hoc unpacking of float values into (sign, exponent,
>   significand) with a centralized routine that will apply flush-to-zero
>   on input values;
> 
> - splitting float_status.flush_to_zero into separate input/output flags;
> 
> - modifying targets to set input/output flags appropriately.

Excellent.  This should allow me to clean up the Alpha port a bit.
Specifically wrt helper_ieee_input*.


r~
diff mbox

Patch

diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index e6065b4..f10db48 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -204,6 +204,25 @@  INLINE flag extractFloat32Sign( float32 a )
 }
 
 /*----------------------------------------------------------------------------
+| Unpacks the fractional, exponent, and sign bits of the single-precision
+| floating-point value `a' into the locations pointed to by `aSigPtr',
+| `aExpPtr', and `aSignPtr', respectively.
+-----------------------------------------------------------------------------*/
+
+INLINE void
+ unpackFloat32( float32 a, bits32 *aSigPtr, int16 *aExpPtr, flag *aSignPtr STATUS_PARAM )
+{
+    *aSigPtr = extractFloat32Frac( a );
+    *aExpPtr = extractFloat32Exp( a );
+    *aSignPtr = extractFloat32Sign( a );
+
+    if ( STATUS(flush_inputs_to_zero) && *aExpPtr == 0 ) {
+        *aSigPtr = 0;
+        float_raise( float_flag_input_denormal STATUS_VAR);
+    }
+}
+
+/*----------------------------------------------------------------------------
 | Normalizes the subnormal single-precision floating-point value represented
 | by the denormalized significand `aSig'.  The normalized exponent and
 | significand are stored at the locations pointed to by `zExpPtr' and
@@ -296,7 +315,7 @@  static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P
             return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 ));
         }
         if ( zExp < 0 ) {
-            if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 );
+            if ( STATUS(flush_outputs_to_zero) ) return packFloat32( zSign, 0, 0 );
             isTiny =
                    ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
                 || ( zExp < -1 )
@@ -368,6 +387,25 @@  INLINE flag extractFloat64Sign( float64 a )
 }
 
 /*----------------------------------------------------------------------------
+| Unpacks the fractional, exponent, and sign bits of the double-precision
+| floating-point value `a' into the locations pointed to by `aSigPtr',
+| `aExpPtr', and `aSignPtr', respectively.
+-----------------------------------------------------------------------------*/
+
+INLINE void
+ unpackFloat64( float64 a, bits64 *aSigPtr, int16 *aExpPtr, flag *aSignPtr STATUS_PARAM )
+{
+    *aSigPtr = extractFloat64Frac( a );
+    *aExpPtr = extractFloat64Exp( a );
+    *aSignPtr = extractFloat64Sign( a );
+
+    if ( STATUS(flush_inputs_to_zero) && *aExpPtr == 0 ) {
+        *aSigPtr = 0;
+        float_raise( float_flag_input_denormal STATUS_VAR);
+    }
+}
+
+/*----------------------------------------------------------------------------
 | Normalizes the subnormal double-precision floating-point value represented
 | by the denormalized significand `aSig'.  The normalized exponent and
 | significand are stored at the locations pointed to by `zExpPtr' and
@@ -460,7 +498,7 @@  static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P
             return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 ));
         }
         if ( zExp < 0 ) {
-            if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 );
+            if ( STATUS(flush_outputs_to_zero) ) return packFloat64( zSign, 0, 0 );
             isTiny =
                    ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
                 || ( zExp < -1 )
@@ -537,6 +575,25 @@  INLINE flag extractFloatx80Sign( floatx80 a )
 }
 
 /*----------------------------------------------------------------------------
+| Unpacks the fractional, exponent, and sign bits of the extended
+| double-precision floating-point value `a' into the locations pointed to by
+| `aSigPtr', `aExpPtr', and `aSignPtr', respectively.
+-----------------------------------------------------------------------------*/
+
+INLINE void
+ unpackFloatx80( floatx80 a, bits64 *aSigPtr, int32 *aExpPtr, flag *aSignPtr STATUS_PARAM )
+{
+    *aSigPtr = extractFloatx80Frac( a );
+    *aExpPtr = extractFloatx80Exp( a );
+    *aSignPtr = extractFloatx80Sign( a );
+
+    if ( STATUS(flush_inputs_to_zero) && *aExpPtr == 0 ) {
+        *aSigPtr = 0;
+        float_raise( float_flag_input_denormal STATUS_VAR);
+    }
+}
+
+/*----------------------------------------------------------------------------
 | Normalizes the subnormal extended double-precision floating-point value
 | represented by the denormalized significand `aSig'.  The normalized exponent
 | and significand are stored at the locations pointed to by `zExpPtr' and
@@ -639,7 +696,7 @@  static floatx80
             goto overflow;
         }
         if ( zExp <= 0 ) {
-            if ( STATUS(flush_to_zero) ) return packFloatx80( zSign, 0, 0 );
+            if ( STATUS(flush_outputs_to_zero) ) return packFloatx80( zSign, 0, 0 );
             isTiny =
                    ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
                 || ( zExp < 0 )
@@ -834,6 +891,30 @@  INLINE flag extractFloat128Sign( float128 a )
 }
 
 /*----------------------------------------------------------------------------
+| Unpacks the least-significant 64 fraction, the most-significant 48 fraction,
+| exponent, and sign bits of the quadruple-precision floating-point value `a'
+| into the locations pointed to by `aSig1Ptr', `aSig0Ptr', `aExpPtr', and
+| `aSignPtr', respectively.
+-----------------------------------------------------------------------------*/
+
+INLINE void
+ unpackFloat128(
+     float128 a, bits64 *aSig1Ptr, bits64 *aSig0Ptr,
+     int32 *aExpPtr, flag *aSignPtr STATUS_PARAM )
+{
+    *aSig1Ptr = extractFloat128Frac1( a );
+    *aSig0Ptr = extractFloat128Frac0( a );
+    *aExpPtr = extractFloat128Exp( a );
+    *aSignPtr = extractFloat128Sign( a );
+
+    if ( STATUS(flush_inputs_to_zero) && *aExpPtr == 0 ) {
+        *aSig1Ptr = 0;
+        *aSig0Ptr = 0;
+        float_raise( float_flag_input_denormal STATUS_VAR);
+    }
+}
+
+/*----------------------------------------------------------------------------
 | Normalizes the subnormal quadruple-precision floating-point value
 | represented by the denormalized significand formed by the concatenation of
 | `aSig0' and `aSig1'.  The normalized exponent is stored at the location
@@ -970,7 +1051,7 @@  static float128
             return packFloat128( zSign, 0x7FFF, 0, 0 );
         }
         if ( zExp < 0 ) {
-            if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 );
+            if ( STATUS(flush_outputs_to_zero) ) return packFloat128( zSign, 0, 0, 0 );
             isTiny =
                    ( STATUS(float_detect_tininess) == float_tininess_before_rounding )
                 || ( zExp < -1 )
@@ -1298,9 +1379,7 @@  int32 float32_to_int32( float32 a STATUS_PARAM )
     bits32 aSig;
     bits64 aSig64;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
     if ( ( aExp == 0xFF ) && aSig ) aSign = 0;
     if ( aExp ) aSig |= 0x00800000;
     shiftCount = 0xAF - aExp;
@@ -1328,9 +1407,7 @@  int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM )
     bits32 aSig;
     int32 z;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
     shiftCount = aExp - 0x9E;
     if ( 0 <= shiftCount ) {
         if ( float32_val(a) != 0xCF000000 ) {
@@ -1370,9 +1447,7 @@  int64 float32_to_int64( float32 a STATUS_PARAM )
     bits32 aSig;
     bits64 aSig64, aSigExtra;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
     shiftCount = 0xBE - aExp;
     if ( shiftCount < 0 ) {
         float_raise( float_flag_invalid STATUS_VAR);
@@ -1407,9 +1482,7 @@  int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM )
     bits64 aSig64;
     int64 z;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
     shiftCount = aExp - 0xBE;
     if ( 0 <= shiftCount ) {
         if ( float32_val(a) != 0xDF000000 ) {
@@ -1448,9 +1521,7 @@  float64 float32_to_float64( float32 a STATUS_PARAM )
     int16 aExp;
     bits32 aSig;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
     if ( aExp == 0xFF ) {
         if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a STATUS_VAR ));
         return packFloat64( aSign, 0x7FF, 0 );
@@ -1479,9 +1550,7 @@  floatx80 float32_to_floatx80( float32 a STATUS_PARAM )
     int16 aExp;
     bits32 aSig;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
     if ( aExp == 0xFF ) {
         if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a STATUS_VAR ) );
         return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
@@ -1512,9 +1581,7 @@  float128 float32_to_float128( float32 a STATUS_PARAM )
     int16 aExp;
     bits32 aSig;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
     if ( aExp == 0xFF ) {
         if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a STATUS_VAR ) );
         return packFloat128( aSign, 0x7FFF, 0, 0 );
@@ -1602,11 +1669,10 @@  static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
     int16 aExp, bExp, zExp;
     bits32 aSig, bSig, zSig;
     int16 expDiff;
+    flag dummySign;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    bSig = extractFloat32Frac( b );
-    bExp = extractFloat32Exp( b );
+    unpackFloat32( a, &aSig, &aExp, &dummySign STATUS_VAR);
+    unpackFloat32( b, &bSig, &bExp, &dummySign STATUS_VAR);
     expDiff = aExp - bExp;
     aSig <<= 6;
     bSig <<= 6;
@@ -1644,7 +1710,7 @@  static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
             return a;
         }
         if ( aExp == 0 ) {
-            if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 );
+            if ( STATUS(flush_outputs_to_zero) ) return packFloat32( zSign, 0, 0 );
             return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
         }
         zSig = 0x40000000 + aSig + bSig;
@@ -1676,11 +1742,10 @@  static float32 subFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM)
     int16 aExp, bExp, zExp;
     bits32 aSig, bSig, zSig;
     int16 expDiff;
+    flag dummySign;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    bSig = extractFloat32Frac( b );
-    bExp = extractFloat32Exp( b );
+    unpackFloat32( a, &aSig, &aExp, &dummySign STATUS_VAR);
+    unpackFloat32( b, &bSig, &bExp, &dummySign STATUS_VAR);
     expDiff = aExp - bExp;
     aSig <<= 7;
     bSig <<= 7;
@@ -1794,12 +1859,8 @@  float32 float32_mul( float32 a, float32 b STATUS_PARAM )
     bits64 zSig64;
     bits32 zSig;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
-    bSig = extractFloat32Frac( b );
-    bExp = extractFloat32Exp( b );
-    bSign = extractFloat32Sign( b );
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
+    unpackFloat32( b, &bSig, &bExp, &bSign STATUS_VAR);
     zSign = aSign ^ bSign;
     if ( aExp == 0xFF ) {
         if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
@@ -1852,12 +1913,8 @@  float32 float32_div( float32 a, float32 b STATUS_PARAM )
     int16 aExp, bExp, zExp;
     bits32 aSig, bSig, zSig;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
-    bSig = extractFloat32Frac( b );
-    bExp = extractFloat32Exp( b );
-    bSign = extractFloat32Sign( b );
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
+    unpackFloat32( b, &bSig, &bExp, &bSign STATUS_VAR);
     zSign = aSign ^ bSign;
     if ( aExp == 0xFF ) {
         if ( aSig ) return propagateFloat32NaN( a, b STATUS_VAR );
@@ -1918,11 +1975,8 @@  float32 float32_rem( float32 a, float32 b STATUS_PARAM )
     bits32 alternateASig;
     sbits32 sigMean;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
-    bSig = extractFloat32Frac( b );
-    bExp = extractFloat32Exp( b );
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
+    unpackFloat32( b, &bSig, &bExp, &zSign STATUS_VAR);
     if ( aExp == 0xFF ) {
         if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
             return propagateFloat32NaN( a, b STATUS_VAR );
@@ -2014,9 +2068,7 @@  float32 float32_sqrt( float32 a STATUS_PARAM )
     bits32 aSig, zSig;
     bits64 rem, term;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
     if ( aExp == 0xFF ) {
         if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR );
         if ( ! aSign ) return a;
@@ -2066,9 +2118,7 @@  float32 float32_log2( float32 a STATUS_PARAM )
     int16 aExp;
     bits32 aSig, zSig, i;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
 
     if ( aExp == 0 ) {
         if ( aSig == 0 ) return packFloat32( 1, 0xFF, 0 );
@@ -2110,9 +2160,14 @@  float32 float32_log2( float32 a STATUS_PARAM )
 
 int float32_eq( float32 a, float32 b STATUS_PARAM )
 {
+    flag aSign, bSign;
+    int16 aExp, bExp;
+    bits32 aSig, bSig;
 
-    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
-         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
+    unpackFloat32( b, &bSig, &bExp, &bSign STATUS_VAR);
+    if (    ( ( aExp == 0xFF ) && aSig )
+         || ( ( bExp == 0xFF ) && bSig )
        ) {
         if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
             float_raise( float_flag_invalid STATUS_VAR);
@@ -2134,16 +2189,18 @@  int float32_eq( float32 a, float32 b STATUS_PARAM )
 int float32_le( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    int16 aExp, bExp;
+    bits32 aSig, bSig;
     bits32 av, bv;
 
-    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
-         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
+    unpackFloat32( b, &bSig, &bExp, &bSign STATUS_VAR);
+    if (    ( ( aExp == 0xFF ) && aSig )
+         || ( ( bExp == 0xFF ) && bSig )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
         return 0;
     }
-    aSign = extractFloat32Sign( a );
-    bSign = extractFloat32Sign( b );
     av = float32_val(a);
     bv = float32_val(b);
     if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 );
@@ -2160,16 +2217,18 @@  int float32_le( float32 a, float32 b STATUS_PARAM )
 int float32_lt( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    int16 aExp, bExp;
+    bits32 aSig, bSig;
     bits32 av, bv;
 
-    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
-         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
+    unpackFloat32( b, &bSig, &bExp, &bSign STATUS_VAR);
+    if (    ( ( aExp == 0xFF ) && aSig )
+         || ( ( bExp == 0xFF ) && bSig )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
         return 0;
     }
-    aSign = extractFloat32Sign( a );
-    bSign = extractFloat32Sign( b );
     av = float32_val(a);
     bv = float32_val(b);
     if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 );
@@ -2186,10 +2245,15 @@  int float32_lt( float32 a, float32 b STATUS_PARAM )
 
 int float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
 {
+    flag aSign, bSign;
+    int16 aExp, bExp;
+    bits32 aSig, bSig;
     bits32 av, bv;
 
-    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
-         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
+    unpackFloat32( b, &bSig, &bExp, &bSign STATUS_VAR);
+    if (    ( ( aExp == 0xFF ) && aSig )
+         || ( ( bExp == 0xFF ) && bSig )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
         return 0;
@@ -2210,18 +2274,20 @@  int float32_eq_signaling( float32 a, float32 b STATUS_PARAM )
 int float32_le_quiet( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    int16 aExp, bExp;
+    bits32 aSig, bSig;
     bits32 av, bv;
 
-    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
-         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
+    unpackFloat32( b, &bSig, &bExp, &bSign STATUS_VAR);
+    if (    ( ( aExp == 0xFF ) && aSig )
+         || ( ( bExp == 0xFF ) && bSig )
        ) {
         if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
             float_raise( float_flag_invalid STATUS_VAR);
         }
         return 0;
     }
-    aSign = extractFloat32Sign( a );
-    bSign = extractFloat32Sign( b );
     av = float32_val(a);
     bv = float32_val(b);
     if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 );
@@ -2239,18 +2305,20 @@  int float32_le_quiet( float32 a, float32 b STATUS_PARAM )
 int float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    int16 aExp, bExp;
+    bits32 aSig, bSig;
     bits32 av, bv;
 
-    if (    ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
-         || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
+    unpackFloat32( b, &bSig, &bExp, &bSign STATUS_VAR);
+    if (    ( ( aExp == 0xFF ) && aSig )
+         || ( ( bExp == 0xFF ) && bSig )
        ) {
         if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
             float_raise( float_flag_invalid STATUS_VAR);
         }
         return 0;
     }
-    aSign = extractFloat32Sign( a );
-    bSign = extractFloat32Sign( b );
     av = float32_val(a);
     bv = float32_val(b);
     if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 );
@@ -2274,9 +2342,7 @@  int32 float64_to_int32( float64 a STATUS_PARAM )
     int16 aExp, shiftCount;
     bits64 aSig;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
     if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
     if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
     shiftCount = 0x42C - aExp;
@@ -2302,9 +2368,7 @@  int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM )
     bits64 aSig, savedASig;
     int32 z;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
     if ( 0x41E < aExp ) {
         if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
         goto invalid;
@@ -2347,9 +2411,7 @@  int64 float64_to_int64( float64 a STATUS_PARAM )
     int16 aExp, shiftCount;
     bits64 aSig, aSigExtra;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
     if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
     shiftCount = 0x433 - aExp;
     if ( shiftCount <= 0 ) {
@@ -2390,9 +2452,7 @@  int64 float64_to_int64_round_to_zero( float64 a STATUS_PARAM )
     bits64 aSig;
     int64 z;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
     if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
     shiftCount = aExp - 0x433;
     if ( 0 <= shiftCount ) {
@@ -2439,9 +2499,7 @@  float32 float64_to_float32( float64 a STATUS_PARAM )
     bits64 aSig;
     bits32 zSig;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
     if ( aExp == 0x7FF ) {
         if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a STATUS_VAR ) );
         return packFloat32( aSign, 0xFF, 0 );
@@ -2516,9 +2574,7 @@  bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM)
     bits32 increment;
     int8 roundingMode;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
     if ( aExp == 0xFF ) {
         if (aSig) {
             /* Make sure correct exceptions are raised.  */
@@ -2609,9 +2665,7 @@  floatx80 float64_to_floatx80( float64 a STATUS_PARAM )
     int16 aExp;
     bits64 aSig;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
     if ( aExp == 0x7FF ) {
         if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a STATUS_VAR ) );
         return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
@@ -2643,9 +2697,7 @@  float128 float64_to_float128( float64 a STATUS_PARAM )
     int16 aExp;
     bits64 aSig, zSig0, zSig1;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
     if ( aExp == 0x7FF ) {
         if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a STATUS_VAR ) );
         return packFloat128( aSign, 0x7FFF, 0, 0 );
@@ -2747,11 +2799,10 @@  static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
     int16 aExp, bExp, zExp;
     bits64 aSig, bSig, zSig;
     int16 expDiff;
+    flag dummySign;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    bSig = extractFloat64Frac( b );
-    bExp = extractFloat64Exp( b );
+    unpackFloat64( a, &aSig, &aExp, &dummySign STATUS_VAR );
+    unpackFloat64( b, &bSig, &bExp, &dummySign STATUS_VAR );
     expDiff = aExp - bExp;
     aSig <<= 9;
     bSig <<= 9;
@@ -2789,7 +2840,7 @@  static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
             return a;
         }
         if ( aExp == 0 ) {
-            if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 );
+            if ( STATUS(flush_outputs_to_zero) ) return packFloat64( zSign, 0, 0 );
             return packFloat64( zSign, 0, ( aSig + bSig )>>9 );
         }
         zSig = LIT64( 0x4000000000000000 ) + aSig + bSig;
@@ -2821,11 +2872,10 @@  static float64 subFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM )
     int16 aExp, bExp, zExp;
     bits64 aSig, bSig, zSig;
     int16 expDiff;
+    flag dummySign;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    bSig = extractFloat64Frac( b );
-    bExp = extractFloat64Exp( b );
+    unpackFloat64( a, &aSig, &aExp, &dummySign STATUS_VAR );
+    unpackFloat64( b, &bSig, &bExp, &dummySign STATUS_VAR );
     expDiff = aExp - bExp;
     aSig <<= 10;
     bSig <<= 10;
@@ -2937,12 +2987,8 @@  float64 float64_mul( float64 a, float64 b STATUS_PARAM )
     int16 aExp, bExp, zExp;
     bits64 aSig, bSig, zSig0, zSig1;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
-    bSig = extractFloat64Frac( b );
-    bExp = extractFloat64Exp( b );
-    bSign = extractFloat64Sign( b );
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloat64( b, &bSig, &bExp, &bSign STATUS_VAR );
     zSign = aSign ^ bSign;
     if ( aExp == 0x7FF ) {
         if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) {
@@ -2997,12 +3043,8 @@  float64 float64_div( float64 a, float64 b STATUS_PARAM )
     bits64 rem0, rem1;
     bits64 term0, term1;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
-    bSig = extractFloat64Frac( b );
-    bExp = extractFloat64Exp( b );
-    bSign = extractFloat64Sign( b );
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloat64( b, &bSig, &bExp, &bSign STATUS_VAR );
     zSign = aSign ^ bSign;
     if ( aExp == 0x7FF ) {
         if ( aSig ) return propagateFloat64NaN( a, b STATUS_VAR );
@@ -3067,11 +3109,8 @@  float64 float64_rem( float64 a, float64 b STATUS_PARAM )
     bits64 q, alternateASig;
     sbits64 sigMean;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
-    bSig = extractFloat64Frac( b );
-    bExp = extractFloat64Exp( b );
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloat64( b, &bSig, &bExp, &zSign STATUS_VAR );
     if ( aExp == 0x7FF ) {
         if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) {
             return propagateFloat64NaN( a, b STATUS_VAR );
@@ -3150,9 +3189,7 @@  float64 float64_sqrt( float64 a STATUS_PARAM )
     bits64 aSig, zSig, doubleZSig;
     bits64 rem0, rem1, term0, term1;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
     if ( aExp == 0x7FF ) {
         if ( aSig ) return propagateFloat64NaN( a, a STATUS_VAR );
         if ( ! aSign ) return a;
@@ -3199,9 +3236,7 @@  float64 float64_log2( float64 a STATUS_PARAM )
     int16 aExp;
     bits64 aSig, aSig0, aSig1, zSig, i;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
 
     if ( aExp == 0 ) {
         if ( aSig == 0 ) return packFloat64( 1, 0x7FF, 0 );
@@ -3242,10 +3277,15 @@  float64 float64_log2( float64 a STATUS_PARAM )
 
 int float64_eq( float64 a, float64 b STATUS_PARAM )
 {
+    flag aSign, bSign;
+    int16 aExp, bExp;
+    bits64 aSig, bSig;
     bits64 av, bv;
 
-    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
-         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloat64( b, &bSig, &bExp, &bSign STATUS_VAR );
+    if (    ( ( aExp == 0x7FF ) && aSig )
+         || ( ( bExp == 0x7FF ) && bSig )
        ) {
         if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
             float_raise( float_flag_invalid STATUS_VAR);
@@ -3268,16 +3308,18 @@  int float64_eq( float64 a, float64 b STATUS_PARAM )
 int float64_le( float64 a, float64 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    int16 aExp, bExp;
+    bits64 aSig, bSig;
     bits64 av, bv;
 
-    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
-         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloat64( b, &bSig, &bExp, &bSign STATUS_VAR );
+    if (    ( ( aExp == 0x7FF ) && aSig )
+         || ( ( bExp == 0x7FF ) && bSig )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
         return 0;
     }
-    aSign = extractFloat64Sign( a );
-    bSign = extractFloat64Sign( b );
     av = float64_val(a);
     bv = float64_val(b);
     if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 );
@@ -3294,16 +3336,18 @@  int float64_le( float64 a, float64 b STATUS_PARAM )
 int float64_lt( float64 a, float64 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    int16 aExp, bExp;
+    bits64 aSig, bSig;
     bits64 av, bv;
 
-    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
-         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloat64( b, &bSig, &bExp, &bSign STATUS_VAR );
+    if (    ( ( aExp == 0x7FF ) && aSig )
+         || ( ( bExp == 0x7FF ) && bSig )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
         return 0;
     }
-    aSign = extractFloat64Sign( a );
-    bSign = extractFloat64Sign( b );
     av = float64_val(a);
     bv = float64_val(b);
     if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 );
@@ -3320,10 +3364,15 @@  int float64_lt( float64 a, float64 b STATUS_PARAM )
 
 int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
 {
+    flag aSign, bSign;
+    int16 aExp, bExp;
+    bits64 aSig, bSig;
     bits64 av, bv;
 
-    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
-         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloat64( b, &bSig, &bExp, &bSign STATUS_VAR );
+    if (    ( ( aExp == 0x7FF ) && aSig )
+         || ( ( bExp == 0x7FF ) && bSig )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
         return 0;
@@ -3344,18 +3393,20 @@  int float64_eq_signaling( float64 a, float64 b STATUS_PARAM )
 int float64_le_quiet( float64 a, float64 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    int16 aExp, bExp;
+    bits64 aSig, bSig;
     bits64 av, bv;
 
-    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
-         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloat64( b, &bSig, &bExp, &bSign STATUS_VAR );
+    if (    ( ( aExp == 0x7FF ) && aSig )
+         || ( ( bExp == 0x7FF ) && bSig )
        ) {
         if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
             float_raise( float_flag_invalid STATUS_VAR);
         }
         return 0;
     }
-    aSign = extractFloat64Sign( a );
-    bSign = extractFloat64Sign( b );
     av = float64_val(a);
     bv = float64_val(b);
     if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 );
@@ -3373,18 +3424,20 @@  int float64_le_quiet( float64 a, float64 b STATUS_PARAM )
 int float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    int16 aExp, bExp;
+    bits64 aSig, bSig;
     bits64 av, bv;
 
-    if (    ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
-         || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloat64( b, &bSig, &bExp, &bSign STATUS_VAR );
+    if (    ( ( aExp == 0x7FF ) && aSig )
+         || ( ( bExp == 0x7FF ) && bSig )
        ) {
         if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
             float_raise( float_flag_invalid STATUS_VAR);
         }
         return 0;
     }
-    aSign = extractFloat64Sign( a );
-    bSign = extractFloat64Sign( b );
     av = float64_val(a);
     bv = float64_val(b);
     if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 );
@@ -3410,9 +3463,7 @@  int32 floatx80_to_int32( floatx80 a STATUS_PARAM )
     int32 aExp, shiftCount;
     bits64 aSig;
 
-    aSig = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    aSign = extractFloatx80Sign( a );
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
     if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0;
     shiftCount = 0x4037 - aExp;
     if ( shiftCount <= 0 ) shiftCount = 1;
@@ -3438,9 +3489,7 @@  int32 floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM )
     bits64 aSig, savedASig;
     int32 z;
 
-    aSig = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    aSign = extractFloatx80Sign( a );
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
     if ( 0x401E < aExp ) {
         if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0;
         goto invalid;
@@ -3482,9 +3531,7 @@  int64 floatx80_to_int64( floatx80 a STATUS_PARAM )
     int32 aExp, shiftCount;
     bits64 aSig, aSigExtra;
 
-    aSig = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    aSign = extractFloatx80Sign( a );
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
     shiftCount = 0x403E - aExp;
     if ( shiftCount <= 0 ) {
         if ( shiftCount ) {
@@ -3523,9 +3570,7 @@  int64 floatx80_to_int64_round_to_zero( floatx80 a STATUS_PARAM )
     bits64 aSig;
     int64 z;
 
-    aSig = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    aSign = extractFloatx80Sign( a );
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
     shiftCount = aExp - 0x403E;
     if ( 0 <= shiftCount ) {
         aSig &= LIT64( 0x7FFFFFFFFFFFFFFF );
@@ -3563,9 +3608,7 @@  float32 floatx80_to_float32( floatx80 a STATUS_PARAM )
     int32 aExp;
     bits64 aSig;
 
-    aSig = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    aSign = extractFloatx80Sign( a );
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
     if ( aExp == 0x7FFF ) {
         if ( (bits64) ( aSig<<1 ) ) {
             return commonNaNToFloat32( floatx80ToCommonNaN( a STATUS_VAR ) );
@@ -3591,9 +3634,7 @@  float64 floatx80_to_float64( floatx80 a STATUS_PARAM )
     int32 aExp;
     bits64 aSig, zSig;
 
-    aSig = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    aSign = extractFloatx80Sign( a );
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
     if ( aExp == 0x7FFF ) {
         if ( (bits64) ( aSig<<1 ) ) {
             return commonNaNToFloat64( floatx80ToCommonNaN( a STATUS_VAR ) );
@@ -3621,9 +3662,7 @@  float128 floatx80_to_float128( floatx80 a STATUS_PARAM )
     int16 aExp;
     bits64 aSig, zSig0, zSig1;
 
-    aSig = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    aSign = extractFloatx80Sign( a );
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
     if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) {
         return commonNaNToFloat128( floatx80ToCommonNaN( a STATUS_VAR ) );
     }
@@ -3720,11 +3759,10 @@  static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM
     int32 aExp, bExp, zExp;
     bits64 aSig, bSig, zSig0, zSig1;
     int32 expDiff;
+    flag dummySign;
 
-    aSig = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    bSig = extractFloatx80Frac( b );
-    bExp = extractFloatx80Exp( b );
+    unpackFloatx80( a, &aSig, &aExp, &dummySign STATUS_VAR );
+    unpackFloatx80( b, &bSig, &bExp, &dummySign STATUS_VAR );
     expDiff = aExp - bExp;
     if ( 0 < expDiff ) {
         if ( aExp == 0x7FFF ) {
@@ -3787,11 +3825,10 @@  static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM
     bits64 aSig, bSig, zSig0, zSig1;
     int32 expDiff;
     floatx80 z;
+    flag dummySign;
 
-    aSig = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    bSig = extractFloatx80Frac( b );
-    bExp = extractFloatx80Exp( b );
+    unpackFloatx80( a, &aSig, &aExp, &dummySign STATUS_VAR );
+    unpackFloatx80( b, &bSig, &bExp, &dummySign STATUS_VAR );
     expDiff = aExp - bExp;
     if ( 0 < expDiff ) goto aExpBigger;
     if ( expDiff < 0 ) goto bExpBigger;
@@ -3896,12 +3933,8 @@  floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM )
     bits64 aSig, bSig, zSig0, zSig1;
     floatx80 z;
 
-    aSig = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    aSign = extractFloatx80Sign( a );
-    bSig = extractFloatx80Frac( b );
-    bExp = extractFloatx80Exp( b );
-    bSign = extractFloatx80Sign( b );
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloatx80( b, &bSig, &bExp, &bSign STATUS_VAR );
     zSign = aSign ^ bSign;
     if ( aExp == 0x7FFF ) {
         if (    (bits64) ( aSig<<1 )
@@ -3956,12 +3989,8 @@  floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM )
     bits64 rem0, rem1, rem2, term0, term1, term2;
     floatx80 z;
 
-    aSig = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    aSign = extractFloatx80Sign( a );
-    bSig = extractFloatx80Frac( b );
-    bExp = extractFloatx80Exp( b );
-    bSign = extractFloatx80Sign( b );
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloatx80( b, &bSig, &bExp, &bSign STATUS_VAR );
     zSign = aSign ^ bSign;
     if ( aExp == 0x7FFF ) {
         if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR );
@@ -4036,11 +4065,8 @@  floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM )
     bits64 q, term0, term1, alternateASig0, alternateASig1;
     floatx80 z;
 
-    aSig0 = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    aSign = extractFloatx80Sign( a );
-    bSig = extractFloatx80Frac( b );
-    bExp = extractFloatx80Exp( b );
+    unpackFloatx80( a, &aSig0, &aExp, &aSign STATUS_VAR );
+    unpackFloatx80( b, &bSig, &bExp, &zSign STATUS_VAR );
     if ( aExp == 0x7FFF ) {
         if (    (bits64) ( aSig0<<1 )
              || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) {
@@ -4132,9 +4158,7 @@  floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM )
     bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
     floatx80 z;
 
-    aSig0 = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    aSign = extractFloatx80Sign( a );
+    unpackFloatx80( a, &aSig0, &aExp, &aSign STATUS_VAR );
     if ( aExp == 0x7FFF ) {
         if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a STATUS_VAR );
         if ( ! aSign ) return a;
@@ -4197,11 +4221,16 @@  floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM )
 
 int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
 {
+    flag aSign, bSign;
+    int16 aExp, bExp;
+    bits64 aSig, bSig;
 
-    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
-         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloatx80( b, &bSig, &bExp, &bSign STATUS_VAR );
+    if (    (    ( aExp == 0x7FFF )
+              && (bits64) ( aSig<<1 ) )
+         || (    ( bExp == 0x7FFF )
+              && (bits64) ( bSig<<1 ) )
        ) {
         if (    floatx80_is_signaling_nan( a )
              || floatx80_is_signaling_nan( b ) ) {
@@ -4228,17 +4257,19 @@  int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM )
 int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    int16 aExp, bExp;
+    bits64 aSig, bSig;
 
-    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
-         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloatx80( b, &bSig, &bExp, &bSign STATUS_VAR );
+    if (    (    ( aExp == 0x7FFF )
+              && (bits64) ( aSig<<1 ) )
+         || (    ( bExp == 0x7FFF )
+              && (bits64) ( bSig<<1 ) )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
         return 0;
     }
-    aSign = extractFloatx80Sign( a );
-    bSign = extractFloatx80Sign( b );
     if ( aSign != bSign ) {
         return
                aSign
@@ -4261,17 +4292,19 @@  int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM )
 int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    int16 aExp, bExp;
+    bits64 aSig, bSig;
 
-    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
-         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloatx80( b, &bSig, &bExp, &bSign STATUS_VAR );
+    if (    (    ( aExp == 0x7FFF )
+              && (bits64) ( aSig<<1 ) )
+         || (    ( bExp == 0x7FFF )
+              && (bits64) ( bSig<<1 ) )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
         return 0;
     }
-    aSign = extractFloatx80Sign( a );
-    bSign = extractFloatx80Sign( b );
     if ( aSign != bSign ) {
         return
                aSign
@@ -4293,11 +4326,16 @@  int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM )
 
 int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
 {
+    flag aSign, bSign;
+    int16 aExp, bExp;
+    bits64 aSig, bSig;
 
-    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
-         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloatx80( b, &bSig, &bExp, &bSign STATUS_VAR );
+    if (    (    ( aExp == 0x7FFF )
+              && (bits64) ( aSig<<1 ) )
+         || (    ( bExp == 0x7FFF )
+              && (bits64) ( bSig<<1 ) )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
         return 0;
@@ -4321,11 +4359,15 @@  int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM )
 int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    int16 aExp, bExp;
+    bits64 aSig, bSig;
 
-    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
-         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloatx80( b, &bSig, &bExp, &bSign STATUS_VAR );
+    if (    (    ( aExp == 0x7FFF )
+              && (bits64) ( aSig<<1 ) )
+         || (    ( bExp == 0x7FFF )
+              && (bits64) ( bSig<<1 ) )
        ) {
         if (    floatx80_is_signaling_nan( a )
              || floatx80_is_signaling_nan( b ) ) {
@@ -4333,8 +4375,6 @@  int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
         }
         return 0;
     }
-    aSign = extractFloatx80Sign( a );
-    bSign = extractFloatx80Sign( b );
     if ( aSign != bSign ) {
         return
                aSign
@@ -4357,11 +4397,15 @@  int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM )
 int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM )
 {
     flag aSign, bSign;
+    int16 aExp, bExp;
+    bits64 aSig, bSig;
 
-    if (    (    ( extractFloatx80Exp( a ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( a )<<1 ) )
-         || (    ( extractFloatx80Exp( b ) == 0x7FFF )
-              && (bits64) ( extractFloatx80Frac( b )<<1 ) )
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
+    unpackFloatx80( b, &bSig, &bExp, &bSign STATUS_VAR );
+    if (    (    ( aExp == 0x7FFF )
+              && (bits64) ( aSig<<1 ) )
+         || (    ( bExp == 0x7FFF )
+              && (bits64) ( bSig<<1 ) )
        ) {
         if (    floatx80_is_signaling_nan( a )
              || floatx80_is_signaling_nan( b ) ) {
@@ -4369,8 +4413,6 @@  int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM )
         }
         return 0;
     }
-    aSign = extractFloatx80Sign( a );
-    bSign = extractFloatx80Sign( b );
     if ( aSign != bSign ) {
         return
                aSign
@@ -4403,10 +4445,7 @@  int32 float128_to_int32( float128 a STATUS_PARAM )
     int32 aExp, shiftCount;
     bits64 aSig0, aSig1;
 
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
     if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0;
     if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
     aSig0 |= ( aSig1 != 0 );
@@ -4433,10 +4472,7 @@  int32 float128_to_int32_round_to_zero( float128 a STATUS_PARAM )
     bits64 aSig0, aSig1, savedASig;
     int32 z;
 
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
     aSig0 |= ( aSig1 != 0 );
     if ( 0x401E < aExp ) {
         if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0;
@@ -4480,10 +4516,7 @@  int64 float128_to_int64( float128 a STATUS_PARAM )
     int32 aExp, shiftCount;
     bits64 aSig0, aSig1;
 
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
     if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
     shiftCount = 0x402F - aExp;
     if ( shiftCount <= 0 ) {
@@ -4524,10 +4557,7 @@  int64 float128_to_int64_round_to_zero( float128 a STATUS_PARAM )
     bits64 aSig0, aSig1;
     int64 z;
 
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
     if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
     shiftCount = aExp - 0x402F;
     if ( 0 < shiftCount ) {
@@ -4582,10 +4612,7 @@  float32 float128_to_float32( float128 a STATUS_PARAM )
     bits64 aSig0, aSig1;
     bits32 zSig;
 
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
     if ( aExp == 0x7FFF ) {
         if ( aSig0 | aSig1 ) {
             return commonNaNToFloat32( float128ToCommonNaN( a STATUS_VAR ) );
@@ -4616,10 +4643,7 @@  float64 float128_to_float64( float128 a STATUS_PARAM )
     int32 aExp;
     bits64 aSig0, aSig1;
 
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
     if ( aExp == 0x7FFF ) {
         if ( aSig0 | aSig1 ) {
             return commonNaNToFloat64( float128ToCommonNaN( a STATUS_VAR ) );
@@ -4651,10 +4675,7 @@  floatx80 float128_to_floatx80( float128 a STATUS_PARAM )
     int32 aExp;
     bits64 aSig0, aSig1;
 
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
     if ( aExp == 0x7FFF ) {
         if ( aSig0 | aSig1 ) {
             return commonNaNToFloatx80( float128ToCommonNaN( a STATUS_VAR ) );
@@ -4791,13 +4812,10 @@  static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM
     int32 aExp, bExp, zExp;
     bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
     int32 expDiff;
+    flag dummySign;
 
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &dummySign STATUS_VAR );
+    unpackFloat128( b, &bSig1, &bSig0, &bExp, &dummySign STATUS_VAR );
     expDiff = aExp - bExp;
     if ( 0 < expDiff ) {
         if ( aExp == 0x7FFF ) {
@@ -4838,7 +4856,7 @@  static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM
         }
         add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
         if ( aExp == 0 ) {
-            if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 );
+            if ( STATUS(flush_outputs_to_zero) ) return packFloat128( zSign, 0, 0, 0 );
             return packFloat128( zSign, 0, zSig0, zSig1 );
         }
         zSig2 = 0;
@@ -4873,13 +4891,10 @@  static float128 subFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM
     bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
     int32 expDiff;
     float128 z;
+    flag dummySign;
 
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &dummySign STATUS_VAR );
+    unpackFloat128( b, &bSig1, &bSig0, &bExp, &dummySign STATUS_VAR );
     expDiff = aExp - bExp;
     shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
     shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 );
@@ -4998,14 +5013,8 @@  float128 float128_mul( float128 a, float128 b STATUS_PARAM )
     bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
     float128 z;
 
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
-    bSign = extractFloat128Sign( b );
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
+    unpackFloat128( b, &bSig1, &bSig0, &bExp, &bSign STATUS_VAR );
     zSign = aSign ^ bSign;
     if ( aExp == 0x7FFF ) {
         if (    ( aSig0 | aSig1 )
@@ -5063,14 +5072,8 @@  float128 float128_div( float128 a, float128 b STATUS_PARAM )
     bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
     float128 z;
 
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
-    bSign = extractFloat128Sign( b );
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
+    unpackFloat128( b, &bSig1, &bSig0, &bExp, &bSign STATUS_VAR );
     zSign = aSign ^ bSign;
     if ( aExp == 0x7FFF ) {
         if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b STATUS_VAR );
@@ -5148,13 +5151,8 @@  float128 float128_rem( float128 a, float128 b STATUS_PARAM )
     sbits64 sigMean0;
     float128 z;
 
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
-    bSig1 = extractFloat128Frac1( b );
-    bSig0 = extractFloat128Frac0( b );
-    bExp = extractFloat128Exp( b );
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
+    unpackFloat128( b, &bSig1, &bSig0, &bExp, &zSign STATUS_VAR );
     if ( aExp == 0x7FFF ) {
         if (    ( aSig0 | aSig1 )
              || ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
@@ -5256,10 +5254,7 @@  float128 float128_sqrt( float128 a STATUS_PARAM )
     bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
     float128 z;
 
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
     if ( aExp == 0x7FFF ) {
         if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a STATUS_VAR );
         if ( ! aSign ) return a;
@@ -5319,11 +5314,16 @@  float128 float128_sqrt( float128 a STATUS_PARAM )
 
 int float128_eq( float128 a, float128 b STATUS_PARAM )
 {
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+    flag aSign, bSign;
+    int32 aExp, bExp;
+    bits64 aSig0, aSig1, bSig0, bSig1;
+
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
+    unpackFloat128( b, &bSig1, &bSig0, &bExp, &bSign STATUS_VAR );
+    if (    (    ( aExp == 0x7FFF )
+              && ( aSig0 | aSig1 ) )
+         || (    ( bExp == 0x7FFF )
+              && ( bSig0 | bSig1 ) )
        ) {
         if (    float128_is_signaling_nan( a )
              || float128_is_signaling_nan( b ) ) {
@@ -5350,17 +5350,19 @@  int float128_eq( float128 a, float128 b STATUS_PARAM )
 int float128_le( float128 a, float128 b STATUS_PARAM )
 {
     flag aSign, bSign;
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+    int32 aExp, bExp;
+    bits64 aSig0, aSig1, bSig0, bSig1;
+
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
+    unpackFloat128( b, &bSig1, &bSig0, &bExp, &bSign STATUS_VAR );
+    if (    (    ( aExp == 0x7FFF )
+              && ( aSig0 | aSig1 ) )
+         || (    ( bExp == 0x7FFF )
+              && ( bSig0 | bSig1 ) )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
         return 0;
     }
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
     if ( aSign != bSign ) {
         return
                aSign
@@ -5382,17 +5384,19 @@  int float128_le( float128 a, float128 b STATUS_PARAM )
 int float128_lt( float128 a, float128 b STATUS_PARAM )
 {
     flag aSign, bSign;
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+    int32 aExp, bExp;
+    bits64 aSig0, aSig1, bSig0, bSig1;
+
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
+    unpackFloat128( b, &bSig1, &bSig0, &bExp, &bSign STATUS_VAR );
+    if (    (    ( aExp == 0x7FFF )
+              && ( aSig0 | aSig1 ) )
+         || (    ( bExp == 0x7FFF )
+              && ( bSig0 | bSig1 ) )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
         return 0;
     }
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
     if ( aSign != bSign ) {
         return
                aSign
@@ -5414,11 +5418,16 @@  int float128_lt( float128 a, float128 b STATUS_PARAM )
 
 int float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
 {
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+    flag aSign, bSign;
+    int32 aExp, bExp;
+    bits64 aSig0, aSig1, bSig0, bSig1;
+
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
+    unpackFloat128( b, &bSig1, &bSig0, &bExp, &bSign STATUS_VAR );
+    if (    (    ( aExp == 0x7FFF )
+              && ( aSig0 | aSig1 ) )
+         || (    ( bExp == 0x7FFF )
+              && ( bSig0 | bSig1 ) )
        ) {
         float_raise( float_flag_invalid STATUS_VAR);
         return 0;
@@ -5442,11 +5451,15 @@  int float128_eq_signaling( float128 a, float128 b STATUS_PARAM )
 int float128_le_quiet( float128 a, float128 b STATUS_PARAM )
 {
     flag aSign, bSign;
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+    int32 aExp, bExp;
+    bits64 aSig0, aSig1, bSig0, bSig1;
+
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
+    unpackFloat128( b, &bSig1, &bSig0, &bExp, &bSign STATUS_VAR );
+    if (    (    ( aExp == 0x7FFF )
+              && ( aSig0 | aSig1 ) )
+         || (    ( bExp == 0x7FFF )
+              && ( bSig0 | bSig1 ) )
        ) {
         if (    float128_is_signaling_nan( a )
              || float128_is_signaling_nan( b ) ) {
@@ -5454,8 +5467,6 @@  int float128_le_quiet( float128 a, float128 b STATUS_PARAM )
         }
         return 0;
     }
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
     if ( aSign != bSign ) {
         return
                aSign
@@ -5478,11 +5489,15 @@  int float128_le_quiet( float128 a, float128 b STATUS_PARAM )
 int float128_lt_quiet( float128 a, float128 b STATUS_PARAM )
 {
     flag aSign, bSign;
-
-    if (    (    ( extractFloat128Exp( a ) == 0x7FFF )
-              && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
-         || (    ( extractFloat128Exp( b ) == 0x7FFF )
-              && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
+    int32 aExp, bExp;
+    bits64 aSig0, aSig1, bSig0, bSig1;
+
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
+    unpackFloat128( b, &bSig1, &bSig0, &bExp, &bSign STATUS_VAR );
+    if (    (    ( aExp == 0x7FFF )
+              && ( aSig0 | aSig1 ) )
+         || (    ( bExp == 0x7FFF )
+              && ( bSig0 | bSig1 ) )
        ) {
         if (    float128_is_signaling_nan( a )
              || float128_is_signaling_nan( b ) ) {
@@ -5490,8 +5505,6 @@  int float128_lt_quiet( float128 a, float128 b STATUS_PARAM )
         }
         return 0;
     }
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
     if ( aSign != bSign ) {
         return
                aSign
@@ -5617,12 +5630,14 @@  INLINE int float ## s ## _compare_internal( float ## s a, float ## s b,      \
                                       int is_quiet STATUS_PARAM )            \
 {                                                                            \
     flag aSign, bSign;                                                       \
+    int16 aExp, bExp;                                                        \
+    bits ## s aSig, bSig;                                                    \
     bits ## s av, bv;                                                        \
                                                                              \
-    if (( ( extractFloat ## s ## Exp( a ) == nan_exp ) &&                    \
-         extractFloat ## s ## Frac( a ) ) ||                                 \
-        ( ( extractFloat ## s ## Exp( b ) == nan_exp ) &&                    \
-          extractFloat ## s ## Frac( b ) )) {                                \
+    unpackFloat ## s ( a, &aSig, &aExp, &aSign );                            \
+    unpackFloat ## s ( b, &bSig, &bExp, &bSign );                            \
+    if (( ( aExp == nan_exp ) && aSig ) ||                                   \
+        ( ( bExp == nan_exp ) && bSig )) {                                   \
         if (!is_quiet ||                                                     \
             float ## s ## _is_signaling_nan( a ) ||                          \
             float ## s ## _is_signaling_nan( b ) ) {                         \
@@ -5630,8 +5645,6 @@  INLINE int float ## s ## _compare_internal( float ## s a, float ## s b,      \
         }                                                                    \
         return float_relation_unordered;                                     \
     }                                                                        \
-    aSign = extractFloat ## s ## Sign( a );                                  \
-    bSign = extractFloat ## s ## Sign( b );                                  \
     av = float ## s ## _val(a);                                              \
     bv = float ## s ## _val(b);                                              \
     if ( aSign != bSign ) {                                                  \
@@ -5667,11 +5680,16 @@  INLINE int float128_compare_internal( float128 a, float128 b,
                                       int is_quiet STATUS_PARAM )
 {
     flag aSign, bSign;
-
-    if (( ( extractFloat128Exp( a ) == 0x7fff ) &&
-          ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) ||
-        ( ( extractFloat128Exp( b ) == 0x7fff ) &&
-          ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )) {
+    int32 aExp, bExp;
+    bits64 aSig0, aSig1, bSig0, bSig1;
+
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
+    unpackFloat128( b, &bSig1, &bSig0, &bExp, &bSign STATUS_VAR );
+    if (    (    ( aExp == 0x7FFF )
+              && ( aSig0 | aSig1 ) )
+         || (    ( bExp == 0x7FFF )
+              && ( bSig0 | bSig1 ) )
+       ) {
         if (!is_quiet ||
             float128_is_signaling_nan( a ) ||
             float128_is_signaling_nan( b ) ) {
@@ -5679,8 +5697,6 @@  INLINE int float128_compare_internal( float128 a, float128 b,
         }
         return float_relation_unordered;
     }
-    aSign = extractFloat128Sign( a );
-    bSign = extractFloat128Sign( b );
     if ( aSign != bSign ) {
         if ( ( ( ( a.high | b.high )<<1 ) | a.low | b.low ) == 0 ) {
             /* zero case */
@@ -5714,9 +5730,7 @@  float32 float32_scalbn( float32 a, int n STATUS_PARAM )
     int16 aExp;
     bits32 aSig;
 
-    aSig = extractFloat32Frac( a );
-    aExp = extractFloat32Exp( a );
-    aSign = extractFloat32Sign( a );
+    unpackFloat32( a, &aSig, &aExp, &aSign STATUS_VAR);
 
     if ( aExp == 0xFF ) {
         return a;
@@ -5737,9 +5751,7 @@  float64 float64_scalbn( float64 a, int n STATUS_PARAM )
     int16 aExp;
     bits64 aSig;
 
-    aSig = extractFloat64Frac( a );
-    aExp = extractFloat64Exp( a );
-    aSign = extractFloat64Sign( a );
+    unpackFloat64( a, &aSig, &aExp, &aSign STATUS_VAR );
 
     if ( aExp == 0x7FF ) {
         return a;
@@ -5761,9 +5773,7 @@  floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM )
     int16 aExp;
     bits64 aSig;
 
-    aSig = extractFloatx80Frac( a );
-    aExp = extractFloatx80Exp( a );
-    aSign = extractFloatx80Sign( a );
+    unpackFloatx80( a, &aSig, &aExp, &aSign STATUS_VAR );
 
     if ( aExp == 0x7FF ) {
         return a;
@@ -5784,10 +5794,7 @@  float128 float128_scalbn( float128 a, int n STATUS_PARAM )
     int32 aExp;
     bits64 aSig0, aSig1;
 
-    aSig1 = extractFloat128Frac1( a );
-    aSig0 = extractFloat128Frac0( a );
-    aExp = extractFloat128Exp( a );
-    aSign = extractFloat128Sign( a );
+    unpackFloat128( a, &aSig1, &aSig0, &aExp, &aSign STATUS_VAR );
     if ( aExp == 0x7FFF ) {
         return a;
     }
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 636591b..eb0d53b 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -180,7 +180,9 @@  enum {
     float_flag_divbyzero =  4,
     float_flag_overflow  =  8,
     float_flag_underflow = 16,
-    float_flag_inexact   = 32
+    float_flag_inexact   = 32,
+    /* Not strictly an IEEE flag, but implemented on several architectures.  */
+    float_flag_input_denormal = 64
 };
 
 typedef struct float_status {
@@ -190,15 +192,20 @@  typedef struct float_status {
 #ifdef FLOATX80
     signed char floatx80_rounding_precision;
 #endif
-    flag flush_to_zero;
+    flag flush_inputs_to_zero;
+    flag flush_outputs_to_zero;
     flag default_nan_mode;
 } float_status;
 
 void set_float_rounding_mode(int val STATUS_PARAM);
 void set_float_exception_flags(int val STATUS_PARAM);
-INLINE void set_flush_to_zero(flag val STATUS_PARAM)
+INLINE void set_flush_inputs_to_zero(flag val STATUS_PARAM)
 {
-    STATUS(flush_to_zero) = val;
+    STATUS(flush_inputs_to_zero) = val;
+}
+INLINE void set_flush_outputs_to_zero(flag val STATUS_PARAM)
+{
+    STATUS(flush_outputs_to_zero) = val;
 }
 INLINE void set_default_nan_mode(flag val STATUS_PARAM)
 {
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 18e22b1..723b368 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2209,6 +2209,8 @@  static inline int vfp_exceptbits_from_host(int host_bits)
         target_bits |= 8;
     if (host_bits & float_flag_inexact)
         target_bits |= 0x10;
+    if (host_bits & float_flag_input_denormal)
+        target_bits |= 0x80;
     return target_bits;
 }
 
@@ -2240,6 +2242,8 @@  static inline int vfp_exceptbits_to_host(int target_bits)
         host_bits |= float_flag_underflow;
     if (target_bits & 0x10)
         host_bits |= float_flag_inexact;
+    if (target_bits & 0x80)
+        host_bits |= float_flag_input_denormal;
     return host_bits;
 }
 
@@ -2272,8 +2276,11 @@  void HELPER(vfp_set_fpscr)(CPUState *env, uint32_t val)
         }
         set_float_rounding_mode(i, &env->vfp.fp_status);
     }
-    if (changed & (1 << 24))
-        set_flush_to_zero((val & (1 << 24)) != 0, &env->vfp.fp_status);
+    if (changed & (1 << 24)) {
+        i = (val & (1 << 24)) != 0;
+        set_flush_inputs_to_zero(i, &env->vfp.fp_status);
+        set_flush_outputs_to_zero(i, &env->vfp.fp_status);
+    }
     if (changed & (1 << 25))
         set_default_nan_mode((val & (1 << 25)) != 0, &env->vfp.fp_status);
 
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 2bfdd50..a46caf7 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -1897,8 +1897,14 @@  static unsigned int ieee_rm[] = {
 #define RESTORE_ROUNDING_MODE \
     set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status)
 
+/* FIXME: On most MIPS Technologies chips, there are other flags that interact with
+   FS in interesting ways.  */
 #define RESTORE_FLUSH_MODE \
-    set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status);
+    do { \
+    int flag = (env->active_fpu.fcr31 & (1 << 24)) != 0; \
+    set_flush_inputs_to_zero(flag, &env->active_fpu.fp_status); \
+    set_flush_outputs_to_zero(flag, &env->active_fpu.fp_status); \
+    } while (0);
 
 target_ulong helper_cfc1 (uint32_t reg)
 {
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 8f2ee98..95c22fb 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -2060,7 +2060,7 @@  void helper_mtvscr (ppc_avr_t *r)
 #else
     env->vscr = r->u32[0];
 #endif
-    set_flush_to_zero(vscr_nj, &env->vec_status);
+    set_flush_outputs_to_zero(vscr_nj, &env->vec_status);
 }
 
 void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index db4dc17..9b78ea7 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -507,7 +507,7 @@  static inline void vscr_init (CPUPPCState *env, uint32_t val)
     env->vscr = val;
     /* Altivec always uses round-to-nearest */
     set_float_rounding_mode(float_round_nearest_even, &env->vec_status);
-    set_flush_to_zero(vscr_nj, &env->vec_status);
+    set_flush_outputs_to_zero(vscr_nj, &env->vec_status);
 }
 
 #if defined(CONFIG_USER_ONLY)