X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Ftv%2Ffltcalc.c;h=d153b90b51f15f7b4398438751a19a4c80aa1452;hb=45ecc187cee7107c83c1f9618a1e1e586df73644;hp=8938cdc475a7b7c0de33d65f3407a599a53b8301;hpb=17b9af2a9d5366539116e1165768c25aec59b111;p=libfirm diff --git a/ir/tv/fltcalc.c b/ir/tv/fltcalc.c index 8938cdc47..d153b90b5 100644 --- a/ir/tv/fltcalc.c +++ b/ir/tv/fltcalc.c @@ -52,7 +52,7 @@ #include "xmalloc.h" -/** The number of extra precesion rounding bits */ +/** The number of extra precision rounding bits */ #define ROUNDING_BITS 2 typedef uint32_t UINT32; @@ -182,6 +182,8 @@ static void *pack(const fp_value *int_float, void *packed) { default: break; } + assert(int_float->desc.explicit_one <= 1); + /* pack sign: move it to the left after exponent AND mantissa */ sc_val_from_ulong(int_float->sign, temp); @@ -397,16 +399,19 @@ static int normalize(const fp_value *in_val, fp_value *out_val, int sticky) { } /** - * Operations involving NaN's must return NaN + * Operations involving NaN's must return NaN. + * They are NOT exact. */ #define handle_NAN(a, b, result) \ do { \ if (a->desc.clss == NAN) { \ if (a != result) memcpy(result, a, calc_buffer_size); \ + fc_exact = 0; \ return; \ } \ if (b->desc.clss == NAN) { \ if (b != result) memcpy(result, b, calc_buffer_size); \ + fc_exact = 0; \ return; \ } \ }while (0) @@ -435,6 +440,7 @@ static void _fadd(const fp_value *a, const fp_value *b, fp_value *result) { /* produce NaN on inf - inf */ if (sign && (a->desc.clss == INF) && (b->desc.clss == INF)) { + fc_exact = 0; fc_get_qnan(&a->desc, result); return; } @@ -474,12 +480,14 @@ static void _fadd(const fp_value *a, const fp_value *b, fp_value *result) { if (a->desc.clss == ZERO || b->desc.clss == INF) { if (b != result) memcpy(result, b, calc_buffer_size); + fc_exact = b->desc.clss == NORMAL; result->sign = res_sign; return; } if (b->desc.clss == ZERO || a->desc.clss == INF) { if (a != result) memcpy(result, a, calc_buffer_size); + fc_exact = a->desc.clss == NORMAL; result->sign = res_sign; return; } @@ -548,9 +556,10 @@ static void _fmul(const fp_value *a, const fp_value *b, fp_value *result) { /* produce NaN on 0 * inf */ if (a->desc.clss == ZERO) { - if (b->desc.clss == INF) + if (b->desc.clss == INF) { fc_get_qnan(&a->desc, result); - else { + fc_exact = 0; + } else { if (a != result) memcpy(result, a, calc_buffer_size); result->sign = res_sign; @@ -558,9 +567,10 @@ static void _fmul(const fp_value *a, const fp_value *b, fp_value *result) { return; } if (b->desc.clss == ZERO) { - if (a->desc.clss == INF) + if (a->desc.clss == INF) { fc_get_qnan(&a->desc, result); - else { + fc_exact = 0; + } else { if (b != result) memcpy(result, b, calc_buffer_size); result->sign = res_sign; @@ -569,12 +579,14 @@ static void _fmul(const fp_value *a, const fp_value *b, fp_value *result) { } if (a->desc.clss == INF) { + fc_exact = 0; if (a != result) memcpy(result, a, calc_buffer_size); result->sign = res_sign; return; } if (b->desc.clss == INF) { + fc_exact = 0; if (b != result) memcpy(result, b, calc_buffer_size); result->sign = res_sign; @@ -631,10 +643,11 @@ static void _fdiv(const fp_value *a, const fp_value *b, fp_value *result) { /* produce NAN on 0/0 and inf/inf */ if (a->desc.clss == ZERO) { - if (b->desc.clss == ZERO) + if (b->desc.clss == ZERO) { /* 0/0 -> NaN */ fc_get_qnan(&a->desc, result); - else { + fc_exact = 0; + } else { /* 0/x -> a */ if (a != result) memcpy(result, a, calc_buffer_size); @@ -644,10 +657,11 @@ static void _fdiv(const fp_value *a, const fp_value *b, fp_value *result) { } if (b->desc.clss == INF) { - if (a->desc.clss == INF) + fc_exact = 0; + if (a->desc.clss == INF) { /* inf/inf -> NaN */ fc_get_qnan(&a->desc, result); - else { + } else { /* x/inf -> 0 */ sc_val_from_ulong(0, NULL); _save_result(_exp(result)); @@ -658,6 +672,7 @@ static void _fdiv(const fp_value *a, const fp_value *b, fp_value *result) { } if (a->desc.clss == INF) { + fc_exact = 0; /* inf/x -> inf */ if (a != result) memcpy(result, a, calc_buffer_size); @@ -665,6 +680,7 @@ static void _fdiv(const fp_value *a, const fp_value *b, fp_value *result) { return; } if (b->desc.clss == ZERO) { + fc_exact = 0; /* division by zero */ if (result->sign) fc_get_minusinf(&a->desc, result); @@ -1140,6 +1156,7 @@ LLDBL fc_val_to_ieee754(const fp_value *val) { value_t buildval; ieee_descriptor_t desc; + unsigned mantissa_size; #ifdef HAVE_LONG_DOUBLE desc.exponent_size = 15; @@ -1152,6 +1169,7 @@ LLDBL fc_val_to_ieee754(const fp_value *val) { desc.explicit_one = 0; desc.clss = NORMAL; #endif + mantissa_size = desc.mantissa_size + desc.explicit_one; temp = alloca(calc_buffer_size); value = fc_cast(val, &desc, temp); @@ -1169,10 +1187,10 @@ LLDBL fc_val_to_ieee754(const fp_value *val) { mantissa1 = 0; for (byte_offset = 0; byte_offset < 4; byte_offset++) - mantissa1 |= sc_sub_bits(_mant(value), desc.mantissa_size, byte_offset) << (byte_offset<<3); + mantissa1 |= sc_sub_bits(_mant(value), mantissa_size, byte_offset) << (byte_offset << 3); for (; (byte_offset<<3) < desc.mantissa_size; byte_offset++) - mantissa0 |= sc_sub_bits(_mant(value), desc.mantissa_size, byte_offset) << ((byte_offset-4)<<3); + mantissa0 |= sc_sub_bits(_mant(value), mantissa_size, byte_offset) << ((byte_offset - 4) << 3); #ifdef HAVE_LONG_DOUBLE buildval.val.high = sign << 15; @@ -1319,7 +1337,7 @@ fp_value *fc_get_plusinf(const ieee_descriptor_t *desc, fp_value *result) { result->desc.exponent_size = desc->exponent_size; result->desc.mantissa_size = desc->mantissa_size; result->desc.explicit_one = desc->explicit_one; - result->desc.clss = NORMAL; + result->desc.clss = INF; result->sign = 0; @@ -1408,6 +1426,7 @@ int fc_is_subnormal(const fp_value *a) { char *fc_print(const fp_value *val, char *buf, int buflen, unsigned base) { char *mul_1; + LLDBL flt_val; mul_1 = alloca(calc_buffer_size); @@ -1415,22 +1434,21 @@ char *fc_print(const fp_value *val, char *buf, int buflen, unsigned base) { case FC_DEC: switch ((value_class_t)val->desc.clss) { case INF: - if (buflen >= 8 + val->sign) sprintf(buf, "%sINFINITY", val->sign ? "-":""); - else snprintf(buf, buflen, "%sINF", val->sign ? "-":NULL); + snprintf(buf, buflen, "%cINF", val->sign ? '-' : '+'); break; case NAN: - snprintf(buf, buflen, "NAN"); + snprintf(buf, buflen, "NaN"); break; case ZERO: snprintf(buf, buflen, "0.0"); break; default: - /* XXX to be implemented */ + flt_val = fc_val_to_ieee754(val); #ifdef HAVE_LONG_DOUBLE /* XXX 30 is arbitrary */ - snprintf(buf, buflen, "%.30LE", fc_val_to_ieee754(val)); + snprintf(buf, buflen, "%.30LE", flt_val); #else - snprintf(buf, buflen, "%.18E", fc_val_to_ieee754(val)); + snprintf(buf, buflen, "%.18E", flt_val); #endif } break; @@ -1438,8 +1456,7 @@ char *fc_print(const fp_value *val, char *buf, int buflen, unsigned base) { case FC_HEX: switch ((value_class_t)val->desc.clss) { case INF: - if (buflen >= 8+val->sign) sprintf(buf, "%sINFINITY", val->sign?"-":""); - else snprintf(buf, buflen, "%sINF", val->sign?"-":NULL); + snprintf(buf, buflen, "%cINF", val->sign ? '-' : '+'); break; case NAN: snprintf(buf, buflen, "NAN"); @@ -1448,10 +1465,11 @@ char *fc_print(const fp_value *val, char *buf, int buflen, unsigned base) { snprintf(buf, buflen, "0.0"); break; default: + flt_val = fc_val_to_ieee754(val); #ifdef HAVE_LONG_DOUBLE - snprintf(buf, buflen, "%LA", fc_val_to_ieee754(val)); + snprintf(buf, buflen, "%LA", flt_val); #else - snprintf(buf, buflen, "%A", fc_val_to_ieee754(val)); + snprintf(buf, buflen, "%A", flt_val); #endif } break; @@ -1469,7 +1487,7 @@ unsigned char fc_sub_bits(const fp_value *value, unsigned num_bits, unsigned byt /* this is used to cache the packed version of the value */ static char *packed_value = NULL; - if (packed_value == NULL) packed_value = xmalloc(value_size); + if (packed_value == NULL) packed_value = XMALLOCN(char, value_size); if (value != NULL) pack(value, packed_value); @@ -1531,11 +1549,11 @@ void init_fltcalc(int precision) { /* does nothing if already init */ if (precision == 0) precision = FC_DEFAULT_PRECISION; - init_strcalc(precision + 4); + init_strcalc(precision + 2 + ROUNDING_BITS); - /* needs additionally two bits to round, a bit as explicit 1., and one for + /* needs additionally rounding bits, one bit as explicit 1., and one for * addition overflow */ - max_precision = sc_get_precision() - 4; + max_precision = sc_get_precision() - (2 + ROUNDING_BITS); if (max_precision < precision) printf("WARNING: not enough precision available, using %d\n", max_precision);