X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=sidebyside;f=ir%2Ftv%2Fstrcalc.c;h=d682979cd2a6e0a98bf35078da8ae1d50a4b3d03;hb=ca0508a081617b4b04e9e9f85a6127bd01fad96c;hp=d1ca023d14455b0880fde83b28f6888d0dec034d;hpb=c13f96787114c58c73b93ff3652f843451c29d48;p=libfirm diff --git a/ir/tv/strcalc.c b/ir/tv/strcalc.c index d1ca023d1..d682979cd 100644 --- a/ir/tv/strcalc.c +++ b/ir/tv/strcalc.c @@ -76,6 +76,7 @@ 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_F, SC_E, SC_C, SC_8 }; 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 }; @@ -952,13 +953,34 @@ 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; } +/** + * 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] = sex_digit[bits & 3]; + } + } +} + /* FIXME doesn't check for overflows */ -void sc_val_from_str(const char *str, unsigned int len, void *buffer) +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 +999,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 +1123,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 +1140,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 +1156,6 @@ void sc_val_from_long(long value, void *buffer) value >>= 4; } - if (sign) { if (is_minlong) _inc(buffer, buffer); @@ -1144,14 +1166,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 +1425,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 */