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 + +#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)