* [Qemu-devel] QEMU state of ARM NEON support.
@ 2010-03-22 13:43 Dmitry Zhurikhin
2010-03-25 7:52 ` Juha.Riihimaki
0 siblings, 1 reply; 6+ messages in thread
From: Dmitry Zhurikhin @ 2010-03-22 13:43 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 1714 bytes --]
Hello. We made a small experiment to analyze QEMU state of NEON support. We
took our tests from Valgrind that we wrote to test support for all NEON
instructions and ran them inside of QEMU. I am attaching the output files from
trunk QEMU as well as reference file showing what output should be (taken from
the real test board). We find the results interesting. Overall NEON support is
great. Here is a list of what problems we've seen so far:
- To start with, QEMU translator doesn't support at all 128-bit polynomial
VMULL instruction and VSLI and VSRI instructions. Though there are two patches
in the mailing list to address missing VSLI and VSRI instructions problem. One
patch adds support only for VSLI instruction. The other adds support for both
of them but its emulation of VSLI instruction is incorrect.
- QEMU also raises 'Illegal instruction' interrupt on some kinds of VCVT
instructions and converts all values incorrectly. Seems like QEMU recognizes
VCVT as another instruction.
- Many instructions are emulated (partially) incorrectly. They include
VQSHL(U), V(Q)RSHL, VRSHR, V(R)SRA, VMUL, VMLA, VMLS, VMULL, VMLAL, VMLSL, VZIP,
128-bit VUZP, 64-bit V(Q)(R)SHR(U)N, VQ(R)DMUL(L,H), VQDMLSL, VQDMLAL, VSHLL,
VRECPE and VRSQRT(E,S).
- Encoding of integer constants with cmode 1101 is processed incorrectly (see
VMOV or VMVN).
- Flush-to-zero is not performed before executing floating-point NEON
instructions as it should be (which results in incorrect VCGT and VCLE
instructions result).
- Saturation flag is not set.
- QEMU reports "Internal resource leak"s for some instructions.
Hope this information will be helpful.
Regards,
Dmitry
[-- Attachment #2: qemu-neon-test.tar.bz2 --]
[-- Type: application/x-bzip, Size: 74234 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] QEMU state of ARM NEON support.
2010-03-22 13:43 [Qemu-devel] QEMU state of ARM NEON support Dmitry Zhurikhin
@ 2010-03-25 7:52 ` Juha.Riihimaki
2010-03-25 10:27 ` Dmitry Zhurikhin
2010-03-25 14:00 ` WIP flush-to-zero patch [was: Re: [Qemu-devel] QEMU state of ARM NEON support.] Nathan Froyd
0 siblings, 2 replies; 6+ messages in thread
From: Juha.Riihimaki @ 2010-03-25 7:52 UTC (permalink / raw)
To: zhur; +Cc: qemu-devel
Hi,
Thanks for the testing. I fixed all of the issues found by your test programs except:
- vmull.p8 is not implemented in QEMU.
- vrecpe/vrsqrte returns exact reciprocal/root in QEMU instead of estimate.
- 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.
- vqdmlsl yields different results for some specific input values, however I think QEMU is producing correct results. For example, 1431655765-(2*-32768*-32768)=-715827883 but your reference hardware results say it should be -715827882.
Anyway, many thanks for the testing you did and especially for posting the test programs as well. All these fixes along with many others are now in the Maemo QEMU repository. We'll try to make a new set of ARM emulation patches against upstream QEMU in the near future.
Regards,
Juha
On Mar 22, 2010, at 15:43, ext Dmitry Zhurikhin wrote:
> Hello. We made a small experiment to analyze QEMU state of NEON support. We
> took our tests from Valgrind that we wrote to test support for all NEON
> instructions and ran them inside of QEMU. I am attaching the output files from
> trunk QEMU as well as reference file showing what output should be (taken from
> the real test board). We find the results interesting. Overall NEON support is
> great. Here is a list of what problems we've seen so far:
> - To start with, QEMU translator doesn't support at all 128-bit polynomial
> VMULL instruction and VSLI and VSRI instructions. Though there are two patches
> in the mailing list to address missing VSLI and VSRI instructions problem. One
> patch adds support only for VSLI instruction. The other adds support for both
> of them but its emulation of VSLI instruction is incorrect.
> - QEMU also raises 'Illegal instruction' interrupt on some kinds of VCVT
> instructions and converts all values incorrectly. Seems like QEMU recognizes
> VCVT as another instruction.
> - Many instructions are emulated (partially) incorrectly. They include
> VQSHL(U), V(Q)RSHL, VRSHR, V(R)SRA, VMUL, VMLA, VMLS, VMULL, VMLAL, VMLSL, VZIP,
> 128-bit VUZP, 64-bit V(Q)(R)SHR(U)N, VQ(R)DMUL(L,H), VQDMLSL, VQDMLAL, VSHLL,
> VRECPE and VRSQRT(E,S).
> - Encoding of integer constants with cmode 1101 is processed incorrectly (see
> VMOV or VMVN).
> - Flush-to-zero is not performed before executing floating-point NEON
> instructions as it should be (which results in incorrect VCGT and VCLE
> instructions result).
> - Saturation flag is not set.
> - QEMU reports "Internal resource leak"s for some instructions.
>
> Hope this information will be helpful.
>
>
> Regards,
> Dmitry
> <qemu-neon-test.tar.bz2>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] QEMU state of ARM NEON support.
2010-03-25 7:52 ` Juha.Riihimaki
@ 2010-03-25 10:27 ` Dmitry Zhurikhin
2010-03-25 11:04 ` Juha.Riihimaki
2010-03-25 14:00 ` WIP flush-to-zero patch [was: Re: [Qemu-devel] QEMU state of ARM NEON support.] Nathan Froyd
1 sibling, 1 reply; 6+ messages in thread
From: Dmitry Zhurikhin @ 2010-03-25 10:27 UTC (permalink / raw)
To: Juha.Riihimaki; +Cc: qemu-devel
Juha.Riihimaki@nokia.com wrote:
> Hi,
>
> Thanks for the testing. I fixed all of the issues found by your test programs except:
Great! This is very good news. Please look at my comments below regarding
specific issues.
> - vmull.p8 is not implemented in QEMU.
So seems this is now the only NEON instruction variant left that QEMU doesn't
handle.
> - vrecpe/vrsqrte returns exact reciprocal/root in QEMU instead of estimate.
A simple algorithm used in hardware is described in the ARMv7 ARM* (see function
'recip_estimate' on page A2-59) but I don't think this is a big issue as exact
computations may be even better.
> - 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.
This is actually a "Flush-to-zero" feature which is always on for NEON
instructions (see FZ field description of FPSCR in A2.6.4 chapter of ARMv7 ARM).
Before attempting to perform an action on the floating-point data NEON first
checks if it is close to zero (zero exponent, bits 23-30 for F32, see FPUnpack
function at page A2-48) and behaves as if it was zero if the check succeeds.
> - vqdmlsl yields different results for some specific input values, however I think QEMU is producing correct results. For example, 1431655765-(2*-32768*-32768)=-715827883 but your reference hardware results say it should be -715827882.
From what I understand hardware gets such result because saturation occurs on
the (2*-32768*-32768) step. The result is not 0x80000000 as expected but
because of overflow is set as the largest 32-bit signed integer 0x7FFFFFFF. It
seems that QEMU just doesn't perform saturation (in this particular case at least).
> Anyway, many thanks for the testing you did and especially for posting the test programs as well. All these fixes along with many others are now in the Maemo QEMU repository. We'll try to make a new set of ARM emulation patches against upstream QEMU in the near future.
We'll be waiting for this. Thanks a lot for your work.
> Regards,
> Juha
* I am referring to the "ARM Architecture Reference Manual, ARMv7-A and ARMv7-R
edition" version ARM_2009_Q3.
Regards,
Dmitry
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Qemu-devel] QEMU state of ARM NEON support.
2010-03-25 10:27 ` Dmitry Zhurikhin
@ 2010-03-25 11:04 ` Juha.Riihimaki
0 siblings, 0 replies; 6+ messages in thread
From: Juha.Riihimaki @ 2010-03-25 11:04 UTC (permalink / raw)
To: zhur; +Cc: qemu-devel
On Mar 25, 2010, at 12:27, ext Dmitry Zhurikhin wrote:
> Juha.Riihimaki@nokia.com wrote:
>> - vqdmlsl yields different results for some specific input values, however I think QEMU is producing correct results. For example, 1431655765-(2*-32768*-32768)=-715827883 but your reference hardware results say it should be -715827882.
> From what I understand hardware gets such result because saturation occurs on
> the (2*-32768*-32768) step. The result is not 0x80000000 as expected but
> because of overflow is set as the largest 32-bit signed integer 0x7FFFFFFF. It
> seems that QEMU just doesn't perform saturation (in this particular case at least).
Yes I see, I overlooked the fact that -32768*-32768 changes the sign and so doubling the result of that overflows the signed 32-bit integer even if the result still fits in 32 bits. Thanks, I'll fix that as well.
Regards,
Juha
^ permalink raw reply [flat|nested] 6+ messages in thread
* WIP flush-to-zero patch [was: Re: [Qemu-devel] QEMU state of ARM NEON support.]
2010-03-25 7:52 ` Juha.Riihimaki
2010-03-25 10:27 ` Dmitry Zhurikhin
@ 2010-03-25 14:00 ` Nathan Froyd
2010-03-25 16:11 ` Richard Henderson
1 sibling, 1 reply; 6+ messages in thread
From: Nathan Froyd @ 2010-03-25 14:00 UTC (permalink / raw)
To: Juha.Riihimaki; +Cc: qemu-devel, zhur
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
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)
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: WIP flush-to-zero patch [was: Re: [Qemu-devel] QEMU state of ARM NEON support.]
2010-03-25 14:00 ` WIP flush-to-zero patch [was: Re: [Qemu-devel] QEMU state of ARM NEON support.] Nathan Froyd
@ 2010-03-25 16:11 ` Richard Henderson
0 siblings, 0 replies; 6+ messages in thread
From: Richard Henderson @ 2010-03-25 16:11 UTC (permalink / raw)
To: Nathan Froyd; +Cc: Juha.Riihimaki, qemu-devel, zhur
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~
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2010-03-25 16:11 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-03-22 13:43 [Qemu-devel] QEMU state of ARM NEON support Dmitry Zhurikhin
2010-03-25 7:52 ` Juha.Riihimaki
2010-03-25 10:27 ` Dmitry Zhurikhin
2010-03-25 11:04 ` Juha.Riihimaki
2010-03-25 14:00 ` WIP flush-to-zero patch [was: Re: [Qemu-devel] QEMU state of ARM NEON support.] Nathan Froyd
2010-03-25 16:11 ` Richard Henderson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).