* @author Mathias Heil
* @version $Id$
*/
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "config.h"
#include "fltcalc.h"
#include "strcalc.h"
-#include <math.h> /* need isnan() and isinf() (will be changed)*/
+#include <math.h>
/* undef some reused constants defined by math.h */
#ifdef NAN
# undef NAN
#endif
-#ifdef HAVE_INTTYPES_H
-# include <inttypes.h>
-#endif
-#ifdef HAVE_STRING_H
-# include <string.h>
-#endif
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#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;
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);
}
/**
- * 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)
/* 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;
}
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;
}
/* 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;
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;
}
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;
/* 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);
}
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));
}
if (a->desc.clss == INF) {
+ fc_exact = 0;
/* inf/x -> inf */
if (a != result)
memcpy(result, a, calc_buffer_size);
return;
}
if (b->desc.clss == ZERO) {
+ fc_exact = 0;
/* division by zero */
if (result->sign)
fc_get_minusinf(&a->desc, result);
/* and the mask and return the result */
sc_and(_mant(a), temp, _mant(result));
- if (a != result) memcpy(_exp(result), _exp(a), value_size);
+ if (a != result) {
+ memcpy(_exp(result), _exp(a), value_size);
+ result->sign = a->sign;
+ }
}
/********
ieee_descriptor_t tmp_desc;
(void) len;
-#ifdef HAVE_LONG_DOUBLE
+#if defined(HAVE_LONG_DOUBLE) && !defined(__CYGWIN__)
val = strtold(str, NULL);
DEBUGPRINTF(("val_from_str(%s)\n", str));
tmp_desc.exponent_size = 15;
}
fp_value *fc_val_from_ieee754(LLDBL l, const ieee_descriptor_t *desc, fp_value *result) {
- char *temp;
- int bias_res, bias_val, mant_val;
+ char *temp;
+ int bias_res, bias_val, mant_val;
value_t srcval;
- UINT32 sign, exponent, mantissa0, mantissa1;
+ char sign;
+ UINT32 exponent, mantissa0, mantissa1;
srcval.d = l;
bias_res = ((1 << (desc->exponent_size - 1)) - 1);
value_t buildval;
ieee_descriptor_t desc;
+ unsigned mantissa_size;
#ifdef HAVE_LONG_DOUBLE
desc.exponent_size = 15;
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);
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;
else
return fc_get_snan(desc, result);
}
+ else if(value->desc.clss == INF) {
+ if (value->sign == 0)
+ return fc_get_plusinf(desc, result);
+ else
+ return fc_get_minusinf(desc, result);
+ }
/* set the descriptor of the new value */
result->desc.exponent_size = desc->exponent_size;
return result;
}
-fp_value *fc_get_plusinf(const ieee_descriptor_t *desc, fp_value *result) {
+fp_value *fc_get_plusinf(const ieee_descriptor_t *desc, fp_value *result)
+{
+ char *mant;
+
if (result == NULL) result = calc_buffer;
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;
sc_val_from_ulong((1 << desc->exponent_size) - 1, _exp(result));
- sc_val_from_ulong(0, _mant(result));
+ mant = _mant(result);
+ sc_val_from_ulong(0, mant);
+ if (desc->explicit_one) {
+ sc_set_bit_at(mant, result->desc.mantissa_size + ROUNDING_BITS);
+ }
return result;
}
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);
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;
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");
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;
/* 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);
}
/* Return non-zero if a given value can be converted lossless into another precision */
-int fc_can_lossless_conv_to(const fp_value *value, char exp_size, char mant_size) {
+int fc_can_lossless_conv_to(const fp_value *value, const ieee_descriptor_t *desc) {
int v;
int exp_bias;
}
/* check if the exponent can be encoded: note, 0 and all ones are reserved for the exponent */
- exp_bias = (1 << (exp_size - 1)) - 1;
+ exp_bias = (1 << (desc->exponent_size - 1)) - 1;
v = fc_get_exponent(value) + exp_bias;
- if (0 < v && v < (1 << exp_size) - 1) {
- /* check the mantissa */
+ if (0 < v && v < (1 << desc->exponent_size) - 1) {
+ /* exponent can be encoded, now check the mantissa */
v = value->desc.mantissa_size + ROUNDING_BITS - sc_get_lowest_set_bit(_mant(value));
- return v < mant_size;
+ return v <= desc->mantissa_size;
}
return 0;
}
/* 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);
/*
* convert a floating point value into an sc value ...
*/
-int fc_flt2int(const fp_value *a, void *result, ir_mode *dst_mode) {
+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;
+ int mantissa_size;
+ int tgt_bits;
if (a->sign && !mode_is_signed(dst_mode)) {
/* FIXME: for now we cannot convert this */
return 0;
}
+ tgt_bits = get_mode_size_bits(dst_mode);
+ if (mode_is_signed(dst_mode))
+ --tgt_bits;
+
assert(exp_val >= 0 && "floating point value not integral before fc_flt2int() call");
- shift = exp_val - (a->desc.mantissa_size + ROUNDING_BITS);
+ mantissa_size = a->desc.mantissa_size + ROUNDING_BITS;
+ shift = exp_val - mantissa_size;
+ if (tgt_bits < mantissa_size + 1)
+ tgt_bits = mantissa_size + 1;
if (shift > 0) {
- sc_shlI(_mant(a), shift, 64, 0, result);
+ sc_shlI(_mant(a), shift, tgt_bits, 0, result);
} else {
- sc_shrI(_mant(a), -shift, 64, 0, result);
+ sc_shrI(_mant(a), -shift, tgt_bits, 0, result);
}
/* check for overflow */