some fixes for xml dumper / still buggy.
[libfirm] / ir / tv / strcalc.c
index 626e81b..8a2d9ed 100644 (file)
@@ -6,13 +6,13 @@
  * NOTES
  ******/
 
-#include <assert.h>   /* assertions */
-#include <string.h>   /* memset/memcmp */
-
 #include "strcalc.h"
 
-#include <stdio.h>    /* output for error messages */
 #include <stdlib.h>
+#include <assert.h>   /* assertions */
+#include <string.h>   /* memset/memcmp */
+#include <stdio.h>    /* output for error messages */
+#include <limits.h>   /* definition of LONG_MIN, used in sc_get_val_from_long */
 
 /*
  * local definitions and macros
 
 #define fail_char(a, b, c, d) _fail_char((a), (b), (c), (d), __FILE__,  __LINE__)
 
+#ifdef STRCALC_DEBUG_COMPUTATION
+#  define DEBUGPRINTF_COMPUTATION(x) printf x
+#else
+#  define DEBUGPRINTF_COMPUTATION(x) ((void)0)
+#endif
 #ifdef STRCALC_DEBUG
-  /* shortcut output for debugging only, gices always full precisition */
-#  define sc_print_hex(a) sc_print((a), 0, SC_HEX)
-#  define sc_print_dec(a) sc_print((a), 0, SC_DEC)
-#  define sc_print_oct(a) sc_print((a), 0, SC_OCT)
-#  define sc_print_bin(a) sc_print((a), 0, SC_BIN)
 #  define DEBUGPRINTF(x) printf x
 #else
 #  define DEBUGPRINTF(x) ((void)0)
 #endif
 
+
 /*
  * private variables
  */
 
 static char *calc_buffer = NULL;    /* buffer holding all results */
 static char *output_buffer = NULL;  /* buffer for output */
-static int BIT_PATTERN_SIZE;
-static int CALC_BUFFER_SIZE;
-static int MAX_VALUE_SIZE;
+static int BIT_PATTERN_SIZE;        /* maximum number of bits */
+static int CALC_BUFFER_SIZE;        /* size of internally stored values */
+static int MAX_VALUE_SIZE;          /* maximum size of values */
+
+static int carry_flag;              /* some computation set carry_flag: */
+                                    /* rightshift if bits were lost due to shifting */
+                                    /* division if there was a remainder */
 
 static const char max_digit[4] = { SC_0, SC_1, SC_3, SC_7 };
 static const char min_digit[4] = { SC_F, SC_E, SC_C, SC_8 };
@@ -94,7 +99,7 @@ static const char and_table[16][16] = {
                               SC_8, SC_8, SC_8, SC_8, SC_C, SC_C, SC_C, SC_C },
 
                             { SC_0, SC_1, SC_0, SC_1, SC_4, SC_5, SC_4, SC_5,
-                              SC_8, SC_9, SC_8, SC_9, SC_D, SC_E, SC_D, SC_E },
+                              SC_8, SC_9, SC_8, SC_9, SC_C, SC_D, SC_C, SC_D },
 
                             { SC_0, SC_0, SC_2, SC_2, SC_4, SC_4, SC_6, SC_6,
                               SC_8, SC_8, SC_A, SC_A, SC_C, SC_C, SC_E, SC_E },
@@ -440,6 +445,17 @@ static int _sign(const char *val)
   return (val[CALC_BUFFER_SIZE-1] <= SC_7) ? (1) : (-1);
 }
 
+/*
+ * returns non-zero if bit at position pos is set
+ */
+static int _bit(const char *val, int pos)
+{
+  int bit    = pos & 3;
+  int nibble = pos >> 2;
+
+  return _bitisset(val[nibble], bit);
+}
+
 static void _inc(char *val, char *buffer)
 {
   int counter = 0;
@@ -458,8 +474,8 @@ static void _inc(char *val, char *buffer)
       return;
     }
   }
-  /* here a carry could be lost, this is intended because this will only
-   * happen when a value changes sign. */
+  /* here a carry could be lost, this is intended because this should
+   * happen only when a value changes sign. */
 }
 
 static void _negate(const char *val, char *buffer)
@@ -482,7 +498,6 @@ static void _add(const char *val1, const char *val2, char *buffer)
     buffer[counter] = add2[0];
     carry = add_table[_val(add1[1])][_val(add2[1])][0];
   }
