From ca0508a081617b4b04e9e9f85a6127bd01fad96c Mon Sep 17 00:00:00 2001 From: Michael Beck Date: Mon, 14 Nov 2005 01:43:26 +0000 Subject: [PATCH] BugFix: sc_val_from_str() did not handled hexnumbers right, fixed [r6910] --- ir/tv/strcalc.c | 36 +++++++++++++++++++++++++++++------- ir/tv/strcalc.h | 11 ++++++++++- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/ir/tv/strcalc.c b/ir/tv/strcalc.c index 9a286b4c2..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 }; @@ -957,8 +958,29 @@ 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); diff --git a/ir/tv/strcalc.h b/ir/tv/strcalc.h index 8122544c6..0adf44511 100644 --- a/ir/tv/strcalc.h +++ b/ir/tv/strcalc.h @@ -23,6 +23,8 @@ #ifndef _STRCALC_H_ #define _STRCALC_H_ +#include "irmode.h" + #ifdef STRCALC_DEBUG_ALL /* switch on all debug options */ # ifndef STRCALC_DEBUG # define STRCALC_DEBUG /* switch on debug output */ @@ -118,9 +120,16 @@ enum base_t { const void *sc_get_buffer(void); int sc_get_buffer_length(void); -void sc_val_from_str(const char *str, unsigned int len, void *buffer); +/** create an value form a string representation */ +void sc_val_from_str(const char *str, unsigned int len, void *buffer, ir_mode *mode); + +/** create a value from a long */ void sc_val_from_long(long l, void *buffer); + +/** create a value form an unsigned long */ void sc_val_from_ulong(unsigned long l, void *buffer); + +/** converts a value to a long */ long sc_val_to_long(const void *val); void sc_min_from_bits(unsigned int num_bits, unsigned int sign, void *buffer); void sc_max_from_bits(unsigned int num_bits, unsigned int sign, void *buffer); -- 2.20.1