Add two break; missing in r20857.
[libfirm] / ir / tv / tv.c
index 512a1e5..083e630 100644 (file)
@@ -158,6 +158,29 @@ static int hash_val(const void *value, unsigned int length) {
        return hash;
 }
 
+static int cmp_tv(const void *p1, const void *p2, size_t n) {
+       const tarval *tv1 = p1;
+       const tarval *tv2 = p2;
+       (void) n;
+
+       assert(tv1->kind == k_tarval);
+       assert(tv2->kind == k_tarval);
+       if(tv1->mode < tv2->mode)
+               return -1;
+       if(tv1->mode > tv2->mode)
+               return 1;
+       if(tv1->length < tv2->length)
+               return -1;
+       if(tv1->length > tv2->length)
+               return 1;
+       if(tv1->value < tv2->value)
+               return -1;
+       if(tv1->value > tv2->value)
+               return 1;
+
+       return 0;
+}
+
 /** finds tarval with value/mode or creates new tarval */
 static tarval *get_tarval(const void *value, int length, ir_mode *mode) {
        tarval tv;
@@ -256,12 +279,14 @@ static tarval *get_tarval_overflow(const void *value, int length, ir_mode *mode)
 /*
  *   public variables declared in tv.h
  */
-static tarval reserved_tv[4];
+static tarval reserved_tv[6];
 
-tarval *tarval_bad       = &reserved_tv[0];
-tarval *tarval_undefined = &reserved_tv[1];
-tarval *tarval_b_false   = &reserved_tv[2];
-tarval *tarval_b_true    = &reserved_tv[3];
+tarval *tarval_b_false     = &reserved_tv[0];
+tarval *tarval_b_true      = &reserved_tv[1];
+tarval *tarval_bad         = &reserved_tv[2];
+tarval *tarval_undefined   = &reserved_tv[3];
+tarval *tarval_reachable   = &reserved_tv[4];
+tarval *tarval_unreachable = &reserved_tv[5];
 
 /*
  *   public functions declared in tv.h
@@ -285,8 +310,10 @@ tarval *new_tarval_from_str(const char *str, size_t len, ir_mode *mode)
 
        case irms_internal_boolean:
                /* match [tT][rR][uU][eE]|[fF][aA][lL][sS][eE] */
-               if (strcasecmp(str, "true")) return tarval_b_true;
-               else if (strcasecmp(str, "false")) return tarval_b_true;
+               if (strcasecmp(str, "true"))
+                       return tarval_b_true;
+               else if (strcasecmp(str, "false"))
+                       return tarval_b_true;
                else
                        /* XXX This is C semantics */
                        return atoi(str) ? tarval_b_true : tarval_b_false;
@@ -437,6 +464,14 @@ tarval *(get_tarval_b_true)(void) {
        return _get_tarval_b_true();
 }
 
+tarval *(get_tarval_reachable)(void) {
+       return _get_tarval_reachable();
+}
+
+tarval *(get_tarval_unreachable)(void) {
+       return _get_tarval_unreachable();
+}
+
 tarval *get_tarval_max(ir_mode *mode) {
        assert(mode);
 
@@ -611,6 +646,14 @@ tarval *get_tarval_all_one(ir_mode *mode) {
        return tarval_bad;
 }
 
+int tarval_is_constant(tarval *tv) {
+       int num_res = sizeof(reserved_tv) / sizeof(reserved_tv[0]);
+
+       /* reserved tarvals are NOT constants. Note that although
+          tarval_b_true and tarval_b_false are reserved, they are constants of course. */
+       return (tv < &reserved_tv[2] || tv > &reserved_tv[num_res - 1]);
+}
+
 tarval *get_tarval_minus_one(ir_mode *mode) {
        assert(mode);
 
@@ -864,7 +907,8 @@ tarval *tarval_convert_to(tarval *src, ir_mode *dst_mode) {
        assert(src);
        assert(dst_mode);
 
-       if (src->mode == dst_mode) return src;
+       if (src->mode == dst_mode)
+               return src;
 
        if (get_mode_n_vector_elems(src->mode) > 1) {
                /* vector arithmetic not implemented yet */
@@ -906,7 +950,7 @@ tarval *tarval_convert_to(tarval *src, ir_mode *dst_mode) {
                                res = fc_rnd(src->value, NULL);
                                break;
                        default:
-                               assert(0);
+                               panic("Unsupported float to int conversion mode in tarval_convert_to()");
                                break;
                        }
                        buffer = alloca(sc_get_buffer_length());
@@ -1055,67 +1099,125 @@ tarval *tarval_neg(tarval *a) {
  * addition
  */
 tarval *tarval_add(tarval *a, tarval *b) {
-       char *buffer;
+       tarval  *res;
+       char    *buffer;
+       ir_mode *dst_mode, *src_mode = NULL;
 
        assert(a);
        assert(b);
-       assert(a->mode == b->mode);
 
        if (get_mode_n_vector_elems(a->mode) > 1 || get_mode_n_vector_elems(b->mode) > 1) {
                /* vector arithmetic not implemented yet */
                return tarval_bad;
        }
 
+       if (mode_is_reference(a->mode)) {
+               src_mode = a->mode;
+               dst_mode = find_unsigned_mode(a->mode);
+
+               if (dst_mode == NULL)
+                       return tarval_bad;
+
+               a = tarval_convert_to(a, dst_mode);
+               b = tarval_convert_to(b, dst_mode);
+       }
+       if (mode_is_reference(b->mode)) {
+               src_mode = b->mode;
+               dst_mode = find_unsigned_mode(b->mode);
+
+               if (dst_mode == 0)
+                       return tarval_bad;
+
+               a = tarval_convert_to(a, dst_mode);
+               b = tarval_convert_to(b, dst_mode);
+       }
+
+       assert(a->mode == b->mode);
+
        switch (get_mode_sort(a->mode)) {
        case irms_int_number:
                /* modes of a,b are equal, so result has mode of a as this might be the character */
                buffer = alloca(sc_get_buffer_length());
                sc_add(a->value, b->value, buffer);
-               return get_tarval_overflow(buffer, a->length, a->mode);
+               res = get_tarval_overflow(buffer, a->length, a->mode);
+               break;
 
        case irms_float_number:
                if (no_float)
                        return tarval_bad;
 
                fc_add(a->value, b->value, NULL);
-               return get_tarval_overflow(fc_get_buffer(), fc_get_buffer_length(), a->mode);
+               res = get_tarval_overflow(fc_get_buffer(), fc_get_buffer_length(), a->mode);
+               break;
 
        default:
                return tarval_bad;
        }
+       if (src_mode != NULL)
+               return tarval_convert_to(res, src_mode);
+       return res;
 }
 
 /*
  * subtraction
  */
 tarval *tarval_sub(tarval *a, tarval *b) {
-       char *buffer;
+       tarval  *res;
+       char    *buffer;
+       ir_mode *dst_mode, *src_mode = NULL;
 
        assert(a);
        assert(b);
-       assert(a->mode == b->mode);
 
        if (get_mode_n_vector_elems(a->mode) > 1 || get_mode_n_vector_elems(b->mode) > 1) {
                /* vector arithmetic not implemented yet */
                return tarval_bad;
        }
+       if (mode_is_reference(a->mode)) {
+               src_mode = a->mode;
+               dst_mode = find_unsigned_mode(a->mode);
+
+               if (dst_mode == NULL)
+                       return tarval_bad;
+
+               a = tarval_convert_to(a, dst_mode);
+               b = tarval_convert_to(b, dst_mode);
+       }
+       if (mode_is_reference(b->mode)) {
+               src_mode = b->mode;
+               dst_mode = find_unsigned_mode(b->mode);
+
+               if (dst_mode == 0)
+                       return tarval_bad;
+
+               a = tarval_convert_to(a, dst_mode);
+               b = tarval_convert_to(b, dst_mode);
+       }
+
+       assert(a->mode == b->mode);
+
        switch (get_mode_sort(a->mode)) {
        case irms_int_number:
                /* modes of a,b are equal, so result has mode of a as this might be the character */
                buffer = alloca(sc_get_buffer_length());
                sc_sub(a->value, b->value, buffer);
-               return get_tarval_overflow(buffer, a->length, a->mode);
+               res = get_tarval_overflow(buffer, a->length, a->mode);
+               break;
 
        case irms_float_number:
                if (no_float)
                        return tarval_bad;
 
                fc_sub(a->value, b->value, NULL);
-               return get_tarval_overflow(fc_get_buffer(), fc_get_buffer_length(), a->mode);
+               res = get_tarval_overflow(fc_get_buffer(), fc_get_buffer_length(), a->mode);
+               break;
 
        default:
                return tarval_bad;
        }
+       if (src_mode != NULL)
+               return tarval_convert_to(res, src_mode);
+       return res;
 }
 
 /*
@@ -1308,7 +1410,7 @@ tarval *tarval_and(tarval *a, tarval *b) {
 /*
  * bitwise or
  */
-tarval *tarval_or (tarval *a, tarval *b) {
+tarval *tarval_or(tarval *a, tarval *b) {
        assert(a);
        assert(b);
        assert(a->mode == b->mode);
@@ -1435,9 +1537,9 @@ tarval *tarval_shrs(tarval *a, tarval *b) {
 }
 
 /*
- * bitwise rotation
+ * bitwise rotation to left
  */
-tarval *tarval_rot(tarval *a, tarval *b) {
+tarval *tarval_rotl(tarval *a, tarval *b) {
        char *temp_val = NULL;
 
        assert(a);
@@ -1457,7 +1559,7 @@ tarval *tarval_rot(tarval *a, tarval *b) {
        } else
                temp_val = (char*)b->value;
 
-       sc_rot(a->value, temp_val, get_mode_size_bits(a->mode), mode_is_signed(a->mode), NULL);
+       sc_rotl(a->value, temp_val, get_mode_size_bits(a->mode), mode_is_signed(a->mode), NULL);
        return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode);
 }
 
@@ -1465,6 +1567,7 @@ tarval *tarval_rot(tarval *a, tarval *b) {
  * carry flag of the last operation
  */
 int tarval_carry(void) {
+       panic("tarval_carry() requetsed: not implemented on all operations");
        return sc_had_carry();
 }
 
@@ -1540,7 +1643,15 @@ int tarval_snprintf(char *buf, size_t len, tarval *tv) {
        case irms_control_flow:
        case irms_memory:
        case irms_auxiliary:
-               return snprintf(buf, len, "<TV_OVERFLOW_BAD>");
+               if (tv == tarval_bad)
+                       return snprintf(buf, len, "<TV_BAD>");
+               if (tv == tarval_undefined)
+                       return snprintf(buf, len, "<TV_UNDEF>");
+               if (tv == tarval_unreachable)
+                       return snprintf(buf, len, "<TV_UNREACHABLE>");
+               if (tv == tarval_reachable)
+                       return snprintf(buf, len, "<TV_REACHABLE>");
+               return snprintf(buf, len, "<TV_??""?>");
        }
 
        return 0;
@@ -1658,6 +1769,30 @@ int tarval_ieee754_get_exponent(tarval *tv) {
        return fc_get_exponent(tv->value);
 }
 
+/*
+ * Check if the tarval can be converted to the given mode without
+ * precision loss.
+ */
+int tarval_ieee754_can_conv_lossless(tarval *tv, ir_mode *mode) {
+       char exp_size, mant_size;
+       switch (get_mode_size_bits(mode)) {
+       case 32:
+               exp_size = 8; mant_size = 23;
+               break;
+       case 64:
+               exp_size = 11; mant_size = 52;
+               break;
+       case 80:
+       case 96:
+               exp_size = 15; mant_size = 64;
+               break;
+       default:
+               panic("Unsupported mode in tarval_ieee754_can_conv_lossless()");
+               return 0;
+       }
+       return fc_can_lossless_conv_to(tv->value, exp_size, mant_size);
+}
+
 /* Set the immediate precision for IEEE-754 results. */
 unsigned tarval_ieee754_set_immediate_precision(unsigned bits) {
        return fc_set_immediate_precision(bits);
@@ -1729,11 +1864,15 @@ static const tarval_mode_info hex_output = {
  * Initialization of the tarval module: called before init_mode()
  */
 void init_tarval_1(long null_value) {
+       /* if these assertion fail, tarval_is_constant() will follow ... */
+       assert(tarval_b_false == &reserved_tv[0] && "b_false MUST be the first reserved tarval!");
+       assert(tarval_b_true  == &reserved_tv[1] && "b_true MUST be the second reserved tarval!");
+
        _null_value = null_value;
 
        /* initialize the sets holding the tarvals with a comparison function and
         * an initial size, which is the expected number of constants */
-       tarvals = new_set(memcmp, N_CONSTANTS);
+       tarvals = new_set(cmp_tv, N_CONSTANTS);
        values  = new_set(memcmp, N_CONSTANTS);
        /* init strcalc with precision of 68 to support floating point values with 64
         * bit mantissa (needs extra bits for rounding and overflow) */
@@ -1745,21 +1884,29 @@ void init_tarval_1(long null_value) {
  * Initialization of the tarval module: called after init_mode()
  */
 void init_tarval_2(void) {
-       tarval_bad->kind        = k_tarval;
-       tarval_bad->mode        = mode_BAD;
-       tarval_bad->value       = INT_TO_PTR(resid_tarval_bad);
+       tarval_bad->kind          = k_tarval;
+       tarval_bad->mode          = mode_BAD;
+       tarval_bad->value         = INT_TO_PTR(resid_tarval_bad);
 
-       tarval_undefined->kind  = k_tarval;
-       tarval_undefined->mode  = mode_ANY;
-       tarval_undefined->value = INT_TO_PTR(resid_tarval_undefined);
+       tarval_undefined->kind    = k_tarval;
+       tarval_undefined->mode    = mode_ANY;
+       tarval_undefined->value   = INT_TO_PTR(resid_tarval_undefined);
 
-       tarval_b_true->kind     = k_tarval;
-       tarval_b_true->mode     = mode_b;
-       tarval_b_true->value    = INT_TO_PTR(resid_tarval_b_true);
+       tarval_b_true->kind       = k_tarval;
+       tarval_b_true->mode       = mode_b;
+       tarval_b_true->value      = INT_TO_PTR(resid_tarval_b_true);
 
-       tarval_b_false->kind    = k_tarval;
-       tarval_b_false->mode    = mode_b;
-       tarval_b_false->value   = INT_TO_PTR(resid_tarval_b_false);
+       tarval_b_false->kind      = k_tarval;
+       tarval_b_false->mode      = mode_b;
+       tarval_b_false->value     = INT_TO_PTR(resid_tarval_b_false);
+
+       tarval_unreachable->kind  = k_tarval;
+       tarval_unreachable->mode  = mode_X;
+       tarval_unreachable->value = INT_TO_PTR(resid_tarval_unreachable);
+
+       tarval_reachable->kind    = k_tarval;
+       tarval_reachable->mode    = mode_X;
+       tarval_reachable->value   = INT_TO_PTR(resid_tarval_reachable);
 
        /*
         * assign output modes that are compatible with the
@@ -1784,6 +1931,10 @@ void finish_tarval(void) {
        del_set(values);  values = NULL;
 }
 
+int (is_tarval)(const void *thing) {
+       return _is_tarval(thing);
+}
+
 /****************************************************************************
  *   end of tv.c
  ****************************************************************************/