diff options
author | Martynas Venckus <martynas@cvs.openbsd.org> | 2008-10-07 22:06:30 +0000 |
---|---|---|
committer | Martynas Venckus <martynas@cvs.openbsd.org> | 2008-10-07 22:06:30 +0000 |
commit | 13e274e30a2f3dce36a95d6cc01a2265a620eb19 (patch) | |
tree | 0eb7c8b8911c16c7d7ea19554846a1838def0749 | |
parent | 42029dea90615aabb34095ab75e07c870aed697e (diff) |
unbreak ieeefp emulation code wrt converting double to unsigned
long ints for alpha. we've got only one instruction (cvttq) to
convert double-t to quadword, and float64_to_int64 did not take
into account the unsigned conversions
therefore, overflow always occured, and half of the unsigned range
(LONG_MAX .. ULONG_MAX) was broken
introduce roundAndPackInt64NoOverflow and float64_to_int64_no_overflow
for softfloat, that works with unsigned integers as well. note
that this will return zero for nan/inf/oflow/uflow, raising exception
flag
perl is happy now
looked over by miod@
tested by naddy@, and by me on nick@'s alpha
-rw-r--r-- | sys/arch/alpha/alpha/fp_complete.c | 8 | ||||
-rw-r--r-- | sys/lib/libkern/softfloat.c | 87 | ||||
-rw-r--r-- | sys/lib/libkern/softfloat.h | 5 |
3 files changed, 96 insertions, 4 deletions
diff --git a/sys/arch/alpha/alpha/fp_complete.c b/sys/arch/alpha/alpha/fp_complete.c index 112f77af432..ee94b2da568 100644 --- a/sys/arch/alpha/alpha/fp_complete.c +++ b/sys/arch/alpha/alpha/fp_complete.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fp_complete.c,v 1.7 2006/02/25 03:58:56 deraadt Exp $ */ +/* $OpenBSD: fp_complete.c,v 1.8 2008/10/07 22:06:29 martynas Exp $ */ /* $NetBSD: fp_complete.c,v 1.5 2002/01/18 22:15:56 ross Exp $ */ /*- @@ -310,6 +310,10 @@ cvt_qt_dg_qg(u_int32_t inst_bits, struct proc *p) * unfortunate habit of always returning the nontrapping result. * XXX: there are several apparent AARM/AAH disagreements, as well as * the issue of trap handler pc and trapping results. + * XXX: this function will work for signed and unsigned 64-bit integers. + * rounding will happen per IEEE 754. invalid exception will be + * raised if argument is infinity, not-a-number or if it + * overflows/underflows. zero will be returned, in this case. */ static void cvt_tq_gq(u_int32_t inst_bits, struct proc *p) @@ -319,7 +323,7 @@ cvt_tq_gq(u_int32_t inst_bits, struct proc *p) inst.bits = inst_bits; stt(inst.float_detail.fb, &tfb, p); - tfc.i = float64_to_int64(tfb.i); + tfc.i = float64_to_int64_no_overflow(tfb.i); alpha_ldt(inst.float_detail.fc, &tfc); /* yes, ldt */ } diff --git a/sys/lib/libkern/softfloat.c b/sys/lib/libkern/softfloat.c index 848407619ce..f8d75e0327c 100644 --- a/sys/lib/libkern/softfloat.c +++ b/sys/lib/libkern/softfloat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: softfloat.c,v 1.2 2007/12/29 16:59:16 miod Exp $ */ +/* $OpenBSD: softfloat.c,v 1.3 2008/10/07 22:06:29 martynas Exp $ */ /* $NetBSD: softfloat.c,v 1.1 2001/04/26 03:10:47 ross Exp $ */ /* @@ -213,6 +213,53 @@ static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 ) return z; } + +#ifdef __alpha__ +/* +------------------------------------------------------------------------------- +Takes the 128-bit fixed-point value formed by concatenating `absZ0' and +`absZ1', with binary point between bits 63 and 64 (between the input words), +and returns the properly rounded 64-bit integer corresponding to the input. +If `zSign' is 1, the input is negated before being converted to an integer. +Ordinarily, the fixed-point input is simply rounded to an integer, with +the inexact exception raised if the input cannot be represented exactly as +an integer. +------------------------------------------------------------------------------- +*/ +static int64 roundAndPackInt64NoOverflow( flag zSign, bits64 absZ0, + bits64 absZ1 ) +{ + int8 roundingMode; + flag roundNearestEven, increment; + int64 z; + + roundingMode = float_rounding_mode(); + roundNearestEven = ( roundingMode == float_round_nearest_even ); + increment = ( (sbits64) absZ1 < 0 ); + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + increment = 0; + } + else { + if ( zSign ) { + increment = ( roundingMode == float_round_down ) && absZ1; + } + else { + increment = ( roundingMode == float_round_up ) && absZ1; + } + } + } + if ( increment ) { + ++absZ0; + absZ0 &= ~ ( ( (bits64) ( absZ1<<1 ) == 0 ) & roundNearestEven ); + } + z = absZ0; + if ( zSign ) z = - z; + if ( absZ1 ) float_set_inexact(); + return z; + +} +#endif /* __alpha__ */ #endif /* @@ -2401,6 +2448,44 @@ int64 float64_to_int64( float64 a ) } +#ifdef __alpha__ +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point value +`a' to the 64-bit two's complement integer format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-Point +Arithmetic---which means in particular that the conversion is rounded +according to the current rounding mode. If `a' is a NaN, the invalid +exception is raised and zero is returned. +------------------------------------------------------------------------------- +*/ +int64 float64_to_int64_no_overflow( float64 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig, aSigExtra; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp ) aSig |= LIT64( 0x0010000000000000 ); + shiftCount = 0x433 - aExp; + if ( shiftCount <= 0 ) { + if ( 0x43E < aExp ) { + float_raise( float_flag_invalid ); + return 0; + } + aSigExtra = 0; + aSig <<= - shiftCount; + } + else { + shift64ExtraRightJamming( aSig, 0, shiftCount, &aSig, &aSigExtra ); + } + return roundAndPackInt64NoOverflow( aSign, aSig, aSigExtra ); + +} +#endif /* __alpha__ */ + /* ------------------------------------------------------------------------------- Returns the result of converting the double-precision floating-point value diff --git a/sys/lib/libkern/softfloat.h b/sys/lib/libkern/softfloat.h index cc2bd1fbad9..cc5ed44172e 100644 --- a/sys/lib/libkern/softfloat.h +++ b/sys/lib/libkern/softfloat.h @@ -1,4 +1,4 @@ -/* $OpenBSD: softfloat.h,v 1.3 2008/06/26 05:42:20 ray Exp $ */ +/* $OpenBSD: softfloat.h,v 1.4 2008/10/07 22:06:29 martynas Exp $ */ /* $NetBSD: softfloat.h,v 1.1 2001/04/26 03:10:48 ross Exp $ */ /* This is a derivative work. */ @@ -232,6 +232,9 @@ int float64_to_int32( float64 ); int float64_to_int32_round_to_zero( float64 ); #ifndef SOFTFLOAT_FOR_GCC /* __fix?fdi provided by libgcc2.c */ int64_t float64_to_int64( float64 ); +#ifdef __alpha__ +int64_t float64_to_int64_no_overflow( float64 ); +#endif /* __alpha__ */ int64_t float64_to_int64_round_to_zero( float64 ); #endif float32 float64_to_float32( float64 ); |