- fixed warning
[libfirm] / ir / tv / fltcalc.c
index 600e0ae..0f162da 100644 (file)
@@ -25,9 +25,7 @@
  * @version  $Id$
  */
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "config.h"
 
 #include "fltcalc.h"
 #include "strcalc.h"
 #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 <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;
@@ -182,6 +176,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 +393,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 +434,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 +474,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 +550,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 +561,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 +573,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 +637,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 +651,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 +666,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 +674,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);
@@ -1024,10 +1034,11 @@ done:
 }
 
 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);
@@ -1140,6 +1151,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 +1164,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 +1182,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 +1332,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 +1421,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 +1429,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 +1451,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 +1460,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 +1482,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);
@@ -1489,7 +1502,7 @@ int fc_get_exponent(const fp_value *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;
 
@@ -1504,12 +1517,12 @@ int fc_can_lossless_conv_to(const fp_value *value, char exp_size, char mant_size
        }
 
        /* 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;
 }
@@ -1531,11 +1544,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);