summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMartynas Venckus <martynas@cvs.openbsd.org>2008-10-07 22:06:30 +0000
committerMartynas Venckus <martynas@cvs.openbsd.org>2008-10-07 22:06:30 +0000
commit13e274e30a2f3dce36a95d6cc01a2265a620eb19 (patch)
tree0eb7c8b8911c16c7d7ea19554846a1838def0749 /sys
parent42029dea90615aabb34095ab75e07c870aed697e (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
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/alpha/alpha/fp_complete.c8
-rw-r--r--sys/lib/libkern/softfloat.c87
-rw-r--r--sys/lib/libkern/softfloat.h5
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 );