#include <limits.h> /* definition of LONG_MIN, used in sc_get_val_from_long */
#include "strcalc.h"
+#include "xmalloc.h"
/*
* local definitions and macros
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 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 };
{ {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"
}
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++)
{
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;
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, expects all upper bits
+ * cleared.
+ */
+static void sign_extend(char *calc_buffer, ir_mode *mode) {
+ if (mode_is_signed(mode)) {
+ int bits = get_mode_size_bits(mode) - 1;
+ int ofs = bits >> 2;
+ int max = max_digit[bits & 3];
+ int i;
+
+ if (calc_buffer[ofs] > max) {
+ /* sign bit is set, we need sign expansion */
+
+ for (i = ofs + 1; i < calc_buffer_size; ++i)
+ calc_buffer[i] = SC_F;
+ calc_buffer[ofs] = or_table[calc_buffer[ofs]][sex_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;
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++; }
} /* 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)
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);
value >>= 4;
}
-
if (sign) {
if (is_minlong)
_inc(buffer, 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;
}
}
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 */
/*
* 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)
{
if (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];
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));
+ calc_buffer = xmalloc(calc_buffer_size+1 * sizeof(char));
+ output_buffer = xmalloc(bit_pattern_size+1 * sizeof(char));
if (calc_buffer == NULL || output_buffer == NULL) {
assert(0 && "malloc failed");