Initial version of the memory disambiguator added
[libfirm] / ir / tv / tv.c
index 5c6b09b..21dab02 100644 (file)
@@ -52,6 +52,7 @@
 #include "strcalc.h"
 #include "fltcalc.h"
 #include "irtools.h"
+#include "xmalloc.h"
 #include "firm_common.h"
 
 /** Size of hash tables.  Should correspond to average number of distinct constant
@@ -97,8 +98,8 @@ static long long count = 0;
 /****************************************************************************
  *   private variables
  ****************************************************************************/
-static struct set *tarvals;   /* container for tarval structs */
-static struct set *values;    /* container for values */
+static struct set *tarvals = NULL;   /* container for tarval structs */
+static struct set *values = NULL;    /* container for values */
 static tarval_int_overflow_mode_t int_overflow_mode = TV_OVERFLOW_WRAP;
 
 /****************************************************************************
@@ -136,13 +137,13 @@ INLINE static void tarval_verify(tarval *tv)
 }
 #endif /* NDEBUG */
 
-static int hash_tv(tarval *tv)
-{
+/** Hash a tarval. */
+static int hash_tv(tarval *tv) {
   return (PTR_TO_INT(tv->value) ^ PTR_TO_INT(tv->mode)) + tv->length;
 }
 
-static int hash_val(const void *value, unsigned int length)
-{
+/** Hash a value. Treat it as a byte array. */
+static int hash_val(const void *value, unsigned int length) {
   unsigned int i;
   unsigned int hash = 0;
 
@@ -191,13 +192,10 @@ static tarval *get_tarval_overflow(const void *value, int length, ir_mode *mode)
           case TV_OVERFLOW_WRAP:
             {
               char *temp = alloca(sc_get_buffer_length());
-              char *diff = alloca(sc_get_buffer_length());
-              sc_sub(get_mode_max(mode)->value, get_mode_min(mode)->value, diff);
-              sc_val_from_ulong(1, temp);
-              sc_add(diff, temp, diff);
-              sc_sub(value, diff, temp);
-              while (sc_comp(temp, get_mode_max(mode)->value) == 1)
-                sc_sub(temp, diff, temp);
+              sc_val_from_ulong(-1, temp);
+              sc_and(temp, value, temp);
+                         /* the sc_ module expects that all bits are set ... */
+              sign_extend(temp, mode);
               return get_tarval(temp, length, mode);
             }
           case TV_OVERFLOW_BAD:
@@ -213,13 +211,8 @@ static tarval *get_tarval_overflow(const void *value, int length, ir_mode *mode)
           case TV_OVERFLOW_WRAP:
             {
               char *temp = alloca(sc_get_buffer_length());
-              char *diff = alloca(sc_get_buffer_length());
-              sc_sub(get_mode_max(mode)->value, get_mode_min(mode)->value, diff);
-              sc_val_from_ulong(1, temp);
-              sc_add(diff, temp, diff);
-              sc_add(value, diff, temp);
-              while (sc_comp(temp, get_mode_max(mode)->value) == 1)
-                sc_add(temp, diff, temp);
+              sc_val_from_ulong(-1, temp);
+              sc_and(temp, value, temp);
               return get_tarval(temp, length, mode);
             }
           case TV_OVERFLOW_BAD:
@@ -248,7 +241,6 @@ static tarval *get_tarval_overflow(const void *value, int length, ir_mode *mode)
   return get_tarval(value, length, mode);
 }
 
-
 /*
  *   public variables declared in tv.h
  */
@@ -916,7 +908,10 @@ tarval *tarval_convert_to(tarval *src, ir_mode *m)
       switch (get_mode_sort(m)) {
         case irms_int_number:
         case irms_character:
-          return get_tarval_overflow(src->value, src->length, m);
+         buffer = alloca(sc_get_buffer_length());
+         memcpy(buffer, src->value, sc_get_buffer_length());
+         sign_extend(buffer, src->mode);
+          return get_tarval_overflow(buffer, src->length, m);
 
         case irms_internal_boolean:
           /* XXX C semantics */
@@ -931,7 +926,8 @@ tarval *tarval_convert_to(tarval *src, ir_mode *m)
           /* decimal string representation because hexadecimal output is
            * interpreted unsigned by fc_val_from_str, so this is a HACK */
           snprintf(buffer, 100, "%s",
-                   sc_print(src->value, get_mode_size_bits(src->mode), SC_DEC));
+                   sc_print(src->value, get_mode_size_bits(src->mode), SC_DEC, mode_is_signed(src->mode)));
+          buffer[100 - 1] = '\0';
           switch (get_mode_size_bits(m))
           {
             case 32:
@@ -1484,23 +1480,26 @@ int tarval_snprintf(char *buf, size_t len, tarval *tv)
 
   switch (get_mode_sort(tv->mode))
   {
+    case irms_reference:
+      if (tv == tv->mode->null) return snprintf(buf, len, "NULL");
+      /* fall through */
     case irms_int_number:
     case irms_character:
       switch (mode_info->mode_output) {
 
       case TVO_DECIMAL:
-        str = sc_print(tv->value, get_mode_size_bits(tv->mode), SC_DEC);
-    break;
+        str = sc_print(tv->value, get_mode_size_bits(tv->mode), SC_DEC, mode_is_signed(tv->mode));
+        break;
 
       case TVO_OCTAL:
-        str = sc_print(tv->value, get_mode_size_bits(tv->mode), SC_OCT);
-    break;
+        str = sc_print(tv->value, get_mode_size_bits(tv->mode), SC_OCT, 0);
+        break;
 
       case TVO_HEX:
       case TVO_NATIVE:
       default:
-        str = sc_print(tv->value, get_mode_size_bits(tv->mode), SC_HEX);
-    break;
+        str = sc_print(tv->value, get_mode_size_bits(tv->mode), SC_HEX, 0);
+        break;
       }
       return snprintf(buf, len, "%s%s%s", prefix, str, suffix);
 
@@ -1519,23 +1518,6 @@ int tarval_snprintf(char *buf, size_t len, tarval *tv)
       }
       break;
 
-    case irms_reference:
-      if (tv == tv->mode->null) return snprintf(buf, len, "NULL");
-      if (tv->value != NULL){
-      if (len > tv->length) {
-        memcpy(buf, tv->value, tv->length);
-        buf[tv->length] = '\0';
-      }
-      else {
-        /* truncated */
-        memcpy(buf, tv->value, len-1);
-        buf[len-1] = '\0';
-      }
-      return tv->length;
-         }
-      else
-    return snprintf(buf, len, "void");
-
     case irms_internal_boolean:
       switch (mode_info->mode_output) {
 
@@ -1579,7 +1561,7 @@ char *get_tarval_bitpattern(tarval *tv)
   int i, j, pos = 0;
   int n = get_mode_size_bits(tv->mode);
   int bytes = (n + 7) / 8;
-  char *res = malloc((n + 1) * sizeof(char));
+  char *res = xmalloc((n + 1) * sizeof(char));
   unsigned char byte;
 
   for(i = 0; i < bytes; i++) {
@@ -1664,7 +1646,33 @@ tarval_classification_t classify_tarval(tarval *tv)
   return TV_CLASSIFY_OTHER;
 }
 
-/**
+/*
+ * Returns non-zero if a given (integer) tarval has only one single bit
+ * set.
+ */
+int is_single_bit_tarval(tarval *tv) {
+  int i, l;
+  int bits;
+
+  if (!tv || tv == tarval_bad) return 0;
+  if (! mode_is_int(tv->mode)) return 0;
+
+  l = get_mode_size_bytes(tv->mode);
+  for (bits = 0, i = l - 1; i >= 0; --i) {
+    unsigned char v = get_tarval_sub_bits(tv, (unsigned)i);
+
+    /* check for more than one bit in these */
+    if (v) {
+      if (v & (v-1))
+        return 0;
+      if (++bits > 1)
+        return 0;
+    }
+  }
+  return bits;
+}
+
+/*
  * Sets the overflow mode for integer operations.
  */
 void tarval_set_integer_overflow_mode(tarval_int_overflow_mode_t ov_mode) {
@@ -1687,15 +1695,6 @@ static const tarval_mode_info hex_output = {
   NULL,
 };
 
-/**
- * default mode_info for output as reference
- */
-static const tarval_mode_info reference_output = {
-  TVO_NATIVE,
-  "&(",
-  ")",
-};
-
 /*
  * Initialization of the tarval module: called before init_mode()
  */
@@ -1721,17 +1720,21 @@ void init_tarval_2(void)
 {
   ANNOUNCE();
 
-  tarval_bad->kind       = k_tarval;
-  tarval_bad->mode       = mode_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->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->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->kind    = k_tarval;
+  tarval_b_false->mode    = mode_b;
+  tarval_b_false->value   = INT_TO_PTR(resid_tarval_b_false);
 
   /*
    * assign output modes that are compatible with the
@@ -1747,7 +1750,7 @@ void init_tarval_2(void)
   set_tarval_mode_output_option(mode_Iu, &hex_output);
   set_tarval_mode_output_option(mode_Ls, &hex_output);
   set_tarval_mode_output_option(mode_Lu, &hex_output);
-  set_tarval_mode_output_option(mode_P,  &reference_output);
+  set_tarval_mode_output_option(mode_P,  &hex_output);
 }
 
 /* free all memory occupied by tarval. */