X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Ftv%2Ffltcalc.c;h=564b28c0c795e6d7a6ebc8be62ccbd3b010fccbd;hb=ab0e5a91b4acdb44ae152930042cbfa9e927bcdd;hp=4a619ea99e59fe38b823b1520ac2cc0e9e3a0921;hpb=0d1dddb39fb247e15b28a74181a0bc5bb764e2ad;p=libfirm diff --git a/ir/tv/fltcalc.c b/ir/tv/fltcalc.c index 4a619ea99..564b28c0c 100644 --- a/ir/tv/fltcalc.c +++ b/ir/tv/fltcalc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved. + * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved. * * This file is part of libFirm. * @@ -129,32 +129,36 @@ struct _fp_value { #define _shift_left(x, y, b) sc_shl((x), (y), value_size*4, 0, (b)) -#define FUNC_PTR(code) fc_##code - -#if FLTCALC_DEBUG +#ifdef FLTCALC_DEBUG # define DEBUGPRINTF(x) printf x #else # define DEBUGPRINTF(x) ((void)0) #endif -#if FLTCALC_TRACE_CALC +#ifdef FLTCALC_TRACE_CALC # define TRACEPRINTF(x) printf x #else # define TRACEPRINTF(x) ((void)0) #endif +/** The immediate precision. */ +static unsigned immediate_prec = 0; + +/** A temporal buffer. */ static fp_value *calc_buffer = NULL; +/** Current rounding mode.*/ static fc_rounding_mode_t rounding_mode; static int calc_buffer_size; static int value_size; static int max_precision; -/******** - * private functions - ********/ + +/** Exact flag. */ +static int fc_exact = 1; + #if 0 -static void _fail_char(const char *str, unsigned int len, int pos) { +static void fail_char(const char *str, unsigned int len, int pos) { if (*(str+pos)) printf("ERROR: Unexpected character '%c'\n", *(str + pos)); else @@ -167,7 +171,7 @@ static void _fail_char(const char *str, unsigned int len, int pos) { #endif /** pack machine-like */ -static void *_pack(const fp_value *int_float, void *packed) { +static void *pack(const fp_value *int_float, void *packed) { char *shift_val; char *temp; fp_value *val_buffer; @@ -220,7 +224,13 @@ static void *_pack(const fp_value *int_float, void *packed) { return packed; } -static void _normalize(const fp_value *in_val, fp_value *out_val, int sticky) { +/** + * Normalize a fp_value. + * + * @return non-zero if result is exact + */ +static int normalize(const fp_value *in_val, fp_value *out_val, int sticky) { + int exact = 1; int hsb; char lsb, guard, round, round_dir = 0; char *temp = alloca(value_size); @@ -235,7 +245,7 @@ static void _normalize(const fp_value *in_val, fp_value *out_val, int sticky) { out_val->desc.clss = NORMAL; - /* mantissa all zeros, so zero exponent (because of explicit one)*/ + /* mantissa all zeros, so zero exponent (because of explicit one) */ if (hsb == 2 + in_val->desc.mantissa_size) { sc_val_from_ulong(0, _exp(out_val)); hsb = -1; @@ -249,8 +259,10 @@ static void _normalize(const fp_value *in_val, fp_value *out_val, int sticky) { _shift_right(_mant(in_val), temp, _mant(out_val)); /* remember if some bits were shifted away */ - if (!sticky) sticky = sc_had_carry(); - + if (sc_had_carry()) { + exact = 0; + sticky = 1; + } sc_add(_exp(in_val), temp, _exp(out_val)); } else if (hsb > -1) { /* shift left */ @@ -270,7 +282,10 @@ static void _normalize(const fp_value *in_val, fp_value *out_val, int sticky) { sc_sub(temp, _exp(out_val), NULL); _shift_right(_mant(out_val), sc_get_buffer(), _mant(out_val)); - if (!sticky) sticky = sc_had_carry(); + if (sc_had_carry()) { + exact = 0; + sticky = 1; + } /* denormalized means exponent of zero */ sc_val_from_ulong(0, _exp(out_val)); @@ -316,6 +331,7 @@ static void _normalize(const fp_value *in_val, fp_value *out_val, int sticky) { if (lsb != 0) { sc_val_from_long(lsb, temp); sc_add(_mant(out_val), temp, _mant(out_val)); + exact = 0; } /* could have rounded down to zero */ @@ -327,7 +343,8 @@ static void _normalize(const fp_value *in_val, fp_value *out_val, int sticky) { if ((out_val->desc.clss != SUBNORMAL) && (hsb < -1)) { sc_val_from_ulong(1, temp); _shift_right(_mant(out_val), temp, _mant(out_val)); - + if (exact && sc_had_carry()) + exact = 0; sc_add(_exp(out_val), temp, _exp(out_val)); } else if ((out_val->desc.clss == SUBNORMAL) && (hsb == -1)) { /* overflow caused the mantissa to be normal again, @@ -388,6 +405,7 @@ static void _normalize(const fp_value *in_val, fp_value *out_val, int sticky) { } } } + return exact; } /** @@ -399,7 +417,7 @@ do { \ if (a != result) memcpy(result, a, calc_buffer_size); \ return; \ } \ - if (b->desc.clss == NAN) { \ + if (b->desc.clss == NAN) { \ if (b != result) memcpy(result, b, calc_buffer_size); \ return; \ } \ @@ -416,6 +434,8 @@ static void _fadd(const fp_value *a, const fp_value *b, fp_value *result) { char sign, res_sign; char sticky; + fc_exact = 1; + handle_NAN(a, b, result); /* make sure result has a descriptor */ @@ -486,6 +506,7 @@ static void _fadd(const fp_value *a, const fp_value *b, fp_value *result) { _shift_right(_mant(b), exp_diff, temp); sticky = sc_had_carry(); + fc_exact &= !sticky; if (sticky && sign) { /* if subtracting a little more than the represented value or adding a little @@ -515,16 +536,19 @@ static void _fadd(const fp_value *a, const fp_value *b, fp_value *result) { /* resulting exponent is the bigger one */ memmove(_exp(result), _exp(a), value_size); - _normalize(result, result, sticky); + fc_exact &= normalize(result, result, sticky); } /** * calculate a * b */ static void _fmul(const fp_value *a, const fp_value *b, fp_value *result) { + int sticky; char *temp; char res_sign; + fc_exact = 1; + handle_NAN(a, b, result); temp = alloca(value_size); @@ -591,17 +615,22 @@ static void _fmul(const fp_value *a, const fp_value *b, fp_value *result) { sc_val_from_ulong(2 + result->desc.mantissa_size, temp); _shift_right(_mant(result), temp, _mant(result)); + sticky = sc_had_carry(); + fc_exact &= !sticky; - _normalize(result, result, sc_had_carry()); + fc_exact &= normalize(result, result, sticky); } /** * calculate a / b */ static void _fdiv(const fp_value *a, const fp_value *b, fp_value *result) { + int sticky; char *temp, *dividend; char res_sign; + fc_exact = 1; + handle_NAN(a, b, result); temp = alloca(value_size); @@ -612,7 +641,7 @@ static void _fdiv(const fp_value *a, const fp_value *b, fp_value *result) { result->sign = res_sign = a->sign ^ b->sign; - /* produce nan on 0/0 and inf/inf */ + /* produce NAN on 0/0 and inf/inf */ if (a->desc.clss == ZERO) { if (b->desc.clss == ZERO) /* 0/0 -> nan */ @@ -682,9 +711,11 @@ static void _fdiv(const fp_value *a, const fp_value *b, fp_value *result) { sc_val_from_ulong(1, divisor); _shift_right(_mant(b), divisor, divisor); sc_div(dividend, divisor, _mant(result)); + sticky = sc_had_carry(); + fc_exact &= !sticky; } - _normalize(result, result, sc_had_carry()); + fc_exact &= normalize(result, result, sticky); } #if 0 @@ -728,7 +759,7 @@ static void _power_of_ten(int exp, descriptor_t *desc, char *result) { /** * Truncate the fractional part away. * - * This does not clip to any integer rang. + * This does not clip to any integer range. */ static void _trunc(const fp_value *a, fp_value *result) { /* @@ -746,6 +777,9 @@ static void _trunc(const fp_value *a, fp_value *result) { int exp_bias, exp_val; char *temp; + /* fixme: can be exact */ + fc_exact = 0; + temp = alloca(value_size); if (a != result) @@ -864,7 +898,7 @@ void *fc_val_from_str(const char *str, unsigned int len, char exp_size, char man break; default: - _fail_char(old_str, len, str - old_str); + fail_char(old_str, len, str - old_str); } break; @@ -890,7 +924,7 @@ void *fc_val_from_str(const char *str, unsigned int len, char exp_size, char man goto done; default: - _fail_char(old_str, len, str - old_str); + fail_char(old_str, len, str - old_str); } break; @@ -912,7 +946,7 @@ void *fc_val_from_str(const char *str, unsigned int len, char exp_size, char man goto done; default: - _fail_char(old_str, len, str - old_str); + fail_char(old_str, len, str - old_str); } break; @@ -922,7 +956,7 @@ void *fc_val_from_str(const char *str, unsigned int len, char exp_size, char man exp_sign = 1; /* fall through */ case '+': - if (*(str-1) != 'e' && *(str-1) != 'E') _fail_char(old_str, len, str - old_str); + if (*(str-1) != 'e' && *(str-1) != 'E') fail_char(old_str, len, str - old_str); str++; break; @@ -934,7 +968,7 @@ void *fc_val_from_str(const char *str, unsigned int len, char exp_size, char man break; default: - _fail_char(old_str, len, str - old_str); + fail_char(old_str, len, str - old_str); } break; @@ -948,7 +982,7 @@ void *fc_val_from_str(const char *str, unsigned int len, char exp_size, char man case '\0': goto done; default: - _fail_char(old_str, len, str - old_str); + fail_char(old_str, len, str - old_str); } } } /* switch(state) */ @@ -1029,6 +1063,9 @@ fp_value *fc_val_from_ieee754(LLDBL l, char exp_size, char mant_size, fp_value * if (result == NULL) result = calc_buffer; temp = alloca(value_size); + /* CLEAR the buffer */ + memset(result, 0, fc_get_buffer_length()); + result->desc.exponent_size = exp_size; result->desc.mantissa_size = mant_size; @@ -1093,7 +1130,7 @@ fp_value *fc_val_from_ieee754(LLDBL l, char exp_size, char mant_size, fp_value * _shift_left(_mant(result), sc_get_buffer(), _mant(result)); } - _normalize(result, result, 0); + normalize(result, result, 0); TRACEPRINTF(("val_from_float results in %s\n", fc_print(result, temp, calc_buffer_size, FC_PACKED))); @@ -1176,6 +1213,13 @@ fp_value *fc_cast(const fp_value *value, char exp_size, char mant_size, fp_value return result; } + if (value->desc.clss == NAN) { + if (sc_get_highest_set_bit(_mant(value)) == value->desc.mantissa_size + 1) + return fc_get_qnan(exp_size, mant_size, result); + else + return fc_get_snan(exp_size, mant_size, result); + } + /* set the descriptor of the new value */ result->desc.exponent_size = exp_size; result->desc.mantissa_size = mant_size; @@ -1203,7 +1247,7 @@ fp_value *fc_cast(const fp_value *value, char exp_size, char mant_size, fp_value memmove(_mant(result), _mant(value), value_size); } - _normalize(result, result, 0); + normalize(result, result, 0); TRACEPRINTF(("Cast results in %s\n", fc_print(result, temp, value_size, FC_PACKED))); return result; } @@ -1416,7 +1460,7 @@ char *fc_print(const fp_value *val, char *buf, int buflen, unsigned base) { case FC_PACKED: default: - snprintf(buf, buflen, "%s", sc_print(_pack(val, mul_1), value_size*4, SC_HEX, 0)); + snprintf(buf, buflen, "%s", sc_print(pack(val, mul_1), value_size*4, SC_HEX, 0)); buf[buflen - 1] = '\0'; break; } @@ -1425,18 +1469,18 @@ char *fc_print(const fp_value *val, char *buf, int buflen, unsigned base) { unsigned char fc_sub_bits(const fp_value *value, unsigned num_bits, unsigned byte_ofs) { /* this is used to cache the packed version of the value */ - static char *pack = NULL; + static char *packed_value = NULL; - if (pack == NULL) pack = xmalloc(value_size); + if (packed_value == NULL) packed_value = xmalloc(value_size); if (value != NULL) - _pack(value, pack); + pack(value, packed_value); - return sc_sub_bits(pack, num_bits, byte_ofs); + return sc_sub_bits(packed_value, num_bits, byte_ofs); } int fc_zero_mantissa(const fp_value *value) { - return sc_is_zero(_mant(value)); + return sc_get_lowest_set_bit(_mant(value)) == 2 + value->desc.mantissa_size; } int fc_get_exponent(const fp_value *value) { @@ -1467,7 +1511,7 @@ void init_fltcalc(int precision) { * addition overflow */ max_precision = sc_get_precision() - 4; if (max_precision < precision) - printf("WARING: not enough precision available, using %d\n", max_precision); + printf("WARNING: not enough precision available, using %d\n", max_precision); rounding_mode = FC_TONEAREST; value_size = sc_get_buffer_length(); @@ -1493,12 +1537,16 @@ void finish_fltcalc (void) { free(calc_buffer); calc_buffer = NULL; } +#ifdef FLTCALC_TRACE_CALC +static char buffer[100]; +#endif + /* definition of interface functions */ fp_value *fc_add(const fp_value *a, const fp_value *b, fp_value *result) { if (result == NULL) result = calc_buffer; - TRACEPRINTF(("%s ", fc_print(a, buffer, 100, FC_PACKED))); - TRACEPRINTF(("+ %s ", fc_print(b, buffer, 100, FC_PACKED))); + TRACEPRINTF(("%s ", fc_print(a, buffer, sizeof(buffer), FC_PACKED))); + TRACEPRINTF(("+ %s ", fc_print(b, buffer, sizeof(buffer), FC_PACKED))); /* make the value with the bigger exponent the first one */ if (sc_comp(_exp(a), _exp(b)) == -1) @@ -1506,7 +1554,7 @@ fp_value *fc_add(const fp_value *a, const fp_value *b, fp_value *result) { else _fadd(a, b, result); - TRACEPRINTF(("= %s\n", fc_print(result, buffer, 100, FC_PACKED))); + TRACEPRINTF(("= %s\n", fc_print(result, buffer, sizeof(buffer), FC_PACKED))); return result; } @@ -1515,8 +1563,8 @@ fp_value *fc_sub(const fp_value *a, const fp_value *b, fp_value *result) { if (result == NULL) result = calc_buffer; - TRACEPRINTF(("%s ", fc_print(a, buffer, 100, FC_PACKED))); - TRACEPRINTF(("- %s ", fc_print(b, buffer, 100, FC_PACKED))); + TRACEPRINTF(("%s ", fc_print(a, buffer, sizeof(buffer), FC_PACKED))); + TRACEPRINTF(("- %s ", fc_print(b, buffer, sizeof(buffer), FC_PACKED))); temp = alloca(calc_buffer_size); memcpy(temp, b, calc_buffer_size); @@ -1526,67 +1574,138 @@ fp_value *fc_sub(const fp_value *a, const fp_value *b, fp_value *result) { else _fadd(a, temp, result); - TRACEPRINTF(("= %s\n", fc_print(result, buffer, 100, FC_PACKED))); + TRACEPRINTF(("= %s\n", fc_print(result, buffer, sizeof(buffer), FC_PACKED))); return result; } fp_value *fc_mul(const fp_value *a, const fp_value *b, fp_value *result) { if (result == NULL) result = calc_buffer; - TRACEPRINTF(("%s ", fc_print(a, buffer, 100, FC_PACKED))); - TRACEPRINTF(("* %s ", fc_print(b, buffer, 100, FC_PACKED))); + TRACEPRINTF(("%s ", fc_print(a, buffer, sizeof(buffer), FC_PACKED))); + TRACEPRINTF(("* %s ", fc_print(b, buffer, sizeof(buffer), FC_PACKED))); _fmul(a, b, result); - TRACEPRINTF(("= %s\n", fc_print(result, buffer, 100, FC_PACKED))); + TRACEPRINTF(("= %s\n", fc_print(result, buffer, sizeof(buffer), FC_PACKED))); return result; } fp_value *fc_div(const fp_value *a, const fp_value *b, fp_value *result) { if (result == NULL) result = calc_buffer; - TRACEPRINTF(("%s ", fc_print(a, buffer, 100, FC_PACKED))); - TRACEPRINTF(("/ %s ", fc_print(b, buffer, 100, FC_PACKED))); + TRACEPRINTF(("%s ", fc_print(a, buffer, sizeof(buffer), FC_PACKED))); + TRACEPRINTF(("/ %s ", fc_print(b, buffer, sizeof(buffer), FC_PACKED))); _fdiv(a, b, result); - TRACEPRINTF(("= %s\n", fc_print(result, buffer, 100, FC_PACKED))); + TRACEPRINTF(("= %s\n", fc_print(result, buffer, sizeof(buffer), FC_PACKED))); return result; } fp_value *fc_neg(const fp_value *a, fp_value *result) { if (result == NULL) result = calc_buffer; - TRACEPRINTF(("- %s ", fc_print(a, buffer, 100, FC_PACKED))); + TRACEPRINTF(("- %s ", fc_print(a, buffer, sizeof(buffer), FC_PACKED))); if (a != result) memcpy(result, a, calc_buffer_size); result->sign = !a->sign; - TRACEPRINTF(("= %s\n", fc_print(result, buffer, 100, FC_PACKED))); + TRACEPRINTF(("= %s\n", fc_print(result, buffer, sizeof(buffer), FC_PACKED))); return result; } fp_value *fc_int(const fp_value *a, fp_value *result) { if (result == NULL) result = calc_buffer; - TRACEPRINTF(("%s ", fc_print(a, buffer, 100, FC_PACKED))); + TRACEPRINTF(("%s ", fc_print(a, buffer, sizeof(buffer), FC_PACKED))); TRACEPRINTF(("truncated to integer ")); _trunc(a, result); - TRACEPRINTF(("= %s\n", fc_print(result, buffer, 100, FC_PACKED))); + TRACEPRINTF(("= %s\n", fc_print(result, buffer, sizeof(buffer), FC_PACKED))); return result; } fp_value *fc_rnd(const fp_value *a, fp_value *result) { if (result == NULL) result = calc_buffer; - TRACEPRINTF(("%s ", fc_print(a, buffer, 100, FC_PACKED))); + (void) a; + TRACEPRINTF(("%s ", fc_print(a, buffer, sizeof(buffer), FC_PACKED))); TRACEPRINTF(("rounded to integer ")); assert(!"fc_rnd() not yet implemented"); - TRACEPRINTF(("= %s\n", fc_print(result, buffer, 100, FC_PACKED))); + TRACEPRINTF(("= %s\n", fc_print(result, buffer, sizeof(buffer), FC_PACKED))); return result; } + +/* + * convert a floating point value into an sc value ... + */ +int fc_flt2int(const fp_value *a, void *result, ir_mode *dst_mode) { + if (a->desc.clss == NORMAL) { + int exp_bias = (1 << (a->desc.exponent_size - 1)) - 1; + int exp_val = sc_val_to_long(_exp(a)) - exp_bias; + int shift, highest; + + if (a->sign && !mode_is_signed(dst_mode)) { + /* FIXME: for now we cannot convert this */ + return 0; + } + + assert(exp_val >= 0 && "floating point value not integral before fc_flt2int() call"); + shift = exp_val - a->desc.mantissa_size - 2; + + if (shift > 0) { + sc_shlI(_mant(a), shift, 64, 0, result); + } else { + sc_shrI(_mant(a), -shift, 64, 0, result); + } + + /* check for overflow */ + highest = sc_get_highest_set_bit(result); + + if (mode_is_signed(dst_mode)) { + if (highest == sc_get_lowest_set_bit(result)) { + /* need extra test for MIN_INT */ + if (highest >= (int) get_mode_size_bits(dst_mode)) { + /* FIXME: handle overflow */ + return 0; + } + } else { + if (highest >= (int) get_mode_size_bits(dst_mode) - 1) { + /* FIXME: handle overflow */ + return 0; + } + } + } else { + if (highest >= (int) get_mode_size_bits(dst_mode)) { + /* FIXME: handle overflow */ + return 0; + } + } + + if (a->sign) + sc_neg(result, result); + + return 1; + } + else if (a->desc.clss == ZERO) { + sc_zero(result); + return 1; + } + return 0; +} + + +unsigned fc_set_immediate_precision(unsigned bits) { + unsigned old = immediate_prec; + + immediate_prec = bits; + return old; +} + +int fc_is_exact(void) { + return fc_exact; +}