-  /* loose last carry, which will occur only when changing sign */
 }
 
 static void _mul(const char *val1, const char *val2, char *buffer)
@@ -548,6 +563,7 @@ static void _mul(const char *val1, const char *val2, char *buffer)
       /* A carry may hang over */
       /* c_outer is always smaller than MAX_VALUE_SIZE! */
       temp_buffer[MAX_VALUE_SIZE + c_outer] = carry;
+      carry = SC_0;
     }
   }
 
@@ -591,11 +607,12 @@ static void _divmod(const char *dividend, const char *divisor, char *quot, char
   memset(quot, SC_0, CALC_BUFFER_SIZE);
   memset(rem, SC_0, CALC_BUFFER_SIZE);
 
+  /* if the divisor is zero this won't work (quot is zero) */
+  if (sc_comp(divisor, quot) == 0) assert(0 && "division by zero!");
+
   /* if the dividend is zero result is zero (quot is zero)*/
   if (sc_comp(dividend, quot) == 0)
     return;
-  /* if the divisor is zero this won't work (quot is zero) */
-  if (sc_comp(divisor, quot) == 0) assert(0 && "division by zero!");
 
   if (_sign(dividend) == -1)
   {
@@ -616,7 +633,7 @@ static void _divmod(const char *dividend, const char *divisor, char *quot, char
     minus_divisor = neg_val2;
   }
 
-  /* if divisor >= dividend quotision is easy
+  /* if divisor >= dividend division is easy
    * (remember these are absolute values) */
   switch (sc_comp(dividend, divisor))
   {
@@ -628,11 +645,11 @@ static void _divmod(const char *dividend, const char *divisor, char *quot, char
       memcpy(rem, dividend, CALC_BUFFER_SIZE);
       return;
 
-    default: /* unluckily quotision is necessary :( */
+    default: /* unluckily division is necessary :( */
       break;
   }
 
-  for (c_dividend = MAX_VALUE_SIZE - 1; c_dividend >= 0; c_dividend--)
+  for (c_dividend = CALC_BUFFER_SIZE - 1; c_dividend >= 0; c_dividend--)
   {
     _push(dividend[c_dividend], rem);
     _push(SC_0, quot);
@@ -654,6 +671,8 @@ static void _divmod(const char *dividend, const char *divisor, char *quot, char
     }
   }
 
+  carry_flag = !sc_is_zero(rem);
+
   if (sign)
   {
     _negate(quot, quot);
@@ -756,16 +775,26 @@ static void _shr(const char *val1, char *buffer, long offset, int radius, unsign
   shift = offset % 4;
   offset = offset / 4;
 
+  /* check if any bits are lost, and set carry_flag is so */
+  for (counter = 0; counter < offset; counter++)
+  {
+    if (val1[counter] != carry_flag)
+    {
+      carry_flag = 1;
+      break;
+    }
+  }
+  if ((carry_flag == 0) && (_val(val1[counter]) & shift) != 0)
+    carry_flag = 1;
+
+  /* shift digits to the right with offset, carry and all */
   counter = 0;
   if (radius/4 - offset > 0) {
     buffer[counter] = shrs_table[_val(val1[offset])][shift][0];
     counter = 1;
   }
-
-  /* shift digits to the right with offset, carry and all */
   for (; counter < radius/4 - offset; counter++)
   {
-
     shrs = shrs_table[_val(val1[counter + offset])][shift];
     buffer[counter] = shrs[0];
     buffer[counter-1] = or_table[_val(buffer[counter-1])][_val(shrs[1])];
@@ -773,7 +802,7 @@ static void _shr(const char *val1, char *buffer, long offset, int radius, unsign
 
   /* the last digit is special in regard of signed/unsigned shift */
   bitoffset = radius%4;
-  msd = val1[radius/4];  /* most significant digit */
+  msd = (radius/4<CALC_BUFFER_SIZE)?(val1[radius/4]):(sign);  /* most significant digit */
 
   /* remove sign bits if mode was signed and this is an unsigned shift */
   if (!signed_shift && is_signed) {
@@ -788,6 +817,7 @@ static void _shr(const char *val1, char *buffer, long offset, int radius, unsign
   } else {
     buffer[counter] = shrs[0];
   }
+
   if (counter > 0) buffer[counter - 1] = or_table[_val(buffer[counter-1])][_val(shrs[1])];
 
   /* fill with SC_F or SC_0 depending on sign */
@@ -803,13 +833,6 @@ static void _rot(const char *val1, char *buffer, long offset, int radius, unsign
   char temp1[CALC_BUFFER_SIZE];
   char temp2[CALC_BUFFER_SIZE];
 
-  const char *shl;
-  char carry = SC_0;
-
-  int counter, old_counter;
-  int shift;
-  int bitoffset;
-
   offset = offset % radius;
 
   /* rotation by multiples of the typelength is identity */
@@ -821,6 +844,7 @@ static void _rot(const char *val1, char *buffer, long offset, int radius, unsign
   _shl(val1, temp1, offset, radius, is_signed);
   _shr(val1, temp2, radius - offset, radius, is_signed, 0);
   _bitor(temp1, temp2, buffer);
+  carry_flag = 0; /* set by shr, but due to rot this is false */
 }
 
 /*****************************************************************************
@@ -907,7 +931,7 @@ void sc_val_from_str(const char *str, unsigned int len)
     base[1] = SC_0; base[0] = SC_A;
   }
 
-  /* begin string evaluation, from left to right */
+  /* BEGIN string evaluation, from left to right */
   while (len > 0)
   {
     switch (*str)
@@ -984,13 +1008,19 @@ void sc_val_from_str(const char *str, unsigned int len)
 void sc_val_from_long(long value)
 {
   char *pos;
-  int sign;
+  char sign, is_minlong;
 
   pos = calc_buffer;
   sign = (value < 0);
+  is_minlong = value == LONG_MIN;
 
-  /* FIXME MININT won't work */
-  if (sign) value = -value;
+  /* use absolute value, special treatment of MIN_LONG */
+  if (sign) {
+    if (is_minlong)
+      value = -(value+1);
+    else
+      value = -value;
+  }
 
   CLEAR_CALC_BUFFER();
 
@@ -1000,7 +1030,11 @@ void sc_val_from_long(long value)
     value /= 16;
   }
 
-  if (sign) _negate(calc_buffer, calc_buffer);
+
+  if (sign) {
+    if (is_minlong) _inc(calc_buffer, calc_buffer);
+    _negate(calc_buffer, calc_buffer);
+  }
 }
 
 long sc_val_to_long(const void *val)
@@ -1060,56 +1094,57 @@ void sc_calc(const void* value1, const void* value2, unsigned op)
   const char *val1 = (const char *)value1;
   const char *val2 = (const char *)value2;
   CLEAR_CALC_BUFFER();
+  carry_flag = 0;
 
-  DEBUGPRINTF(("%s ", sc_print(value1, SC_HEX)));
+  DEBUGPRINTF_COMPUTATION(("%s ", sc_print_hex(value1)));
 
   switch (op)
   {
     case SC_NEG:
       _negate(val1, calc_buffer);
-      DEBUGPRINTF(("negated: %s\n", sc_print_hex(calc_buffer)));
+      DEBUGPRINTF_COMPUTATION(("negated: %s\n", sc_print_hex(calc_buffer)));
       return;
     case SC_OR:
-      DEBUGPRINTF(("| "));
+      DEBUGPRINTF_COMPUTATION(("| "));
       _bitor(val1, val2, calc_buffer);
       break;
     case SC_AND:
-      DEBUGPRINTF(("& "));
+      DEBUGPRINTF_COMPUTATION(("& "));
       _bitand(val1, val2, calc_buffer);
       break;
     case SC_XOR:
-      DEBUGPRINTF(("^ "));
+      DEBUGPRINTF_COMPUTATION(("^ "));
       _bitxor(val1, val2, calc_buffer);
       break;
     case SC_NOT:
       _bitnot(val1, calc_buffer);
-      DEBUGPRINTF(("bit-negated: %s\n", sc_print_hex(calc_buffer)));
+      DEBUGPRINTF_COMPUTATION(("bit-negated: %s\n", sc_print_hex(calc_buffer)));
       return;
     case SC_ADD:
-      DEBUGPRINTF(("+ "));
+      DEBUGPRINTF_COMPUTATION(("+ "));
       _add(val1, val2, calc_buffer);
       break;
     case SC_SUB:
-      DEBUGPRINTF(("- "));
+      DEBUGPRINTF_COMPUTATION(("- "));
       _sub(val1, val2, calc_buffer);
       break;
     case SC_MUL:
-      DEBUGPRINTF(("* "));
+      DEBUGPRINTF_COMPUTATION(("* "));
       _mul(val1, val2, calc_buffer);
       break;
     case SC_DIV:
-      DEBUGPRINTF(("/ "));
+      DEBUGPRINTF_COMPUTATION(("/ "));
       _divmod(val1, val2, calc_buffer, unused_res);
       break;
     case SC_MOD:
-      DEBUGPRINTF(("%% "));
+      DEBUGPRINTF_COMPUTATION(("%% "));
       _divmod(val1, val2, unused_res, calc_buffer);
       break;
     default:
       assert(0);
   }
-  DEBUGPRINTF(("%s -> ", sc_print_hex(value2)));
-  DEBUGPRINTF(("%s\n", sc_print_hex(calc_buffer)));
+  DEBUGPRINTF_COMPUTATION(("%s -> ", sc_print_hex(value2)));
+  DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer)));
 }
 
 void sc_bitcalc(const void* value1, const void* value2, int radius, int sign, unsigned op)
@@ -1118,31 +1153,32 @@ void sc_bitcalc(const void* value1, const void* value2, int radius, int sign, un
   const char *val2 = (const char *)value2;
   long offset;
 
+  carry_flag = 0;
   offset = sc_val_to_long(val2);
 
-  DEBUGPRINTF(("%s ", sc_print_hex(value1)));
+  DEBUGPRINTF_COMPUTATION(("%s ", sc_print_hex(value1)));
   switch (op)
   {
     case SC_SHL:
-      DEBUGPRINTF(("<< %d ", offset));
+      DEBUGPRINTF_COMPUTATION(("<< %d ", offset));
       _shl(val1, calc_buffer, offset, radius, sign);
       break;
     case SC_SHR:
-      DEBUGPRINTF((">> %d ", offset));
+      DEBUGPRINTF_COMPUTATION((">> %d ", offset));
       _shr(val1, calc_buffer, offset, radius, sign, 0);
       break;
     case SC_SHRS:
-      DEBUGPRINTF((">>> %d ", offset));
+      DEBUGPRINTF_COMPUTATION((">>> %d ", offset));
       _shr(val1, calc_buffer, offset, radius, sign, 1);
       break;
     case SC_ROT:
-      DEBUGPRINTF(("<<>> %d ", offset));
+      DEBUGPRINTF_COMPUTATION(("<<>> %d ", offset));
       _rot(val1, calc_buffer, offset, radius, sign);
       break;
     default:
       assert(0);
   }
-  DEBUGPRINTF(("-> %s\n", sc_print_hex(calc_buffer)));
+  DEBUGPRINTF_COMPUTATION(("-> %s\n", sc_print_hex(calc_buffer)));
 }
 
 int sc_comp(const void* value1, const void* value2)
@@ -1173,7 +1209,6 @@ int sc_get_highest_set_bit(const void *value)
 {
   const char *val = (const char*)value;
   int high, counter;
-  char sign;
 
   high = CALC_BUFFER_SIZE * 4;
 
@@ -1210,6 +1245,27 @@ int sc_get_lowest_set_bit(const void *value)
   return low;
 }
 
+int sc_is_zero(const void *value)
+{
+  const char* val = (const char *)value;
+  int counter;
+
+  for (counter = 0; counter < CALC_BUFFER_SIZE; counter++) {
+    if (val[counter] != SC_0) return 0;
+  }
+  return 1;
+}
+
+int sc_is_negative(const void *value)
+{
+  return _sign(value) == -1;
+}
+
+int sc_had_carry(void)
+{
+  return carry_flag;
+}
+
 unsigned char sc_sub_bits(const void *value, int len, unsigned byte_ofs)
 {
   const char *val     = (const char *)value;
@@ -1229,9 +1285,13 @@ unsigned char sc_sub_bits(const void *value, int len, unsigned byte_ofs)
 
 /*
  * convert to a string
+ * XXX Doesn't check buffer bounds
  */
 const char *sc_print(const void *value, unsigned bits, enum base_t base)
 {
+  static const char big_digits[]   = "0123456789ABCDEF";
+  static const char small_digits[] = "0123456789abcdef";
+
   char base_val[CALC_BUFFER_SIZE];
   char div1_res[CALC_BUFFER_SIZE];
   char div2_res[CALC_BUFFER_SIZE];
@@ -1243,31 +1303,46 @@ const char *sc_print(const void *value, unsigned bits, enum base_t base)
   const char *p;
   char *m, *n, *t;
   char *pos;
+  const char *digits = small_digits;
 
-  pos = output_buffer + BIT_PATTERN_SIZE;
-  *pos = '\0';
+  pos = output_buffer + BIT_PATTERN_SIZE ;
+  *(--pos) = '\0';
 
   /* special case */
-  if (bits == 0)
+  if (bits == 0) {
     bits = BIT_PATTERN_SIZE;
-
+#ifdef STRCALC_DEBUG_FULLPRINT
+    bits <<= 1;
+#endif
+  }
   nibbles = bits >> 2;
   switch (base) {
 
   case SC_HEX:
-    for (counter = 0; counter < nibbles; ++counter)
-      *(--pos) = "0123456789abcdef"[_val(val[counter])];
+    digits = big_digits;
+  case SC_hex:
+    for (counter = 0; counter < nibbles; ++counter) {
+      *(--pos) = digits[_val(val[counter])];
+#ifdef STRCALC_DEBUG_GROUPPRINT
+      if ((counter+1)%8 == 0)
+        *(--pos) = ' ';
+#endif
+    }
 
     /* last nibble must be masked */
     if (bits & 3) {
       x = and_table[_val(val[++counter])][bits & 3];
-      *(--pos) = "0123456789abcdef"[_val(x)];
+      *(--pos) = digits[_val(x)];
     }
 
     /* now kill zeros */
-    for (; counter > 1; --counter, ++pos)
+    for (; counter > 1; --counter, ++pos) {
+#ifdef STRCALC_DEBUG_GROUPPRINT
+      if (pos[0] == ' ') ++pos;
+#endif
       if (pos[0] != '0')
        break;
+    }
     break;
 
   case SC_BIN:
@@ -1303,27 +1378,27 @@ const char *sc_print(const void *value, unsigned bits, enum base_t base)
     memset(base_val, SC_0, CALC_BUFFER_SIZE);
     base_val[0] = base == SC_DEC ? SC_A : SC_8;
 
-    m    = val;
+    p    = val;
     sign = 0;
     if (base == SC_DEC) {
       /* check for negative values */
-      if (_sign(val) == -1) {
+      if (_bit(val, bits - 1)) {
        _negate(val, div2_res);
        sign = 1;
-       m = div2_res;
+       p = div2_res;
       }
     }
 
     /* transfer data into oscilating buffers */
     memset(div1_res, SC_0, CALC_BUFFER_SIZE);
     for (counter = 0; counter < nibbles; ++counter)
-      div1_res[counter] = m[counter];
+      div1_res[counter] = p[counter];
 
      /* last nibble must be masked */
     if (bits & 3) {
       ++counter;
 
-      div1_res[counter] = and_table[_val(m[counter])][bits & 3];
+      div1_res[counter] = and_table[_val(p[counter])][bits & 3];
     }
 
     m = div1_res;
@@ -1333,7 +1408,7 @@ const char *sc_print(const void *value, unsigned bits, enum base_t base)
       t = m;
       m = n;
       n = t;
-      *(--pos) = "0123456789abcdef"[_val(rem_res[0])];
+      *(--pos) = digits[_val(rem_res[0])];
 
       x = 0;
       for (i = 0; i < sizeof(div1_res); ++i)
@@ -1362,8 +1437,8 @@ void init_strcalc(int precision_in_bytes)
     CALC_BUFFER_SIZE = (4 * precision_in_bytes);
     MAX_VALUE_SIZE   = (2 * precision_in_bytes);
 
-    calc_buffer = malloc(CALC_BUFFER_SIZE * sizeof(char));
-    output_buffer = malloc(BIT_PATTERN_SIZE * sizeof(char));
+    calc_buffer = malloc(CALC_BUFFER_SIZE+1 * sizeof(char));
+    output_buffer = malloc(BIT_PATTERN_SIZE+1 * sizeof(char));
 
     if (calc_buffer == NULL || output_buffer == NULL)
     {