sign_extend() did NOT expect all upper bits cleared but clear it
[libfirm] / ir / tv / strcalc.c
index 4799bd4..6e45a26 100644 (file)
@@ -32,6 +32,7 @@
 #include <limits.h>   /* definition of LONG_MIN, used in sc_get_val_from_long */
 
 #include "strcalc.h"
+#include "xmalloc.h"
 
 /*
  * local definitions and macros
 #define fail_char(a, b, c, d) _fail_char((a), (b), (c), (d), __FILE__,  __LINE__)
 
 /* shortcut output for debugging */
-#  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 sc_print_hex(a) sc_print((a), 0, SC_HEX, 0)
+#  define sc_print_dec(a) sc_print((a), 0, SC_DEC, 1)
+#  define sc_print_oct(a) sc_print((a), 0, SC_OCT, 0)
+#  define sc_print_bin(a) sc_print((a), 0, SC_BIN, 0)
 
 #ifdef STRCALC_DEBUG_PRINTCOMP
 #  define DEBUGPRINTF_COMPUTATION(x) printf x
@@ -76,6 +77,8 @@ static int carry_flag;              /**< some computation set the carry_flag:
                                          However, the meaning of carry is machine dependent
                                          and often defined in other ways! */
 
+static const char sex_digit[4] = { SC_E, SC_C, SC_8, SC_0 };
+static const char zex_digit[4] = { SC_1, SC_3, SC_7, SC_F };
 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 };
 
@@ -415,7 +418,7 @@ static char const shrs_table[16][4][2] = {
                        { {SC_F, SC_0}, {SC_7, SC_8}, {SC_3, SC_C}, {SC_1, SC_E} }
                                    };
 
