Fixing d2f in interpreter (Was: Re: [kaffe] Re: Re: NetBSD/ppc now works)

Dalibor Topic robilad at kaffe.org
Fri Apr 30 11:59:02 PDT 2004


Dalibor Topic wrote:
> Riccardo wrote:

> I suspect that d2f is broken in the interpreter. The Java language spec 
> demands that in case of overflow the value of float is a signed 
> infinity, but the C standard says oveflow results in undefined 
> behaviour. So I assume we'd have to check whether the double is 
> representable as a float before we convert it, and handle the special 
> cases that would invoke undefined behaviour ourself.
> 
> I'm working on a patch.

Okay, I've got a patch for the interpreter. I'm unsure if it's really 
necessary, or if it really fixes things, but hey, it's worth a try :)

Could you give this patch a try on netbsd-ppc and see if it fixes the 
DoubleCvt test?

cheers,
dalibor topic
-------------- next part --------------
Index: kaffe/kaffevm/intrp/icode.h
===================================================================
RCS file: /cvs/kaffe/kaffe/kaffe/kaffevm/intrp/icode.h,v
retrieving revision 1.20
diff -u -r1.20 icode.h
--- kaffe/kaffevm/intrp/icode.h	1 Feb 2004 22:14:53 -0000	1.20
+++ kaffe/kaffevm/intrp/icode.h	30 Apr 2004 18:03:14 -0000
@@ -12,6 +12,10 @@
 #ifndef __icode_h
 #define	__icode_h
 
+#include <float.h>
+
+#include "jtypes.h"
+
 #define	move_long_const(t, c)			(t)[0].v.tlong = (c)
 #define	add_long(t, f1, f2)			(t)[0].v.tlong = (f1)[0].v.tlong + (f2)[0].v.tlong
 #define	sub_long(t, f1, f2)			(t)[0].v.tlong = (f1)[0].v.tlong - (f2)[0].v.tlong
@@ -269,7 +273,106 @@
 #define	cvt_float_int(t, f)			(t)[0].v.tint = soft_cvtfi((f)[0].v.tfloat)
 #define	cvt_float_double(t, f)			(t)[0].v.tdouble = (f)[0].v.tfloat
 #define	cvt_double_int(t, f)			(t)[0].v.tint = soft_cvtdi((f)[0].v.tdouble)
-#define	cvt_double_float(t, f)			(t)[0].v.tfloat = (f)[0].v.tdouble
+
+/* A union used to convert bits to floats.  */
+/* NOTE: I should probably use functions from fp.h here. */
+typedef union {
+/* jint goes first, since ISO C only allows the first 
+ * member of a union to be initialized in an initializer.
+ * If jfloat were first, we wouldn't be able to initialize
+ * it with inf/-inf, since these values are not valid 
+ * expressions in C, they would have to be reserved keywords.
+ */
+jint i;
+jfloat f;
+} conv_float_t;
+
+static const conv_float_t FLOAT_POSITIVE_INFINITY = {0x7f800000};
+static const conv_float_t FLOAT_NEGATIVE_INFINITY = {0xff800000};
+static const conv_float_t FLOAT_DENORMALIZED_MINIMUM = {0x00000001};
+
+/**
+ * Convert a double to a float.
+ *
+ * Special case handling is performed to avoid
+ * getting undefined behaviour if the double can not be
+ * represented as a float.
+ *
+ * If the absolute value is lager than FLT_MAX, signed
+ * infinity is returned. If the absolute value is smaller
+ * than the smallest denormalized float value, signed 0
+ * is returned.
+ *
+ * @param d value to convert
+ * @return converted float
+ */
+ 
+static inline
+jfloat
+soft_convert_double_float(jdouble d) {
+
+	/* Get the absolute value of the parameter. */
+	jdouble abs_val = fabs(d);
+
+	/* Check for overflow. */
+
+	/* An overflow can happen if the absolute value of the 
+	 * parameter to convert is greater than the maximum 
+	 * representable float.
+	 */
+
+	/* NOTE: I should probably use java_lang_Float_MAX_VALUE
+	 * 	 here.
+	 */
+	if (abs_val > FLT_MAX) {
+		/* Java Language Specification 2n Ed §4.2.4 
+		 * demands that overflow results in signed
+		 * infinity. C standard says leaving the
+		 * domain range results in undefined behaviour,
+		 * so we need to check for it and make adjustments.
+		 */
+
+		if (d > 0.0) {
+			return FLOAT_POSITIVE_INFINITY.f;
+		}
+		else {
+			return FLOAT_NEGATIVE_INFINITY.f;
+		}
+	}
+
+	/* check for underflow */
+	/* underflow can happen if the parameter to convert is
+	 * between (+/-)0.0 and (+/-)smallest denormalized float.
+	 */
+	/* NOTE: I'm not sure if this is really necessary, though.
+	 */
+	/* NOTE: I'm also not sure whether we're doing the rounding
+	 *	 as per spec. It may be necessary to round 
+	 * 	 denormalized doubles up to FLOAT_DENORMALIZED_MINIMUM.f
+	 *	 in some cases.
+	 */
+	if (abs_val > 0.0 && abs_val < FLOAT_DENORMALIZED_MINIMUM.f) {
+		/* Java Language Specification 2n Ed §4.2.4
+                 * demands that underflow results in denormalized
+		 * value or signed 0. So if the double is smaller
+		 * than smallest denormalized float value, we
+		 * return a signed 0.
+		 */
+
+		if (d >= 0.0) {
+			return 0.0f;
+		}
+		else {
+			return -0.0f;
+		}
+	}
+
+	/* leave the rest (NaN, in-range-doubles) to the C compiler */
+
+	return d;
+}
+
+#define	cvt_double_float(t, f)			(t)[0].v.tfloat = soft_convert_double_float((f)[0].v.tdouble)
 
 #define	softcall_lookupinterfacemethod(r, n, t)	(r)[0].v.taddr = soft_lookupinterfacemethod((t)[0].v.taddr, (n)->class, (n)->idx)
 #define	softcall_new(r, t)			(r)->v.taddr = soft_new(t)


More information about the kaffe mailing list