+const void *sc_get_buffer(void) {
+ return (void*)calc_buffer;
+}
+
+int sc_get_buffer_length(void) {
+ return calc_buffer_size;
+}
+
+/**
+ * Do sign extension if the mode is signed, otherwise to zero extension.
+ */
+void sign_extend(void *buffer, ir_mode *mode) {
+ char *calc_buffer = buffer;
+ 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;
+
+ char sign = 0;
+ char *base, *val;
+
+ base = alloca(calc_buffer_size);
+ val = alloca(calc_buffer_size);
+
+ /* verify valid pointers (not null) */
+ assert(str);
+ /* a string no characters long is an error */
+ assert(len);
+
+ if (buffer == NULL) buffer = calc_buffer;
+
+ CLEAR_BUFFER(buffer);
+ CLEAR_BUFFER(base);
+ CLEAR_BUFFER(val);
+
+ /* strip leading spaces */
+ while ((len > 0) && (*str == ' ')) { len--; str++; }
+
+ /* if the first two characters are 0x or 0X -> hex
+ * if the first is a 0 -> oct
+ * else dec, strip leading -/+ and remember sign
+ *
+ * only a + or - sign is no number resulting in an error */
+ if (len >= 2) {
+ switch (str[0]) {
+ case '0':
+ if (str[1] == 'x' || str[1] == 'X') { /* hex */
+ str += 2;
+ len -= 2;
+ base[1] = SC_1; base[0] = SC_0;
+ } else { /* oct */
+ str += 1;
+ len -= 1;
+ base[1] = SC_0; base[0] = SC_8;
+ }
+ break;
+
+ case '+':
+ str += 1;
+ len -= 1;
+ base[1] = SC_0; base[0] = SC_A;
+ break;
+
+ case '-':
+ str += 1;
+ len -= 1;
+ sign = 1;
+ base[1] = SC_0; base[0] = SC_A;
+ break;
+
+ default: /* dec, else would have begun with 0x or 0 */
+ base[1] = SC_0; base[0] = SC_A;
+ }
+ } else { /* dec, else would have begun with 0x or 0 */
+ base[1] = SC_0; base[0] = SC_A;
+ }
+
+ /* BEGIN string evaluation, from left to right */
+ while (len > 0) {
+ switch (*str) {
+ case 'f':
+ case 'e':
+ case 'd':
+ case 'c':
+ case 'b':
+ case 'a':
+ if (base[0] > SC_9 || base[1] > SC_0) { /* (base > 10) */
+ val[0] = _digit((*str)-'a'+10);
+ }
+ else
+ fail_char(orig_str, orig_len, *str, str-orig_str+1);
+ break;
+
+ case 'F':
+ case 'E':
+ case 'D':
+ case 'C':
+ case 'B':
+ case 'A':
+ if (base[0] > SC_9 || base[1] > SC_0) { /* (base > 10) */
+ val[0] = _digit((*str)-'A'+10);
+ }
+ else
+ fail_char(orig_str, orig_len, *str, str-orig_str+1);
+ break;
+
+ case '9':
+ case '8':
+ if (base[0] > SC_7 || base[1] > SC_0) { /* (base > 8) */
+ val[0] = _digit((*str)-'0');
+ }
+ else
+ fail_char(orig_str, orig_len, *str, str-orig_str+1);
+ break;
+
+ case '7':
+ case '6':
+ case '5':
+ case '4':
+ case '3':
+ case '2':
+ case '1':
+ case '0':
+ val[0] = _digit((*str)-'0');
+ break;
+
+ default:
+ fail_char(orig_str, orig_len, *str, str-orig_str+1);
+ } /* switch(*str) */
+
+ /* Radix conversion from base b to base B:
+ * (UnUn-1...U1U0)b == ((((Un*b + Un-1)*b + ...)*b + U1)*b + U0)B */
+ do_mul(base, calc_buffer, calc_buffer); /* multiply current value with base */
+ do_add(val, calc_buffer, calc_buffer); /* add next digit to current value */
+
+ /* get ready for the next letter */
+ str++;
+ len--;
+ } /* while (len > 0 ) */
+
+ if (sign)
+ do_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) {
+ char *pos;
+ char sign, is_minlong;
+
+ if (buffer == NULL) buffer = calc_buffer;
+ pos = buffer;
+
+ sign = (value < 0);
+ is_minlong = value == LONG_MIN;
+
+ /* use absolute value, special treatment of MIN_LONG to avoid overflow */
+ if (sign) {
+ if (is_minlong)
+ value = -(value+1);
+ else
+ value = -value;
+ }
+
+ CLEAR_BUFFER(buffer);
+
+ while ((value != 0) && (pos < (char*)buffer + calc_buffer_size)) {
+ *pos++ = _digit(value & 0xf);
+ value >>= 4;
+ }
+
+ if (sign) {
+ if (is_minlong)
+ do_inc(buffer, buffer);
+
+ do_negate(buffer, buffer);
+ }
+}
+
+void sc_val_from_ulong(unsigned long value, void *buffer) {
+ unsigned char *pos;
+
+ if (buffer == NULL) buffer = calc_buffer;
+ pos = buffer;
+
+ while (pos < (unsigned char *)buffer + calc_buffer_size) {
+ *pos++ = (unsigned char)_digit(value & 0xf);
+ value >>= 4;
+ }
+}
+
+long sc_val_to_long(const void *val) {
+ int i;
+ long l = 0;
+
+ for (i = calc_buffer_size - 1; i >= 0; i--) {
+ l = (l << 4) + _val(((char *)val)[i]);
+ }
+ return l;
+}
+
+void sc_min_from_bits(unsigned int num_bits, unsigned int sign, void *buffer) {
+ char *pos;
+ int i, bits;
+
+ if (buffer == NULL) buffer = calc_buffer;
+ CLEAR_BUFFER(buffer);
+
+ if (!sign) return; /* unsigned means minimum is 0(zero) */
+
+ pos = buffer;
+
+ bits = num_bits - 1;
+ for (i = 0; i < bits/4; i++)
+ *pos++ = SC_0;
+
+ *pos++ = min_digit[bits%4];
+
+ for (i++; i <= calc_buffer_size - 1; i++)
+ *pos++ = SC_F;
+}
+
+void sc_max_from_bits(unsigned int num_bits, unsigned int sign, void *buffer) {
+ char* pos;
+ int i, bits;
+
+ if (buffer == NULL) buffer = calc_buffer;
+ CLEAR_BUFFER(buffer);
+ pos = buffer;
+
+ bits = num_bits - sign;
+ for (i = 0; i < bits/4; i++)
+ *pos++ = SC_F;
+
+ *pos++ = max_digit[bits%4];
+
+ for (i++; i <= calc_buffer_size - 1; i++)
+ *pos++ = SC_0;
+}
+
+void sc_truncate(unsigned int num_bits, void *buffer) {
+ char *cbuffer = buffer;
+ char *pos = cbuffer + (num_bits / 4);
+ char *end = cbuffer + calc_buffer_size;
+
+ assert(pos < end);
+
+ switch(num_bits % 4) {
+ case 0: /* nothing to do */ break;
+ case 1: *pos = and_table[_val(*pos)][SC_1]; pos++; break;
+ case 2: *pos = and_table[_val(*pos)][SC_3]; pos++; break;
+ case 3: *pos = and_table[_val(*pos)][SC_7]; pos++; break;
+ }
+
+ for( ; pos < end; ++pos)
+ *pos = SC_0;
+}
+
+int sc_comp(const void* value1, const void* value2) {
+ int counter = calc_buffer_size - 1;
+ const char *val1 = (const char *)value1;
+ const char *val2 = (const char *)value2;
+
+ /* compare signs first:
+ * the loop below can only compare values of the same sign! */
+ if (do_sign(val1) != do_sign(val2))
+ return (do_sign(val1) == 1)?(1):(-1);
+
+ /* loop until two digits differ, the values are equal if there
+ * are no such two digits */
+ while (val1[counter] == val2[counter]) {
+ counter--;
+ if (counter < 0) return 0;
+ }
+
+ /* the leftmost digit is the most significant, so this returns
+ * the correct result.
+ * This implies the digit enum is ordered */
+ return (val1[counter] > val2[counter]) ? (1) : (-1);
+}
+
+int sc_get_highest_set_bit(const void *value) {
+ const char *val = (const char*)value;
+ int high, counter;
+
+ high = calc_buffer_size * 4 - 1;
+
+ for (counter = calc_buffer_size-1; counter >= 0; counter--) {
+ if (val[counter] == SC_0)
+ high -= 4;
+ else {
+ if (val[counter] > SC_7) return high;
+ else if (val[counter] > SC_3) return high - 1;
+ else if (val[counter] > SC_1) return high - 2;
+ else return high - 3;
+ }
+ }
+ return high;
+}
+
+int sc_get_lowest_set_bit(const void *value) {
+ const char *val = (const char*)value;
+ int low, counter;
+
+ low = 0;
+ for (counter = 0; counter < calc_buffer_size; counter++) {
+ switch (val[counter]) {
+ case SC_1:
+ case SC_3:
+ case SC_5:
+ case SC_7:
+ case SC_9:
+ case SC_B:
+ case SC_D:
+ case SC_F:
+ return low;
+ case SC_2:
+ case SC_6:
+ case SC_A:
+ case SC_E:
+ return low + 1;
+ case SC_4:
+ case SC_C:
+ return low + 2;
+ case SC_8:
+ return low + 3;
+ default:
+ low += 4;
+ }
+ }
+ return -1;
+}
+
+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 do_sign(value) == -1;