-/* for converting to binary string */
+/** converting a digit to a binary string */
 static const char *binary_table[16] = {
   "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
   "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"
@@ -821,7 +824,7 @@ static void _shl(const char *val1, char *buffer, long offset, int radius, unsign
   }
   else if (is_signed && !_bitisset(buffer[offset], bitoffset))
   {
-    /* this unsets the upper bits of the leftmost digit */
+    /* this clears the upper bits of the leftmost digit */
     buffer[offset] = and_table[_val(buffer[offset])][_val(max_digit[bitoffset])];
     for (counter = offset+1; counter < calc_buffer_size; counter++)
     {
@@ -848,7 +851,6 @@ static void _shr(const char *val1, char *buffer, long offset, int radius, unsign
   int bitoffset = 0;
 
   assert((offset >= 0) || (0 && "negative rightshift"));
-  assert(((_sign(val1) != -1) || is_signed) || (0 && "unsigned mode and negative value"));
   assert(((!_bitisset(val1[(radius-1)/4], (radius-1)%4)) || !is_signed || (_sign(val1) == -1)) || (0 && "value is positive, should be negative"));
   assert(((_bitisset(val1[(radius-1)/4], (radius-1)%4)) || !is_signed || (_sign(val1) == 1)) || (0 && "value is negative, should be positive"));
 
@@ -932,7 +934,7 @@ static void _rot(const char *val1, char *buffer, long offset, int radius, unsign
 
   offset = offset % radius;
 
-  /* rotation by multiples of the typelength is identity */
+  /* rotation by multiples of the type length is identity */
   if (offset == 0) {
     memmove(buffer, val1, calc_buffer_size);
     return;
@@ -952,13 +954,43 @@ const void *sc_get_buffer(void)
   return (void*)calc_buffer;
 }
 
-const int sc_get_buffer_length(void)
+int sc_get_buffer_length(void)
 {
   return calc_buffer_size;
 }
 
-/* XXX doesn't check for overflows */
-void sc_val_from_str(const char *str, unsigned int len, void *buffer)
+/**
+ * Do sign extension if the mode is signed, otherwise to zero extension.
+ */
+void sign_extend(char *calc_buffer, ir_mode *mode) {
+  int bits    = get_mode_size_bits(mode) - 1;
+  int nibble  = bits >> 2;
+  int max     = max_digit[bits & 3];
+  int i;
+
+  if (mode_is_signed(mode)) {
+    if (calc_buffer[nibble] > max) {
+      /* sign bit is set, we need sign expansion */
+
+      for (i = nibble + 1; i < calc_buffer_size; ++i)
+        calc_buffer[i] = SC_F;
+      calc_buffer[nibble] = or_table[(int)calc_buffer[nibble]][(int)sex_digit[bits & 3]];
+    } else {
+      /* set all bits to zero */
+      for (i = nibble + 1; i < calc_buffer_size; ++i)
+        calc_buffer[i] = SC_0;
+      calc_buffer[nibble] = and_table[(int)calc_buffer[nibble]][(int)zex_digit[bits & 3]];
+    }
+  } else {
+    /* do zero extension */
+    for (i = nibble + 1; i < calc_buffer_size; ++i)
+      calc_buffer[i] = SC_0;
+    calc_buffer[nibble] = and_table[(int)calc_buffer[nibble]][(int)zex_digit[bits & 3]];
+  }
+}
+
+/* FIXME doesn't check for overflows */
+void sc_val_from_str(const char *str, unsigned int len, void *buffer, ir_mode *mode)
 {
   const char *orig_str = str;
   unsigned int orig_len = len;
@@ -977,8 +1009,8 @@ void sc_val_from_str(const char *str, unsigned int len, void *buffer)
   if (buffer == NULL) buffer = calc_buffer;
 
   CLEAR_BUFFER(buffer);
-  memset(base, SC_0, calc_buffer_size);
-  memset(val, SC_0, calc_buffer_size);
+  CLEAR_BUFFER(base);
+  CLEAR_BUFFER(val);
 
   /* strip leading spaces */
   while ((len > 0) && (*str == ' ')) { len--; str++; }
@@ -1101,9 +1133,10 @@ void sc_val_from_str(const char *str, unsigned int len, void *buffer)
   } /* while (len > 0 ) */
 
   if (sign)
-  {
     _negate(calc_buffer, calc_buffer);
-  }
+
+  /* beware: even if hex numbers have no sign, we need sign extension here */
+  sign_extend(calc_buffer, mode);
 }
 
 void sc_val_from_long(long value, void *buffer)
@@ -1117,7 +1150,7 @@ void sc_val_from_long(long value, void *buffer)
   sign = (value < 0);
   is_minlong = value == LONG_MIN;
 
-  /* use absolute value, special treatment of MIN_LONG */
+  /* use absolute value, special treatment of MIN_LONG to avoid overflow */
   if (sign) {
     if (is_minlong)
       value = -(value+1);
@@ -1133,7 +1166,6 @@ void sc_val_from_long(long value, void *buffer)
     value >>= 4;
   }
 
-
   if (sign) {
     if (is_minlong)
       _inc(buffer, buffer);
@@ -1144,14 +1176,14 @@ void sc_val_from_long(long value, void *buffer)
 
 void sc_val_from_ulong(unsigned long value, void *buffer)
 {
-  char *pos;
+  unsigned char *pos;
 
   if (buffer == NULL) buffer = calc_buffer;
   pos = buffer;
 
-  while (pos < (char*)buffer + calc_buffer_size)
+  while (pos < (unsigned char *)buffer + calc_buffer_size)
   {
-    *pos++ = _digit(value & 0xf);
+    *pos++ = (unsigned char)_digit(value & 0xf);
     value >>= 4;
   }
 }
@@ -1403,8 +1435,8 @@ int sc_had_carry(void)
 
 unsigned char sc_sub_bits(const void *value, int len, unsigned byte_ofs)
 {
-  const char *val     = (const char *)value;
-  unsigned nibble_ofs = 2 * byte_ofs;
+  const char *val = (const char *)value;
+  int nibble_ofs  = 2 * byte_ofs;
   unsigned char res;
 
   /* the current scheme uses one byte to store a nibble */
@@ -1420,9 +1452,9 @@ unsigned char sc_sub_bits(const void *value, int len, unsigned byte_ofs)
 
 /*
  * convert to a string
- * XXX Doesn't check buffer bounds
+ * FIXME: Doesn't check buffer bounds
  */
-const char *sc_print(const void *value, unsigned bits, enum base_t base)
+const char *sc_print(const void *value, unsigned bits, enum base_t base, int signed_mode)
 {
   static const char big_digits[]   = "0123456789ABCDEF";
   static const char small_digits[] = "0123456789abcdef";
@@ -1440,7 +1472,7 @@ const char *sc_print(const void *value, unsigned bits, enum base_t base)
   base_val = alloca(calc_buffer_size);
   div1_res = alloca(calc_buffer_size);
   div2_res = alloca(calc_buffer_size);
-  rem_res = alloca(calc_buffer_size);
+  rem_res  = alloca(calc_buffer_size);
 
   pos = output_buffer + bit_pattern_size;
   *(--pos) = '\0';
@@ -1517,16 +1549,16 @@ const char *sc_print(const void *value, unsigned bits, enum base_t base)
 
     p    = val;
     sign = 0;
-    if (base == SC_DEC) {
+    if (signed_mode && base == SC_DEC) {
       /* check for negative values */
       if (_bit(val, bits - 1)) {
-       _negate(val, div2_res);
-       sign = 1;
-       p = div2_res;
+        _negate(val, div2_res);
+        sign = 1;
+        p = div2_res;
       }
     }
 
-    /* transfer data into oscilating buffers */
+    /* transfer data into oscillating buffers */
     memset(div1_res, SC_0, calc_buffer_size);
     for (counter = 0; counter < nibbles; ++counter)
       div1_res[counter] = p[counter];
@@ -1548,7 +1580,7 @@ const char *sc_print(const void *value, unsigned bits, enum base_t base)
       *(--pos) = digits[_val(rem_res[0])];
 
       x = 0;
-      for (i = 0; i < sizeof(div1_res); ++i)
+      for (i = 0; i < calc_buffer_size; ++i)
        x |= _val(m[i]);
 
       if (x == 0)
@@ -1578,13 +1610,8 @@ void init_strcalc(int precision)
     calc_buffer_size = (precision / 2);
     max_value_size   = (precision / 4);
 
-    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) {
-      assert(0 && "malloc failed");
-      exit(-1);
-    }
+    calc_buffer   = xmalloc(calc_buffer_size+1 * sizeof(char));
+    output_buffer = xmalloc(bit_pattern_size+1 * sizeof(char));
 
     DEBUGPRINTF(("init strcalc: \n\tPRECISION: %d\n\tCALC_BUFFER_SIZE = %d\n\tMAX_VALUE_SIZE = %d\n\tbuffer pointer: %p\n", precision, calc_buffer_size, max_value_size, calc_buffer));
   }