From ad7ea5e733b5a62df40a954ff5acdb2131cc4ace Mon Sep 17 00:00:00 2001 From: =?utf8?q?G=C3=B6tz=20Lindenmaier?= Date: Wed, 26 Mar 2003 09:43:45 +0000 Subject: [PATCH] New implementation of tarval module [r981] --- ir/tv/Makefile.in | 2 +- ir/tv/fltcalc.c | 156 ++++ ir/tv/fltcalc.h | 34 + ir/tv/ieee754.h | 208 +++-- ir/tv/strcalc.c | 1229 ++++++++++++++++++++++++++++ ir/tv/strcalc.h | 110 +++ ir/tv/tv.c | 1955 +++++++++++++++++---------------------------- ir/tv/tv.h | 591 ++++++++++---- ir/tv/tv_t.h | 50 +- 9 files changed, 2873 insertions(+), 1462 deletions(-) create mode 100644 ir/tv/fltcalc.c create mode 100644 ir/tv/fltcalc.h create mode 100644 ir/tv/strcalc.c create mode 100644 ir/tv/strcalc.h diff --git a/ir/tv/Makefile.in b/ir/tv/Makefile.in index 6815cd3fb..55372b653 100644 --- a/ir/tv/Makefile.in +++ b/ir/tv/Makefile.in @@ -14,7 +14,7 @@ INSTALL_HEADERS = tv.h SOURCES = $(INSTALL_HEADERS) -SOURCES += Makefile.in ieee754.h tv.c tv_t.h +SOURCES += Makefile.in tv.c tv_t.h strcalc.c strcalc.h fltcalc.c fltcalc.h ieee754.h include $(topdir)/MakeRules diff --git a/ir/tv/fltcalc.c b/ir/tv/fltcalc.c new file mode 100644 index 000000000..c493d5569 --- /dev/null +++ b/ir/tv/fltcalc.c @@ -0,0 +1,156 @@ +/* fltcalc.c + * Authors: Matthias Heil + */ + +#include "fltcalc.h" +#include "ieee754.h" +#include +#include +#include +#include + +/******** + * globals + ********/ +static long double value; + +#define CAST_IN(val) (*((long double *)((val)))) +#define CAST_OUT(val) ((void *)&(val)) + +#define CLEAR_BUFFER() memset((char*)&value, 0, sizeof(long double)) +/******** + * private functions + ********/ + +/******** + * functions defined in fltcalc.h + ********/ +const void *fc_get_buffer(void) +{ + return CAST_OUT(value); +} + +const int fc_get_buffer_length(void) +{ + return sizeof(long double); +} + +void fc_val_from_str(const char *str, unsigned int len) +{ + CLEAR_BUFFER(); + value = strtold(str, NULL); +} + +void fc_val_from_float(long double l) +{ + CLEAR_BUFFER(); + value = l; +} + +long double fc_val_to_float(const void *val) +{ + return CAST_IN(val); +} + +void fc_get_min(unsigned int num_bits) +{ + CLEAR_BUFFER(); + switch (num_bits) + { + case 32: + value = FLT_MIN; + break; + case 64: + value = DBL_MIN; + break; + case 80: + default: + value = LDBL_MIN; + break; + } +} + +void fc_get_max(unsigned int num_bits) +{ + CLEAR_BUFFER(); + switch (num_bits) + { + case 32: + value = FLT_MAX; + break; + case 64: + value = DBL_MAX; + break; + case 80: + default: + value = LDBL_MAX; + break; + } +} + +void fc_get_nan(void) +{ + /* nan: all exponent bit set, non-zero mantissa. not signalling wheni + * msb of mantissa is set (easily found using this struct */ + union ieee854_long_double ld; + + CLEAR_BUFFER(); + ld.ieee_nan.negative = 0; + ld.ieee_nan.exponent = 0x7FFF; + ld.ieee_nan.quiet_nan = 1; + ld.ieee_nan.mantissa0 = 42; + + value = ld.d; +} + +void fc_get_inf(void) +{ + /* +-inf: all exponent bit set, sign is easy, one is strange XXX */ + union ieee854_long_double ld; + + CLEAR_BUFFER(); + ld.ieee_nan.negative = 0; + ld.ieee_nan.exponent = 0x7FFF; + ld.ieee_nan.quiet_nan = 0; + ld.ieee_nan.one = 1; + ld.ieee_nan.mantissa0 = 0; + ld.ieee_nan.mantissa1 = 0; + + value = ld.d; +} + +void fc_calc(const void *a, const void *b, int opcode) +{ + CLEAR_BUFFER(); + switch (opcode) + { + case FC_ADD: + value = CAST_IN(a) + CAST_IN(b); + break; + case FC_SUB: + value = CAST_IN(a) - CAST_IN(b); + break; + case FC_MUL: + value = CAST_IN(a) * CAST_IN(b); + break; + case FC_DIV: + value = CAST_IN(a) / CAST_IN(b); + break; + case FC_NEG: + value = -CAST_IN(a); + } +} + +int fc_comp(const void *a, const void *b) +{ + if (CAST_IN(a) == CAST_IN(b)) return 0; + else return (CAST_IN(a) > CAST_IN(b))?(1):(-1); +} + +char *fc_print_dec(const void *a) +{ + static char buf[100]; + + snprintf(buf, 100, "%1.30Lg", CAST_IN(a)); + return buf; +} diff --git a/ir/tv/fltcalc.h b/ir/tv/fltcalc.h new file mode 100644 index 000000000..5e611dc00 --- /dev/null +++ b/ir/tv/fltcalc.h @@ -0,0 +1,34 @@ +#ifndef _FLTCALC_H_ +#define _FLTCALC_H_ + +enum { + FC_ADD, + FC_SUB, + FC_MUL, + FC_DIV, + FC_NEG, +}; + +#define fc_add(a, b) fc_calc((a), (b), FC_ADD) +#define fc_sub(a, b) fc_calc((a), (b), FC_SUB) +#define fc_mul(a, b) fc_calc((a), (b), FC_MUL) +#define fc_div(a, b) fc_calc((a), (b), FC_DIV) +#define fc_neg(a) fc_calc((a), NULL, FC_NEG) + +const void *fc_get_buffer(void); +const int fc_get_buffer_length(void); + +void fc_val_from_str(const char *str, unsigned int len); +void fc_val_from_float(long double l); +long double fc_val_to_float(const void *val); + +void fc_get_min(unsigned int num_bits); +void fc_get_max(unsigned int num_bits); +void fc_get_nan(void); +void fc_get_inf(void); + +void fc_calc(const void *a, const void *b, int opcode); +char *fc_print_dec(const void *a); +int fc_comp(const void *a, const void *b); + +#endif /* _FLTCALC_H_ */ diff --git a/ir/tv/ieee754.h b/ir/tv/ieee754.h index 2bb60c79b..7131e5de6 100644 --- a/ir/tv/ieee754.h +++ b/ir/tv/ieee754.h @@ -1,47 +1,68 @@ -/* IEEE754 fp format. - Copyright (C) 1995, 1996 Christian von Roques */ - -/* $Id$ */ - -/* This file was derived from the GNU C Library's ieee754.h which - carried the following copyright notice: - -Copyright (C) 1992 Free Software Foundation, Inc. - -The GNU C Library is free software; you can redistribute it and/or -modify it under the terms of the GNU Library General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -The GNU C Library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Library General Public License for more details. - -You should have received a copy of the GNU Library General Public -License along with the GNU C Library; see the file COPYING.LIB. If -not, write to the Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - -/* @@@ This is completely non-portable! ISO/IEC DIS 9899, section - 3.5.2.1: An implementation may allocate any addressable storage - unit large enough to hold a bit-field. If enough space remains, a - bit-field that immediately follows another bit-field in a structure - shall be packed into adjacent bits of the same unit. If - insufficient space remains, whether a bit-field that does not fit - is put into the next unit or overlaps adjacent units is - implementation-defined. The order of allocation of bit-fields - within a unit (high-order to low-order or low-order to high-order) - is implementation-defined. */ - -/* Floating point definitions in ieee standard number 754 - only used in target values (/libfirm/ir/tv/tv.c). */ +/* Copyright (C) 1992, 1995, 1996, 1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + #ifndef _IEEE754_H -#define _IEEE754_H -#ifdef HAVE_CONFIG_H -# include -#endif +#define _IEEE754_H 1 +#include + +#include + +__BEGIN_DECLS + +union ieee754_float + { + float f; + + /* This is the IEEE 754 single-precision format. */ + struct + { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned int negative:1; + unsigned int exponent:8; + unsigned int mantissa:23; +#endif /* Big endian. */ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int mantissa:23; + unsigned int exponent:8; + unsigned int negative:1; +#endif /* Little endian. */ + } ieee; + + /* This format makes it easier to see if a NaN is a signalling NaN. */ + struct + { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned int negative:1; + unsigned int exponent:8; + unsigned int quiet_nan:1; + unsigned int mantissa:22; +#endif /* Big endian. */ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int mantissa:22; + unsigned int quiet_nan:1; + unsigned int exponent:8; + unsigned int negative:1; +#endif /* Little endian. */ + } ieee_nan; + }; + +#define IEEE754_FLOAT_BIAS 0x7f /* Added to exponent. */ union ieee754_double @@ -51,75 +72,128 @@ union ieee754_double /* This is the IEEE 754 double-precision format. */ struct { -#ifdef WORDS_BIGENDIAN +#if __BYTE_ORDER == __BIG_ENDIAN unsigned int negative:1; unsigned int exponent:11; + /* Together these comprise the mantissa. */ unsigned int mantissa0:20; unsigned int mantissa1:32; -#else +#endif /* Big endian. */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +# if __FLOAT_WORD_ORDER == BIG_ENDIAN + unsigned int mantissa0:20; + unsigned int exponent:11; + unsigned int negative:1; + unsigned int mantissa1:32; +# else + /* Together these comprise the mantissa. */ unsigned int mantissa1:32; unsigned int mantissa0:20; unsigned int exponent:11; unsigned int negative:1; -#endif +# endif +#endif /* Little endian. */ } ieee; + + /* This format makes it easier to see if a NaN is a signalling NaN. */ struct { -#ifdef WORDS_BIGENDIAN +#if __BYTE_ORDER == __BIG_ENDIAN unsigned int negative:1; unsigned int exponent:11; unsigned int quiet_nan:1; + /* Together these comprise the mantissa. */ unsigned int mantissa0:19; unsigned int mantissa1:32; #else +# if __FLOAT_WORD_ORDER == BIG_ENDIAN + unsigned int mantissa0:19; + unsigned int quiet_nan:1; + unsigned int exponent:11; + unsigned int negative:1; + unsigned int mantissa1:32; +# else + /* Together these comprise the mantissa. */ unsigned int mantissa1:32; unsigned int mantissa0:19; unsigned int quiet_nan:1; unsigned int exponent:11; unsigned int negative:1; +# endif #endif } ieee_nan; }; -/* bias added to exponent of ieee754_double */ -#define _IEEE754_DOUBLE_BIAS 0x3ff +#define IEEE754_DOUBLE_BIAS 0x3ff /* Added to exponent. */ -union ieee754_float +union ieee854_long_double { - float f; + long double d; - /* This is the ieee754 single-precision format. */ + /* This is the IEEE 854 double-extended-precision format. */ struct { -#ifdef WORDS_BIGENDIAN +#if __BYTE_ORDER == __BIG_ENDIAN unsigned int negative:1; - unsigned int exponent:8; - unsigned int mantissa:23; -#else - unsigned int mantissa:23; - unsigned int exponent:8; + unsigned int exponent:15; + unsigned int empty:16; + unsigned int mantissa0:32; + unsigned int mantissa1:32; +#endif +#if __BYTE_ORDER == __LITTLE_ENDIAN +# if __FLOAT_WORD_ORDER == BIG_ENDIAN + unsigned int exponent:15; + unsigned int negative:1; + unsigned int empty:16; + unsigned int mantissa0:32; + unsigned int mantissa1:32; +# else + unsigned int mantissa1:32; + unsigned int mantissa0:32; + unsigned int exponent:15; unsigned int negative:1; + unsigned int empty:16; +# endif #endif } ieee; - /* This is for extracting information about NaNs. */ + + /* This is for NaNs in the IEEE 854 double-extended-precision format. */ struct { -#ifdef WORDS_BIGENDIAN +#if __BYTE_ORDER == __BIG_ENDIAN unsigned int negative:1; - unsigned int exponent:8; + unsigned int exponent:15; + unsigned int empty:16; + unsigned int one:1; unsigned int quiet_nan:1; - unsigned int mantissa:22; -#else - unsigned int mantissa:22; + unsigned int mantissa0:30; + unsigned int mantissa1:32; +#endif +#if __BYTE_ORDER == __LITTLE_ENDIAN +# if __FLOAT_WORD_ORDER == BIG_ENDIAN + unsigned int exponent:15; + unsigned int negative:1; + unsigned int empty:16; + unsigned int mantissa0:30; unsigned int quiet_nan:1; - unsigned int exponent:8; + unsigned int one:1; + unsigned int mantissa1:32; +# else + unsigned int mantissa1:32; + unsigned int mantissa0:30; + unsigned int quiet_nan:1; + unsigned int one:1; + unsigned int exponent:15; unsigned int negative:1; + unsigned int empty:16; +# endif #endif } ieee_nan; }; -/* bias added to exponent of ieee_float */ -#define _IEEE754_FLOAT_BIAS 0x7f +#define IEEE854_LONG_DOUBLE_BIAS 0x3fff + +__END_DECLS -#endif /* _IEEE754_H */ +#endif /* ieee754.h */ diff --git a/ir/tv/strcalc.c b/ir/tv/strcalc.c new file mode 100644 index 000000000..4dd5d63c5 --- /dev/null +++ b/ir/tv/strcalc.c @@ -0,0 +1,1229 @@ +/****i* strcalc/implementation + * + * AUTHORS + * Matthias Heil + * + * NOTES + ******/ + +#include /* assertions */ +#include /* memset/memcmp */ + +#include "strcalc.h" + +#include /* output for error messages */ +#include + +/***************************************************************************** + * local definitions and macros + *****************************************************************************/ +#define BIT_PATTERN_SIZE (8 * BIGGEST_INTEGER_SIZE_IN_BYTES) +#define CALC_BUFFER_SIZE (4 * BIGGEST_INTEGER_SIZE_IN_BYTES) +#define MAX_VALUE_SIZE (2 * BIGGEST_INTEGER_SIZE_IN_BYTES) + +#define CLEAR_CALC_BUFFER() assert(calc_buffer); memset(calc_buffer, SC_0, CALC_BUFFER_SIZE) +#define _val(a) ((a)-SC_0) +#define _digit(a) ((a)+SC_0) +#define _bitisset(digit, pos) (and_table[_val(digit)][_val(shift_table[pos])] != SC_0) + +#define fail_char(a, b, c, d) _fail_char((a), (b), (c), (d), __FILE__, __LINE__) + +#if 0 +# define DEBUGPRINTF(...) printf(__VA_ARGS__) +#else +# define DEBUGPRINTF(...) ((void)0) +#endif + +/***************************************************************************** + * private variables + *****************************************************************************/ + +static char calc_buffer[CALC_BUFFER_SIZE]; /* buffer holding all results */ + +static char quot[CALC_BUFFER_SIZE]; /* temp buffer holding result of divmod */ +static char rem[CALC_BUFFER_SIZE]; /* temp buffer holding remainder of divmod */ + +static char max_digit[4] = { SC_0, SC_1, SC_3, SC_7 }; +static char min_digit[4] = { SC_F, SC_E, SC_C, SC_8 }; + +static char not_table[16] = { SC_F, SC_E, SC_D, SC_C, SC_B, SC_A, SC_9, SC_8, + SC_7, SC_6, SC_5, SC_4, SC_3, SC_2, SC_1, SC_0 }; + +static char shift_table[4] = { SC_1, SC_2, SC_4, SC_8 }; + +static char and_table[16][16] = { + { SC_0, SC_0, SC_0, SC_0, SC_0, SC_0, SC_0, SC_0, + SC_0, SC_0, SC_0, SC_0, SC_0, SC_0, SC_0, SC_0 }, + + { SC_0, SC_1, SC_0, SC_1, SC_0, SC_1, SC_0, SC_1, + SC_0, SC_1, SC_0, SC_1, SC_0, SC_1, SC_0, SC_1 }, + + { SC_0, SC_0, SC_2, SC_2, SC_0, SC_0, SC_2, SC_2, + SC_0, SC_0, SC_2, SC_2, SC_0, SC_0, SC_2, SC_2 }, + + { SC_0, SC_1, SC_2, SC_3, SC_0, SC_1, SC_2, SC_3, + SC_0, SC_1, SC_2, SC_3, SC_0, SC_1, SC_2, SC_3 }, + + { SC_0, SC_0, SC_0, SC_0, SC_4, SC_4, SC_4, SC_4, + SC_0, SC_0, SC_0, SC_0, SC_4, SC_4, SC_4, SC_4 }, + + { SC_0, SC_1, SC_0, SC_1, SC_4, SC_5, SC_4, SC_5, + SC_0, SC_1, SC_0, SC_1, SC_4, SC_5, SC_4, SC_5 }, + + { SC_0, SC_0, SC_2, SC_2, SC_4, SC_4, SC_6, SC_6, + SC_0, SC_0, SC_2, SC_2, SC_4, SC_4, SC_6, SC_6 }, + + { SC_0, SC_1, SC_2, SC_3, SC_4, SC_5, SC_6, SC_7, + SC_0, SC_1, SC_2, SC_3, SC_4, SC_5, SC_6, SC_7 }, + + { SC_0, SC_0, SC_0, SC_0, SC_0, SC_0, SC_0, SC_0, + SC_8, SC_8, SC_8, SC_8, SC_8, SC_8, SC_8, SC_8 }, + + { SC_0, SC_1, SC_0, SC_1, SC_0, SC_1, SC_0, SC_1, + SC_8, SC_9, SC_8, SC_9, SC_8, SC_9, SC_8, SC_9 }, + + { SC_0, SC_0, SC_2, SC_2, SC_0, SC_0, SC_2, SC_2, + SC_8, SC_8, SC_A, SC_A, SC_8, SC_8, SC_A, SC_A }, + + { SC_0, SC_1, SC_2, SC_3, SC_0, SC_1, SC_2, SC_3, + SC_8, SC_9, SC_A, SC_B, SC_8, SC_9, SC_A, SC_B }, + + { SC_0, SC_0, SC_0, SC_0, SC_4, SC_4, SC_4, SC_4, + SC_8, SC_8, SC_8, SC_8, SC_C, SC_C, SC_C, SC_C }, + + { SC_0, SC_1, SC_0, SC_1, SC_4, SC_5, SC_4, SC_5, + SC_8, SC_9, SC_8, SC_9, SC_D, SC_E, SC_D, SC_E }, + + { SC_0, SC_0, SC_2, SC_2, SC_4, SC_4, SC_6, SC_6, + SC_8, SC_8, SC_A, SC_A, SC_C, SC_C, SC_E, SC_E }, + + { SC_0, SC_1, SC_2, SC_3, SC_4, SC_5, SC_6, SC_7, + SC_8, SC_9, SC_A, SC_B, SC_C, SC_D, SC_E, SC_F } }; + +static char or_table[16][16] = { + { SC_0, SC_1, SC_2, SC_3, SC_4, SC_5, SC_6, SC_7, + SC_8, SC_9, SC_A, SC_B, SC_C, SC_D, SC_E, SC_F }, + + { SC_1, SC_1, SC_3, SC_3, SC_5, SC_5, SC_7, SC_7, + SC_9, SC_9, SC_B, SC_B, SC_D, SC_D, SC_F, SC_F }, + + { SC_2, SC_3, SC_2, SC_3, SC_6, SC_7, SC_6, SC_7, + SC_A, SC_B, SC_A, SC_B, SC_E, SC_F, SC_E, SC_F }, + + { SC_3, SC_3, SC_3, SC_3, SC_7, SC_7, SC_7, SC_7, + SC_B, SC_B, SC_B, SC_B, SC_F, SC_F, SC_F, SC_F }, + + { SC_4, SC_5, SC_6, SC_7, SC_4, SC_5, SC_6, SC_7, + SC_C, SC_D, SC_E, SC_F, SC_C, SC_D, SC_E, SC_F }, + + { SC_5, SC_5, SC_7, SC_7, SC_5, SC_5, SC_7, SC_7, + SC_D, SC_D, SC_F, SC_F, SC_D, SC_D, SC_F, SC_F }, + + { SC_6, SC_7, SC_6, SC_7, SC_6, SC_7, SC_6, SC_7, + SC_E, SC_F, SC_E, SC_F, SC_E, SC_F, SC_E, SC_F }, + + { SC_7, SC_7, SC_7, SC_7, SC_7, SC_7, SC_7, SC_7, + SC_F, SC_F, SC_F, SC_F, SC_F, SC_F, SC_F, SC_F }, + + { SC_8, SC_9, SC_A, SC_B, SC_C, SC_D, SC_E, SC_F, + SC_8, SC_9, SC_A, SC_B, SC_C, SC_D, SC_E, SC_F }, + + { SC_9, SC_9, SC_B, SC_B, SC_D, SC_D, SC_F, SC_F, + SC_9, SC_9, SC_B, SC_B, SC_D, SC_D, SC_F, SC_F }, + + { SC_A, SC_B, SC_A, SC_B, SC_E, SC_F, SC_E, SC_F, + SC_A, SC_B, SC_A, SC_B, SC_E, SC_F, SC_E, SC_F }, + + { SC_B, SC_B, SC_B, SC_B, SC_F, SC_F, SC_F, SC_F, + SC_B, SC_B, SC_B, SC_B, SC_F, SC_F, SC_F, SC_F }, + + { SC_C, SC_D, SC_E, SC_F, SC_C, SC_D, SC_E, SC_F, + SC_C, SC_D, SC_E, SC_F, SC_C, SC_D, SC_E, SC_F }, + + { SC_D, SC_D, SC_F, SC_F, SC_D, SC_D, SC_F, SC_F, + SC_D, SC_D, SC_F, SC_F, SC_D, SC_D, SC_F, SC_F }, + + { SC_E, SC_F, SC_E, SC_F, SC_E, SC_F, SC_E, SC_F, + SC_E, SC_F, SC_E, SC_F, SC_E, SC_F, SC_E, SC_F }, + + { SC_F, SC_F, SC_F, SC_F, SC_F, SC_F, SC_F, SC_F, + SC_F, SC_F, SC_F, SC_F, SC_F, SC_F, SC_F, SC_F } }; + +static char xor_table[16][16] = { + { SC_0, SC_1, SC_2, SC_3, SC_4, SC_5, SC_6, SC_7, + SC_8, SC_9, SC_A, SC_B, SC_C, SC_D, SC_E, SC_F }, + + { SC_1, SC_0, SC_3, SC_2, SC_5, SC_4, SC_7, SC_6, + SC_9, SC_8, SC_B, SC_A, SC_D, SC_C, SC_F, SC_E }, + + { SC_2, SC_3, SC_0, SC_1, SC_6, SC_7, SC_4, SC_5, + SC_A, SC_B, SC_8, SC_9, SC_E, SC_F, SC_C, SC_D }, + + { SC_3, SC_2, SC_1, SC_0, SC_7, SC_6, SC_5, SC_4, + SC_B, SC_A, SC_9, SC_8, SC_F, SC_E, SC_D, SC_C }, + + { SC_4, SC_5, SC_6, SC_7, SC_0, SC_1, SC_2, SC_3, + SC_C, SC_D, SC_E, SC_F, SC_8, SC_9, SC_A, SC_B }, + + { SC_5, SC_4, SC_7, SC_6, SC_1, SC_0, SC_3, SC_2, + SC_D, SC_C, SC_F, SC_E, SC_9, SC_8, SC_B, SC_A }, + + { SC_6, SC_7, SC_4, SC_5, SC_2, SC_3, SC_0, SC_1, + SC_E, SC_F, SC_C, SC_D, SC_A, SC_B, SC_8, SC_9 }, + + { SC_7, SC_6, SC_5, SC_4, SC_3, SC_2, SC_1, SC_0, + SC_F, SC_E, SC_D, SC_C, SC_B, SC_A, SC_9, SC_8 }, + + { SC_8, SC_9, SC_A, SC_B, SC_C, SC_D, SC_E, SC_F, + SC_0, SC_1, SC_2, SC_3, SC_4, SC_5, SC_6, SC_7 }, + + { SC_9, SC_8, SC_B, SC_A, SC_D, SC_C, SC_F, SC_E, + SC_1, SC_0, SC_3, SC_2, SC_5, SC_4, SC_7, SC_6 }, + + { SC_A, SC_B, SC_8, SC_9, SC_E, SC_F, SC_C, SC_D, + SC_2, SC_3, SC_0, SC_1, SC_6, SC_7, SC_4, SC_5 }, + + { SC_B, SC_A, SC_9, SC_8, SC_F, SC_E, SC_D, SC_C, + SC_3, SC_2, SC_1, SC_0, SC_7, SC_6, SC_5, SC_4 }, + + { SC_C, SC_D, SC_E, SC_F, SC_8, SC_9, SC_A, SC_B, + SC_4, SC_5, SC_6, SC_7, SC_0, SC_1, SC_2, SC_3 }, + + { SC_D, SC_C, SC_F, SC_E, SC_9, SC_8, SC_B, SC_A, + SC_5, SC_4, SC_7, SC_6, SC_1, SC_0, SC_3, SC_2 }, + + { SC_E, SC_F, SC_C, SC_D, SC_A, SC_B, SC_8, SC_9, + SC_6, SC_7, SC_4, SC_5, SC_2, SC_3, SC_0, SC_1 }, + + { SC_F, SC_E, SC_D, SC_C, SC_B, SC_A, SC_9, SC_8, + SC_7, SC_6, SC_5, SC_4, SC_3, SC_2, SC_1, SC_0 } + }; + +static char add_table[16][16][2] = { + { {SC_0, SC_0}, {SC_1, SC_0}, {SC_2, SC_0}, {SC_3, SC_0}, + {SC_4, SC_0}, {SC_5, SC_0}, {SC_6, SC_0}, {SC_7, SC_0}, + {SC_8, SC_0}, {SC_9, SC_0}, {SC_A, SC_0}, {SC_B, SC_0}, + {SC_C, SC_0}, {SC_D, SC_0}, {SC_E, SC_0}, {SC_F, SC_0} }, + + { {SC_1, SC_0}, {SC_2, SC_0}, {SC_3, SC_0}, {SC_4, SC_0}, + {SC_5, SC_0}, {SC_6, SC_0}, {SC_7, SC_0}, {SC_8, SC_0}, + {SC_9, SC_0}, {SC_A, SC_0}, {SC_B, SC_0}, {SC_C, SC_0}, + {SC_D, SC_0}, {SC_E, SC_0}, {SC_F, SC_0}, {SC_0, SC_1} }, + + { {SC_2, SC_0}, {SC_3, SC_0}, {SC_4, SC_0}, {SC_5, SC_0}, + {SC_6, SC_0}, {SC_7, SC_0}, {SC_8, SC_0}, {SC_9, SC_0}, + {SC_A, SC_0}, {SC_B, SC_0}, {SC_C, SC_0}, {SC_D, SC_0}, + {SC_E, SC_0}, {SC_F, SC_0}, {SC_0, SC_1}, {SC_1, SC_1} }, + + { {SC_3, SC_0}, {SC_4, SC_0}, {SC_5, SC_0}, {SC_6, SC_0}, + {SC_7, SC_0}, {SC_8, SC_0}, {SC_9, SC_0}, {SC_A, SC_0}, + {SC_B, SC_0}, {SC_C, SC_0}, {SC_D, SC_0}, {SC_E, SC_0}, + {SC_F, SC_0}, {SC_0, SC_1}, {SC_1, SC_1}, {SC_2, SC_1} }, + + { {SC_4, SC_0}, {SC_5, SC_0}, {SC_6, SC_0}, {SC_7, SC_0}, + {SC_8, SC_0}, {SC_9, SC_0}, {SC_A, SC_0}, {SC_B, SC_0}, + {SC_C, SC_0}, {SC_D, SC_0}, {SC_E, SC_0}, {SC_F, SC_0}, + {SC_0, SC_1}, {SC_1, SC_1}, {SC_2, SC_1}, {SC_3, SC_1} }, + + { {SC_5, SC_0}, {SC_6, SC_0}, {SC_7, SC_0}, {SC_8, SC_0}, + {SC_9, SC_0}, {SC_A, SC_0}, {SC_B, SC_0}, {SC_C, SC_0}, + {SC_D, SC_0}, {SC_E, SC_0}, {SC_F, SC_0}, {SC_0, SC_1}, + {SC_1, SC_1}, {SC_2, SC_1}, {SC_3, SC_1}, {SC_4, SC_1} }, + + { {SC_6, SC_0}, {SC_7, SC_0}, {SC_8, SC_0}, {SC_9, SC_0}, + {SC_A, SC_0}, {SC_B, SC_0}, {SC_C, SC_0}, {SC_D, SC_0}, + {SC_E, SC_0}, {SC_F, SC_0}, {SC_0, SC_1}, {SC_1, SC_1}, + {SC_2, SC_1}, {SC_3, SC_1}, {SC_4, SC_1}, {SC_5, SC_1} }, + + { {SC_7, SC_0}, {SC_8, SC_0}, {SC_9, SC_0}, {SC_A, SC_0}, + {SC_B, SC_0}, {SC_C, SC_0}, {SC_D, SC_0}, {SC_E, SC_0}, + {SC_F, SC_0}, {SC_0, SC_1}, {SC_1, SC_1}, {SC_2, SC_1}, + {SC_3, SC_1}, {SC_4, SC_1}, {SC_5, SC_1}, {SC_6, SC_1} }, + + { {SC_8, SC_0}, {SC_9, SC_0}, {SC_A, SC_0}, {SC_B, SC_0}, + {SC_C, SC_0}, {SC_D, SC_0}, {SC_E, SC_0}, {SC_F, SC_0}, + {SC_0, SC_1}, {SC_1, SC_1}, {SC_2, SC_1}, {SC_3, SC_1}, + {SC_4, SC_1}, {SC_5, SC_1}, {SC_6, SC_1}, {SC_7, SC_1} }, + + { {SC_9, SC_0}, {SC_A, SC_0}, {SC_B, SC_0}, {SC_C, SC_0}, + {SC_D, SC_0}, {SC_E, SC_0}, {SC_F, SC_0}, {SC_0, SC_1}, + {SC_1, SC_1}, {SC_2, SC_1}, {SC_3, SC_1}, {SC_4, SC_1}, + {SC_5, SC_1}, {SC_6, SC_1}, {SC_7, SC_1}, {SC_8, SC_1} }, + + { {SC_A, SC_0}, {SC_B, SC_0}, {SC_C, SC_0}, {SC_D, SC_0}, + {SC_E, SC_0}, {SC_F, SC_0}, {SC_0, SC_1}, {SC_1, SC_1}, + {SC_2, SC_1}, {SC_3, SC_1}, {SC_4, SC_1}, {SC_5, SC_1}, + {SC_6, SC_1}, {SC_7, SC_1}, {SC_8, SC_1}, {SC_9, SC_1} }, + + { {SC_B, SC_0}, {SC_C, SC_0}, {SC_D, SC_0}, {SC_E, SC_0}, + {SC_F, SC_0}, {SC_0, SC_1}, {SC_1, SC_1}, {SC_2, SC_1}, + {SC_3, SC_1}, {SC_4, SC_1}, {SC_5, SC_1}, {SC_6, SC_1}, + {SC_7, SC_1}, {SC_8, SC_1}, {SC_9, SC_1}, {SC_A, SC_1} }, + + { {SC_C, SC_0}, {SC_D, SC_0}, {SC_E, SC_0}, {SC_F, SC_0}, + {SC_0, SC_1}, {SC_1, SC_1}, {SC_2, SC_1}, {SC_3, SC_1}, + {SC_4, SC_1}, {SC_5, SC_1}, {SC_6, SC_1}, {SC_7, SC_1}, + {SC_8, SC_1}, {SC_9, SC_1}, {SC_A, SC_1}, {SC_B, SC_1} }, + + { {SC_D, SC_0}, {SC_E, SC_0}, {SC_F, SC_0}, {SC_0, SC_1}, + {SC_1, SC_1}, {SC_2, SC_1}, {SC_3, SC_1}, {SC_4, SC_1}, + {SC_5, SC_1}, {SC_6, SC_1}, {SC_7, SC_1}, {SC_8, SC_1}, + {SC_9, SC_1}, {SC_A, SC_1}, {SC_B, SC_1}, {SC_C, SC_1} }, + + { {SC_E, SC_0}, {SC_F, SC_0}, {SC_0, SC_1}, {SC_1, SC_1}, + {SC_2, SC_1}, {SC_3, SC_1}, {SC_4, SC_1}, {SC_5, SC_1}, + {SC_6, SC_1}, {SC_7, SC_1}, {SC_8, SC_1}, {SC_9, SC_1}, + {SC_A, SC_1}, {SC_B, SC_1}, {SC_C, SC_1}, {SC_D, SC_1} }, + + { {SC_F, SC_0}, {SC_0, SC_1}, {SC_1, SC_1}, {SC_2, SC_1}, + {SC_3, SC_1}, {SC_4, SC_1}, {SC_5, SC_1}, {SC_6, SC_1}, + {SC_7, SC_1}, {SC_8, SC_1}, {SC_9, SC_1}, {SC_A, SC_1}, + {SC_B, SC_1}, {SC_C, SC_1}, {SC_D, SC_1}, {SC_E, SC_1} } + }; + +static char mul_table[16][16][2] = { + { {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0}, + {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0}, + {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0}, + {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0} }, + + { {SC_0, SC_0}, {SC_1, SC_0}, {SC_2, SC_0}, {SC_3, SC_0}, + {SC_4, SC_0}, {SC_5, SC_0}, {SC_6, SC_0}, {SC_7, SC_0}, + {SC_8, SC_0}, {SC_9, SC_0}, {SC_A, SC_0}, {SC_B, SC_0}, + {SC_C, SC_0}, {SC_D, SC_0}, {SC_E, SC_0}, {SC_F, SC_0} }, + + { {SC_0, SC_0}, {SC_2, SC_0}, {SC_4, SC_0}, {SC_6, SC_0}, + {SC_8, SC_0}, {SC_A, SC_0}, {SC_C, SC_0}, {SC_E, SC_0}, + {SC_0, SC_1}, {SC_2, SC_1}, {SC_4, SC_1}, {SC_6, SC_1}, + {SC_8, SC_1}, {SC_A, SC_1}, {SC_C, SC_1}, {SC_E, SC_1} }, + + { {SC_0, SC_0}, {SC_3, SC_0}, {SC_6, SC_0}, {SC_9, SC_0}, + {SC_C, SC_0}, {SC_F, SC_0}, {SC_2, SC_1}, {SC_5, SC_1}, + {SC_8, SC_1}, {SC_B, SC_1}, {SC_E, SC_1}, {SC_1, SC_2}, + {SC_4, SC_2}, {SC_7, SC_2}, {SC_A, SC_2}, {SC_D, SC_2} }, + + { {SC_0, SC_0}, {SC_4, SC_0}, {SC_8, SC_0}, {SC_C, SC_0}, + {SC_0, SC_1}, {SC_4, SC_1}, {SC_8, SC_1}, {SC_C, SC_1}, + {SC_0, SC_2}, {SC_4, SC_2}, {SC_8, SC_2}, {SC_C, SC_2}, + {SC_0, SC_3}, {SC_4, SC_3}, {SC_8, SC_3}, {SC_C, SC_3} }, + + { {SC_0, SC_0}, {SC_5, SC_0}, {SC_A, SC_0}, {SC_F, SC_0}, + {SC_4, SC_1}, {SC_9, SC_1}, {SC_E, SC_1}, {SC_3, SC_2}, + {SC_8, SC_2}, {SC_D, SC_2}, {SC_2, SC_3}, {SC_7, SC_3}, + {SC_C, SC_3}, {SC_1, SC_4}, {SC_6, SC_4}, {SC_B, SC_4} }, + + { {SC_0, SC_0}, {SC_6, SC_0}, {SC_C, SC_0}, {SC_2, SC_1}, + {SC_8, SC_1}, {SC_E, SC_1}, {SC_4, SC_2}, {SC_A, SC_2}, + {SC_0, SC_3}, {SC_6, SC_3}, {SC_C, SC_3}, {SC_2, SC_4}, + {SC_8, SC_4}, {SC_E, SC_4}, {SC_4, SC_5}, {SC_A, SC_5} }, + + { {SC_0, SC_0}, {SC_7, SC_0}, {SC_E, SC_0}, {SC_5, SC_1}, + {SC_C, SC_1}, {SC_3, SC_2}, {SC_A, SC_2}, {SC_1, SC_3}, + {SC_8, SC_3}, {SC_F, SC_3}, {SC_6, SC_4}, {SC_D, SC_4}, + {SC_4, SC_5}, {SC_B, SC_5}, {SC_2, SC_6}, {SC_9, SC_6} }, + + { {SC_0, SC_0}, {SC_8, SC_0}, {SC_0, SC_1}, {SC_8, SC_1}, + {SC_0, SC_2}, {SC_8, SC_2}, {SC_0, SC_3}, {SC_8, SC_3}, + {SC_0, SC_4}, {SC_8, SC_4}, {SC_0, SC_5}, {SC_8, SC_5}, + {SC_0, SC_6}, {SC_8, SC_6}, {SC_0, SC_7}, {SC_8, SC_7} }, + + { {SC_0, SC_0}, {SC_9, SC_0}, {SC_2, SC_1}, {SC_B, SC_1}, + {SC_4, SC_2}, {SC_D, SC_2}, {SC_6, SC_3}, {SC_F, SC_3}, + {SC_8, SC_4}, {SC_1, SC_5}, {SC_A, SC_5}, {SC_3, SC_6}, + {SC_C, SC_6}, {SC_5, SC_7}, {SC_E, SC_7}, {SC_7, SC_8} }, + + { {SC_0, SC_0}, {SC_A, SC_0}, {SC_4, SC_1}, {SC_E, SC_1}, + {SC_8, SC_2}, {SC_2, SC_3}, {SC_C, SC_3}, {SC_6, SC_4}, + {SC_0, SC_5}, {SC_A, SC_5}, {SC_4, SC_6}, {SC_E, SC_6}, + {SC_8, SC_7}, {SC_2, SC_8}, {SC_C, SC_8}, {SC_6, SC_9} }, + + { {SC_0, SC_0}, {SC_B, SC_0}, {SC_6, SC_1}, {SC_1, SC_2}, + {SC_C, SC_2}, {SC_7, SC_3}, {SC_2, SC_4}, {SC_D, SC_4}, + {SC_8, SC_5}, {SC_3, SC_6}, {SC_E, SC_6}, {SC_9, SC_7}, + {SC_4, SC_8}, {SC_F, SC_8}, {SC_A, SC_9}, {SC_5, SC_A} }, + + { {SC_0, SC_0}, {SC_C, SC_0}, {SC_8, SC_1}, {SC_4, SC_2}, + {SC_0, SC_3}, {SC_C, SC_3}, {SC_8, SC_4}, {SC_4, SC_5}, + {SC_0, SC_6}, {SC_C, SC_6}, {SC_8, SC_7}, {SC_4, SC_8}, + {SC_0, SC_9}, {SC_C, SC_9}, {SC_8, SC_A}, {SC_4, SC_B} }, + + { {SC_0, SC_0}, {SC_D, SC_0}, {SC_A, SC_1}, {SC_7, SC_2}, + {SC_4, SC_3}, {SC_1, SC_4}, {SC_E, SC_4}, {SC_B, SC_5}, + {SC_8, SC_6}, {SC_5, SC_7}, {SC_2, SC_8}, {SC_F, SC_8}, + {SC_C, SC_9}, {SC_9, SC_A}, {SC_6, SC_B}, {SC_3, SC_C} }, + + { {SC_0, SC_0}, {SC_E, SC_0}, {SC_C, SC_1}, {SC_A, SC_2}, + {SC_8, SC_3}, {SC_6, SC_4}, {SC_4, SC_5}, {SC_2, SC_6}, + {SC_0, SC_7}, {SC_E, SC_7}, {SC_C, SC_8}, {SC_A, SC_9}, + {SC_8, SC_A}, {SC_6, SC_B}, {SC_4, SC_C}, {SC_2, SC_D} }, + + { {SC_0, SC_0}, {SC_F, SC_0}, {SC_E, SC_1}, {SC_D, SC_2}, + {SC_C, SC_3}, {SC_B, SC_4}, {SC_A, SC_5}, {SC_9, SC_6}, + {SC_8, SC_7}, {SC_7, SC_8}, {SC_6, SC_9}, {SC_5, SC_A}, + {SC_4, SC_B}, {SC_3, SC_C}, {SC_2, SC_D}, {SC_1, SC_E} } + }; + +static char shrs_table[16][4][2] = { + { {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0}, {SC_0, SC_0} }, + { {SC_1, SC_0}, {SC_0, SC_8}, {SC_0, SC_4}, {SC_0, SC_2} }, + { {SC_2, SC_0}, {SC_1, SC_0}, {SC_0, SC_8}, {SC_0, SC_4} }, + { {SC_3, SC_0}, {SC_1, SC_8}, {SC_0, SC_C}, {SC_0, SC_6} }, + { {SC_4, SC_0}, {SC_2, SC_0}, {SC_1, SC_0}, {SC_0, SC_8} }, + { {SC_5, SC_0}, {SC_2, SC_8}, {SC_1, SC_4}, {SC_0, SC_A} }, + { {SC_6, SC_0}, {SC_3, SC_0}, {SC_1, SC_8}, {SC_0, SC_C} }, + { {SC_7, SC_0}, {SC_3, SC_8}, {SC_1, SC_C}, {SC_0, SC_E} }, + { {SC_8, SC_0}, {SC_4, SC_0}, {SC_2, SC_0}, {SC_1, SC_0} }, + { {SC_9, SC_0}, {SC_4, SC_8}, {SC_2, SC_4}, {SC_1, SC_2} }, + { {SC_A, SC_0}, {SC_5, SC_0}, {SC_2, SC_8}, {SC_1, SC_4} }, + { {SC_B, SC_0}, {SC_5, SC_8}, {SC_2, SC_C}, {SC_1, SC_6} }, + { {SC_C, SC_0}, {SC_6, SC_0}, {SC_3, SC_0}, {SC_1, SC_8} }, + { {SC_D, SC_0}, {SC_6, SC_8}, {SC_3, SC_4}, {SC_1, SC_A} }, + { {SC_E, SC_0}, {SC_7, SC_0}, {SC_3, SC_8}, {SC_1, SC_C} }, + { {SC_F, SC_0}, {SC_7, SC_8}, {SC_3, SC_C}, {SC_1, SC_E} } + }; +/***************************************************************************** + * private functions + *****************************************************************************/ +static void _fail_char(const char *str, size_t len, const char fchar, int pos, + const char *file, int line) +{ + printf("ERROR:\n"); + printf("Unexpected character '%c' in %s:%d\n", fchar, file, line); + while (len-- && *str) printf("%c", *str++); printf("\n"); + while (--pos) printf(" "); printf("^\n"); + exit(-1); +} + +static void _bitnot(const char *val, char *buffer) +{ + int counter; + + for (counter = 0; counter= 0; counter--) + { + buffer[counter+1] = buffer[counter]; + } + buffer[0] = digit; +} + +/* XXX: This is MOST slow */ +static void _divmod(const char *dividend, const char *divisor) +{ + const char *minus_divisor; + static char neg_val1[CALC_BUFFER_SIZE]; + static char neg_val2[CALC_BUFFER_SIZE]; + + char sign = 0; /* remember result sign */ + + int c_dividend; /* loop counters */ + + /* clear result buffer */ + memset(quot, SC_0, CALC_BUFFER_SIZE); + memset(rem, SC_0, CALC_BUFFER_SIZE); + /* if the dividend is zero result is zero (quot is zero)*/ + if (sc_comp(dividend, quot) == 0) return; + /* if the divisor is zero this won't work (quot is zero) */ + if (sc_comp(divisor, quot) == 0) assert(0 && "quotision by zero!"); + + if (_sign(dividend) == -1) + { + _negate(dividend, neg_val1); + sign ^= 1; + dividend = neg_val1; + } + + _negate(divisor, neg_val2); + if (_sign(divisor) == -1) + { + sign ^= 1; + minus_divisor = divisor; + divisor = neg_val2; + } + else + { + minus_divisor = neg_val2; + } + + /* if divisor >= dividend quotision is easy + * (remember these are absolute values) */ + switch (sc_comp(dividend, divisor)) + { + case 0: /* dividend == divisor */ + quot[0] = SC_1; + return; + + case -1: /* dividend < divisor */ + memcpy(rem, dividend, CALC_BUFFER_SIZE); + return; + + default: /* unluckily quotision is necessary :( */ + break; + } + + for (c_dividend = MAX_VALUE_SIZE - 1; c_dividend >= 0; c_dividend--) + { + _push(dividend[c_dividend], rem); + _push(SC_0, quot); + + if (sc_comp(rem, divisor) != -1) /* remainder >= divisor */ + { + /* subtract until the remainder becomes negative, this should + * be faster than comparing remainder with divisor */ + _add(rem, minus_divisor, rem); + + while (_sign(rem) == 1) + { + quot[0] = add_table[_val(quot[0])][SC_1][0]; + _add(rem, minus_divisor, rem); + } + + /* subtracted one too much */ + _add(rem, divisor, rem); + } + } + + if (sign) + { + _negate(quot, quot); + _negate(rem, rem); + } +} + +static void _shl(const char *val1, const char *val2, char *buffer, unsigned radius, unsigned is_signed) +{ + char *shl; + char shift; + char carry = SC_0; + + int counter; + int offset = 0; + int bitoffset = 0; + + assert((_sign(val2) != -1) || (0 && "negative leftshift")); + 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")); + + /* the whole value must be moved left the number of bytes represented + * by the value in quot, with bytes to the right set to zero */ + /*XXX This might result in trouble */ + for (counter = MAX_VALUE_SIZE - 1; counter >= 0; counter--) + { + offset = (offset << 4) | (_val(val2[counter])); + } + + shift = shift_table[_val(offset%4)]; /* this is 2 ** (val2 % 4) */ + + /* if shifting far enough the result is zero */ + if (offset >= radius) + { + memset(buffer, SC_0, CALC_BUFFER_SIZE); + return; + } + offset = offset / 4; + + /* shift the single digits some bytes (offset) and some bits (table) + * to the left */ + for (counter = 0; counter < CALC_BUFFER_SIZE - offset; counter++) + { + shl = mul_table[_val(val1[counter])][_val(shift)]; + buffer[counter + offset] = or_table[_val(shl[0])][_val(carry)]; + carry = shl[1]; + } + + /* fill with zeroes */ + for (counter = 0; counter < offset; counter++) buffer[counter] = 0; + /* if the mode was signed, change sign when the mode's msb is now 1 */ + offset = (radius - 1) / 4; + bitoffset = (radius - 1) % 4; + if (is_signed && _bitisset(buffer[offset], bitoffset) && (_sign(buffer) == 1)) + { + /* this sets the upper bits of the leftmost digit */ + buffer[offset] = or_table[_val(buffer[offset])][_val(min_digit[bitoffset])]; + for (counter = offset+1; counter < CALC_BUFFER_SIZE; counter++) + { + buffer[counter] = SC_F; + } + } + else if (is_signed && !_bitisset(buffer[offset], bitoffset) && (_sign(buffer) == -1)) + { + /* this unsets the upper bits of the leftmost digit */ + buffer[offset] = and_table[_val(buffer[offset])][_val(max_digit[bitoffset])]; + /* zero the upper part of the value */ + for (counter = offset+1; counter < CALC_BUFFER_SIZE; counter++) + { + buffer[counter] = SC_0; + } + } +} + +static void _shr(const char *val1, const char *val2, char *buffer, unsigned radius, unsigned is_signed, int signed_shift) +{ + char *shrs; + char sign; + char msd; + + int shift; + + int counter; + int offset = 0; + int bitoffset = 0; + + assert((_sign(val2) != -1) || (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")); + + /*XXX get the value of val2, this might result in trouble * + * (but who wants shifts THAT far anyway) */ + for (counter = MAX_VALUE_SIZE - 1; counter >= 0; counter--) + { + offset = (offset << 4) | (_val(val2[counter])); + } + + shift = offset % 4; /* this is val2 % 4 */ + + sign = ((signed_shift) && (_sign(val1) == -1))?(SC_F):(SC_0); + /* if shifting far enough the result is either 0 or -1 */ + if (offset >= radius) + { + memset(buffer, sign, CALC_BUFFER_SIZE); + return; + } + offset = offset / 4; + + buffer[0] = shrs_table[_val(val1[offset])][shift][0]; + /* shift digits to the right with offset, carry and all */ + for (counter = 1; counter < radius/4; counter++) + { + shrs = shrs_table[_val(val1[counter + offset])][shift]; + buffer[counter] = shrs[0]; + buffer[counter-1] = or_table[_val(buffer[counter-1])][_val(shrs[1])]; + } + + /* the last digit is special in regard of signed/unsigned shift */ + /* counter = radius/4 (after for loop) */ + bitoffset = radius%4; + msd = val1[counter]; /* most significant digit */ + + /* remove sign bits if mode was signed and this is an unsigned shift */ + if (!signed_shift && is_signed) { + msd = and_table[_val(msd)][_val(max_digit[bitoffset])]; + } + + shrs = shrs_table[_val(msd)][shift]; + + /* signed shift and signed mode and negative value means all bits to the left are set */ + if (signed_shift && is_signed && (_sign(val1) == -1)) { + buffer[counter] = or_table[_val(shrs[0])][_val(min_digit[bitoffset])]; + } else { + buffer[counter] = shrs[0]; + } + buffer[counter - 1] = or_table[_val(buffer[counter-1])][_val(shrs[1])]; + + /* fill with SC_F or SC_0 depending on sign */ + for (counter++; counter < CALC_BUFFER_SIZE; counter++) + { + buffer[counter] = sign; + } +} + +/* positive: low-order -> high order, negative other direction */ +static void _rot(const char *val1, const char *val2, char *buffer, unsigned radius, unsigned is_signed) +{ + static char temp_buffer[CALC_BUFFER_SIZE]; + + char *shl; + char carry = SC_0; + + int counter, old_counter; + int shift; + int offset = 0; + int bitoffset; + + /*XXX get the value of val2, this might result in trouble * + * (but who wants shifts THAT far anyway) */ + for (counter = MAX_VALUE_SIZE - 1; counter >= 0; counter--) + { + offset = (offset << 4) | (_val(val2[counter])); + } + /* rotation by multiples of the typelength is identity */ + offset = offset % radius; + if (offset == 0) { + memmove(buffer, val1, CALC_BUFFER_SIZE); + return; + } + /* rotation to the right is the same as rotation to the left + * when done by the right amount */ + if (offset < 0) offset = radius + offset; + + shift = _val(shift_table[offset % 4]); + offset = offset / 4; + + DEBUGPRINTF("offset: %d, shift: %d\n", offset, shift); + for (counter = 0; counter < radius/4 - offset; counter++) + { + shl = mul_table[_val(val1[counter])][_val(shift)]; + temp_buffer[counter + offset] = or_table[_val(shl[0])][_val(carry)]; + carry = shl[1]; + DEBUGPRINTF("%d(%x): %s\n", counter, shl[0], sc_print_hex(temp_buffer)); + } + old_counter = counter; + for (; counter < radius/4; counter++) + { + shl = mul_table[_val(val1[counter])][_val(shift)]; + temp_buffer[counter - old_counter] = or_table[_val(shl[0])][_val(carry)]; + carry = shl[1]; + DEBUGPRINTF("%d(%x)> %s\n", counter, shl[0], sc_print_hex(temp_buffer)); + } + temp_buffer[counter - old_counter] = or_table[_val(temp_buffer[counter-old_counter])][_val(carry)]; + + offset = (radius-1)/4; + bitoffset - (radius-1)%4; + /* fill the rest of the buffer depending on msb and mode signedness*/ + if (is_signed && _bitisset(temp_buffer[offset], bitoffset)) + { + + } + else + { + + } + + memcpy(buffer, temp_buffer, CALC_BUFFER_SIZE); +} + +/***************************************************************************** + * public functions, declared in strcalc.h + *****************************************************************************/ +const void *sc_get_buffer(void) +{ + return (void*)calc_buffer; +} + +const int sc_get_buffer_length(void) +{ + return CALC_BUFFER_SIZE; +} + +void sc_val_from_str(const char *str, unsigned int len) +{ + const char *orig_str = str; + unsigned int orig_len = len; + + char sign = 0; + static char base[CALC_BUFFER_SIZE]; + static char val[CALC_BUFFER_SIZE]; + + /* verify valid pointers (not null) */ + assert(str); + /* a string no characters long is an error */ + assert(len); + + CLEAR_CALC_BUFFER(); + memset(base, SC_0, CALC_BUFFER_SIZE); + memset(val, SC_0, CALC_BUFFER_SIZE); + + /* 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 */ + _mul(base, calc_buffer, calc_buffer); /* multiply current value with base */ + _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) + { + _negate(calc_buffer, calc_buffer); + } +} + +void sc_val_from_long(long value) +{ + char *pos; + int sign; + + pos = calc_buffer; + sign = (value < 0); + + /* FIXME MININT won't work */ + if (sign) value = -value; + + CLEAR_CALC_BUFFER(); + + while ((value != 0) && (pos < calc_buffer + CALC_BUFFER_SIZE)) + { + *pos++ = _digit(value % 16); + value /= 16; + } + + if (sign) _negate(calc_buffer, calc_buffer); +} + +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) +{ + char* pos; + int i, bits; + + CLEAR_CALC_BUFFER(); + if (!sign) return; /* unsigned means minimum is 0(zero) */ + + pos = calc_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) +{ + char* pos; + int i, bits; + + CLEAR_CALC_BUFFER(); + pos = calc_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_calc(const void* value1, const void* value2, unsigned op) +{ + const char *val1 = (char *)value1; + const char *val2 = (char *)value2; + CLEAR_CALC_BUFFER(); + + DEBUGPRINTF("%s ", sc_print(value1, SC_HEX)); + + switch (op) + { + case SC_NEG: + _negate(val1, calc_buffer); + DEBUGPRINTF("negated: %s\n", sc_print(calc_buffer, SC_HEX)); + return; + case SC_OR: + DEBUGPRINTF("| "); + _bitor(val1, val2, calc_buffer); + break; + case SC_AND: + DEBUGPRINTF("& "); + _bitand(val1, val2, calc_buffer); + break; + case SC_XOR: + DEBUGPRINTF("^ "); + _bitxor(val1, val2, calc_buffer); + break; + case SC_NOT: + _bitnot(val1, calc_buffer); + DEBUGPRINTF("bit-negated: %s\n", sc_print(calc_buffer, SC_HEX)); + return; + case SC_ADD: + DEBUGPRINTF("+ "); + _add(val1, val2, calc_buffer); + break; + case SC_SUB: + DEBUGPRINTF("- "); + _sub(val1, val2, calc_buffer); + break; + case SC_MUL: + DEBUGPRINTF("* "); + _mul(val1, val2, calc_buffer); + break; + case SC_DIV: + DEBUGPRINTF("/ "); + _divmod(val1, val2); + memcpy(calc_buffer, quot, CALC_BUFFER_SIZE); + break; + case SC_MOD: + DEBUGPRINTF("%% "); + _divmod(val1, val2); + memcpy(calc_buffer, rem, CALC_BUFFER_SIZE); + break; + default: + assert(0); + } + DEBUGPRINTF("%s -> ", sc_print(value2, SC_HEX)); + DEBUGPRINTF("%s\n", sc_print(calc_buffer, SC_HEX)); +} +void sc_bitcalc(const void* value1, const void* value2, unsigned radius, unsigned sign, unsigned op) +{ + const char *val1 = (char *)value1; + const char *val2 = (char *)value2; + CLEAR_CALC_BUFFER(); + + DEBUGPRINTF("%s ", sc_print(value1, SC_HEX)); + switch (op) + { + case SC_SHL: + DEBUGPRINTF("<< "); + _shl(val1, val2, calc_buffer, radius, sign); + break; + case SC_SHR: + DEBUGPRINTF(">> "); + _shr(val1, val2, calc_buffer, radius, sign, 0); + break; + case SC_SHRS: + DEBUGPRINTF(">>> "); + _shr(val1, val2, calc_buffer, radius, sign, 1); + break; + case SC_ROT: + DEBUGPRINTF("<<>> "); + _rot(val1, val2, calc_buffer, radius, sign); + break; + default: + assert(0); + } + DEBUGPRINTF("%s -> ", sc_print(value2, SC_HEX)); + DEBUGPRINTF("%s\n", sc_print(calc_buffer, SC_HEX)); +} + +int sc_comp(const void* value1, const void* value2) +{ + int counter = CALC_BUFFER_SIZE - 1; + const char *val1 = (char *)value1; + const char *val2 = (char *)value2; + + /* compare signs first: + * the loop below can only compare values of the same sign! */ + if (_sign(val1) != _sign(val2)) return (_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); +} + +char *sc_print(const void *value, unsigned base) +{ + int counter; + + const char *val = (char*)value; + char *pos; + static char *buf = NULL; + + if (buf != NULL) free(buf); + buf = malloc(BIT_PATTERN_SIZE); + + pos = buf + BIT_PATTERN_SIZE - 1; + *pos = '\0'; + + switch (base) + { + case SC_HEX: + for (counter = 0; counter < MAX_VALUE_SIZE; counter++) + { + if (val[counter] < SC_A) + *(--pos) = val[counter] + '0'; + else + *(--pos) = val[counter] + 'a' - 10; + } + break; + + default: + assert(0); + } + return pos; +} diff --git a/ir/tv/strcalc.h b/ir/tv/strcalc.h new file mode 100644 index 000000000..0309861b3 --- /dev/null +++ b/ir/tv/strcalc.h @@ -0,0 +1,110 @@ + /****h* tools/strcalc + * + * NAME + * strcalc -- calculations using strings + * Provides basic mathematical operations on values represented as strings + * + * AUTHORS + * Matthias Heil + * + * DESCRIPTION + * The module uses a string to represent values, and provides operations + * to perform calculations with these values. + * Results are stored in an internal buffer, so you have to make a copy + * of them if you need to store the result. + * + ******/ + +#ifndef _STRCALC_H_ +#define _STRCALC_H_ + +#define BIGGEST_INTEGER_SIZE_IN_BYTES 8 +#define SCDEBUG + +/***************************************************************************** + * typedefs, enums and structs + *****************************************************************************/ +enum { + SC_0 = 0, + SC_1, + SC_2, + SC_3, + SC_4, + SC_5, + SC_6, + SC_7, + SC_8, + SC_9, + SC_A, + SC_B, + SC_C, + SC_D, + SC_E, + SC_F, +}; + +enum { + SC_ADD = 0, + SC_SUB, + SC_NEG, + SC_MUL, + SC_DIV, + SC_MOD, + SC_SHL, + SC_SHR, + SC_SHRS, + SC_ROT, + SC_AND, + SC_OR, + SC_NOT, + SC_XOR, +}; + +enum { + SC_HEX, + SC_DEC, + SC_OKT, + SC_BIN, +}; + +/***************************************************************************** + * definitions and macros + *****************************************************************************/ +#define sc_add(a, b) sc_calc((a), (b), SC_ADD) +#define sc_sub(a, b) sc_calc((a), (b), SC_SUB) +#define sc_neg(a) sc_calc((a), NULL, SC_NEG) +#define sc_and(a, b) sc_calc((a), (b), SC_AND) +#define sc_or(a, b) sc_calc((a), (b), SC_OR) +#define sc_xor(a, b) sc_calc((a), (b), SC_XOR) +#define sc_not(a) sc_calc((a), NULL, SC_NOT) +#define sc_mul(a, b) sc_calc((a), (b), SC_MUL) +#define sc_div(a, b) sc_calc((a), (b), SC_DIV) +#define sc_mod(a, b) sc_calc((a), (b), SC_MOD) +#define sc_shl(a, b, c, d) sc_bitcalc((a), (b), (c), (d), SC_SHL) +#define sc_shr(a, b, c, d) sc_bitcalc((a), (b), (c), (d), SC_SHR) +#define sc_shrs(a, b, c, d) sc_bitcalc((a), (b), (c), (d), SC_SHRS) +#define sc_rot(a, b, c, d) sc_bitcalc((a), (b), (c), (d), SC_ROT) + +#define sc_print_hex(a) sc_print((a), SC_HEX) +#define sc_print_dec(a) sc_print((a), SC_DEC) +#define sc_print_okt(a) sc_print((a), SC_OKT) +#define sc_print_bin(a) sc_print((a), SC_BIN) +/***************************************************************************** + * function declarations + *****************************************************************************/ +const void *sc_get_buffer(void); +const int sc_get_buffer_length(void); + +void sc_val_from_str(const char *str, unsigned int len); +void sc_val_from_long(long l); +long sc_val_to_long(const void *val); +void sc_min_from_bits(unsigned int num_bits, unsigned int sign); +void sc_max_from_bits(unsigned int num_bits, unsigned int sign); + +void sc_calc(const void *val1, const void *val2, unsigned op); +void sc_bitcalc(const void *val1, const void *val2, unsigned radius, unsigned sign, unsigned op); +int sc_comp(const void *val1, const void *val2); + +char* sc_print(const void *val1, unsigned base); + +#endif /* _STRCALC_H_ */ diff --git a/ir/tv/tv.c b/ir/tv/tv.c index 38d248b39..b8b3ceaee 100644 --- a/ir/tv/tv.c +++ b/ir/tv/tv.c @@ -3,1443 +3,965 @@ /* $Id$ */ +/****i* tv/implementation + * + * AUTHORS + * Christian von Roques + * Matthias Heil + * + * NOTES + * Internal storage for tarvals, 1st draft: + * Integers as well as pointers are stored in a hex formatted string holding + * 16 characters. Booleans are not stored as there are only two of them. + * + * Floats are just reinterpreted as byte strings, because I am not sure if + * there is loss if I convert float to long double and back and furthermore + * the implementation of a fully ieee compatible floating point emulation + * is not sensible for now + * With this information it is easy to decide the kind of stored value: + * Integers have size 16, floats 4, doubles 8, long doubles 12. + ******/ + /* This implementation assumes: - * target characters/strings can be represented as type `char'/`char *', - * host's type `long'/`unsigned long' can hold values of mode `l'/`L', - * both host and target have two's complement integral arithmetic, - host's C operators `/' and `%' match target's div and mod. - target_max_ == (1<0 - target_min_ == -target_max_-1 - target_max_ == target_max_-target_min_ * both host and target have IEEE-754 floating-point arithmetic. */ /* !!! float and double divides MUST NOT SIGNAL !!! */ /* @@@ query the floating-point expception status flags */ -/* @@@ ToDo: tarval_convert_to is not fully implemented! */ /* @@@ Problem: All Values are stored twice, once as Univ_*s and a 2nd time in their real target mode. :-( */ -/* @@@ Perhaps use a set instead of a pset: new tarvals allocated on - stack, copied into set by tarval_identify() if really new. If - tarval_identify() discards often enough, the extra copy for kept - values is cheaper than the extra obstack_alloc()/free() for - discarded ones. */ + +#define MAX_INT_LENGTH 8 +#define CHAR_BUFFER_SIZE ((MAX_INT_LENGTH) * 2) #ifdef HAVE_CONFIG_H # include #endif -# include "xprintf.h" -#include -#include -#include -#include -#include -#include -#include - -#include "pset.h" -#define TOBSTACK_ID "tv" -#include "obst.h" -#include "ieee754.h" -#include "tune.h" -#include "xp_help.h" -#include "tv_t.h" -#include "entity_t.h" -#include "ident_t.h" -#include "irmode.h" -#include "irnode.h" +#include /* assertions */ +#include /* nice things for strings */ -static struct obstack tv_obst; /* obstack for all the target values */ -static pset *tarvals; /* pset containing pointers to _all_ tarvals */ +#include +#include "tv_t.h" +#include "set.h" /* to store tarvals in */ +#include "tune.h" /* some constants */ +#include "entity_t.h" /* needed to store pointers to entities */ +#include "irmode.h" /* defines modes etc */ +#include "irnode.h" /* defines boolean return values */ +#include "xprintf.h" +#include "xp_help.h" +#include "host.h" +#include "strcalc.h" +#include "fltcalc.h" -/* currently building an object with tarval_start() & friends ? */ -#define BUILDING obstack_object_size (&tv_obst) +/**************************************************************************** + * local definitions and macros + ****************************************************************************/ +#ifndef NDEBUG +# define TARVAL_VERIFY(a) tarval_verify((a)) +#else +# define TARVAL_VERIFY(a) ((void)0) +#endif -/* bcopy is not ISO C */ -#define bcopy(X, Y, Z) memcpy((Y), (X), (Z)) +#define INSERT_TARVAL(tv) ((tarval*)set_insert(tarvals, (tv), sizeof(tarval), hash_tv((tv)))) +#define FIND_TARVAL(tv) ((tarval*)set_find(tarvals, (tv), sizeof(tarval), hash_tv((tv)))) +#define INSERT_VALUE(val, size) (set_insert(values, (val), size, hash_val((val), size))) +#define FIND_VALUE(val, size) (set_find(values, (val), size, hash_val((val), size))) -/* special tarvals: */ -tarval *tarval_bad; -tarval *tarval_b_false; -tarval *tarval_b_true; -tarval *tarval_D_NaN; -tarval *tarval_D_Inf; -tarval *tarval_P_void; -tarval *tarval_mode_null[irm_max]; -tarval *tarval_mode_min[irm_max]; -tarval *tarval_mode_max[irm_max]; - -tarval *get_tarval_bad () { return tarval_bad; } -tarval *get_tarval_b_false () { return tarval_b_false; } -tarval *get_tarval_b_true () { return tarval_b_true; } -tarval *get_tarval_D_NaN () { return tarval_D_NaN; } -tarval *get_tarval_D_Inf () { return tarval_D_Inf; } -tarval *get_tarval_P_void () { return tarval_P_void; } -tarval *get_tarval_mode_null(ir_mode *mode) - { return tarval_mode_null[get_mode_modecode(mode)]; } -tarval *get_tarval_mode_min (ir_mode *mode) - { return tarval_mode_min[get_mode_modecode(mode)]; } -tarval *get_tarval_mode_max (ir_mode *mode) - { return tarval_mode_max[get_mode_modecode(mode)]; } - -# if 0 -/* @@@ depends on order of ir_mode */ -static tarval_sInt min_sInt[8] = { - TARGET_SIMIN (c), 0, - TARGET_SIMIN (h), 0, - TARGET_SIMIN (i), 0, - TARGET_SIMIN (l), 0 -}; -static tarval_sInt max_sInt[8] = { - TARGET_SIMAX (c), TARGET_UIMAX (C), - TARGET_SIMAX (h), TARGET_UIMAX (H), - TARGET_SIMAX (i), TARGET_UIMAX (I), - TARGET_SIMAX (l), TARGET_UIMAX (L) -}; -# endif - -/* Used to be in irmode.h, replaced now. */ -# define is_Int(m) ((m) <= irm_Lu && (m) >= irm_Bs) /* old */ - -/* return a mode-specific value */ - -tarval_F -tv_val_F (tarval *tv) +#define fail_verify(a) _fail_verify((a), __FILE__, __LINE__) +#if 0 +static long long count = 0; +# define ANNOUNCE() printf(__FILE__": call no. %lld (%s)\n", count++, __FUNCTION__); +#else +# define ANNOUNCE() ((void)0) +#endif +/**************************************************************************** + * private variables + ****************************************************************************/ +static struct set *tarvals; /* container for tarval structs */ +static struct set *values; /* container for values */ + +/**************************************************************************** + * private functions + ****************************************************************************/ +#ifndef NDEBUG +static int hash_val(const void *value, unsigned int length); +static int hash_tv(tarval *tv); +static void _fail_verify(tarval *tv, const char* file, int line) { - return tv->u.F; + /* print a memory image of the tarval and throw an assertion */ + if (tv) + printf("%s:%d: Invalid tarval:\n mode: %s\n value: [%p]\n", file, line, get_mode_name(tv->mode), tv->value); + else + printf("%s:%d: Invalid tarval (null)", file, line); + assert(0); } -tarval_D -tv_val_D (tarval *tv) +static void tarval_verify(tarval *tv) { - return tv->u.D; -} + assert(tv); + assert(tv->mode); + assert(tv->value); -tarval_E -tv_val_E (tarval *tv) -{ - return tv->u.E; + if ((tv == tarval_bad) || (tv == tarval_undefined)) return; + if ((tv == tarval_b_true) || (tv == tarval_b_false)) return; + + if (!FIND_TARVAL(tv)) fail_verify(tv); + if (tv->length > 0 && !FIND_VALUE(tv->value, tv->length)) fail_verify(tv); + + return; } +#endif /* NDEBUG */ -tarval_sInt -tv_val_sInt (tarval *tv) +static int hash_tv(tarval *tv) { - return tv->u.sInt; + return ((unsigned int)tv->value ^ (unsigned int)tv->mode) + tv->length; } -tarval_uInt -tv_val_uInt (tarval *tv) +static int hash_val(const void *value, unsigned int length) { - return tv->u.uInt; + unsigned int i; + unsigned int hash = 0; + + /* scramble the byte - array */ + for (i = 0; i < length; i++) + { + hash += (hash << 5) ^ (hash >> 27) ^ ((char*)value)[i]; + hash += (hash << 11) ^ (hash >> 17); + } + + return hash; } -tarval_P -tv_val_P (tarval *tv) +/* finds tarval with value/mode or creates new tarval*/ +static tarval *get_tarval(const void *value, int length, ir_mode *mode) { - return tv->u.P; + tarval tv; + + tv.mode = mode; + tv.length = length; + if (length > 0) + /* if there already is such a value, it is returned, else value + * is copied into the set */ + tv.value = INSERT_VALUE(value, length); + else + tv.value = value; + + /* if there is such a tarval, it is returned, else tv is copied + * into the set */ + return (tarval *)INSERT_TARVAL(&tv); } -bool -tv_val_b (tarval *tv) +static int overflows(tarval *tv) { - return tv->u.b; -} + switch (get_mode_sort(tv->mode)) + { + case character: + case int_number: + if (sc_comp(tv->value, get_mode_max(tv->mode)->value) == 1) return 1; + if (sc_comp(tv->value, get_mode_min(tv->mode)->value) == -1) return 1; + break; + case float_number: + if (fc_comp(tv->value, get_mode_max(tv->mode)->value) == 1) return 1; + if (fc_comp(tv->value, get_mode_min(tv->mode)->value) == -1) return 1; + break; -/* Overflows `sInt' signed integral `mode'? */ -static INLINE bool -sInt_overflow (tarval_sInt sInt, ir_mode *mode) -{ - assert (is_Int(get_mode_modecode(mode))); - return (get_mode_min(mode) && get_mode_max(mode) /* only valid after firm initialization */ - && (sInt < tv_val_sInt (get_mode_min(mode)) - || tv_val_sInt (get_mode_max(mode)) < sInt)); + default: + break; + } + + return 0; } +/**************************************************************************** + * public variables declared in tv.h + ****************************************************************************/ +tarval *tarval_bad; +tarval *tarval_undefined; +tarval *tarval_b_false; +tarval *tarval_b_true; +tarval *tarval_P_void; -/* Overflows `uInt' unsigned integral `mode'? */ -static INLINE bool -uInt_overflow (tarval_uInt uInt, ir_mode *mode) -{ - assert (is_Int(get_mode_modecode(mode))); - return (get_mode_max(mode) /* only valid after firm initialization */ - && tv_val_uInt (get_mode_max(mode)) < uInt); -} +/**************************************************************************** + * public functions declared in tv.h + ****************************************************************************/ +/* + * Constructors ============================================================= + */ +tarval *new_tarval_from_str(const char *str, size_t len, ir_mode *mode) +{ + ANNOUNCE(); + assert(str); + assert(len); + assert(mode); + + switch (get_mode_sort(mode)) + { + case auxiliary: + assert(0); + break; + case internal_boolean: + /* match tTrRuUeE/fFaAlLsSeE */ + if (strcmp(str, "true")) return tarval_b_true; + else return tarval_b_false; -#ifndef NDEBUG -void -_tarval_vrfy (const tarval *val) -{ - assert (val); - switch (get_mode_modecode(val->mode)) { - /* floating */ - case irm_F: - case irm_D: - case irm_E: - break; - /* integral */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: { - // printf("Tarval is %lu\n", val->u.uInt); - assert (!uInt_overflow (val->u.uInt, val->mode)); - } break; - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - assert (!sInt_overflow (val->u.sInt, val->mode)); break; - case irm_C: - case irm_U: - break; - case irm_P: - if (val->u.P.ent) { - assert (val->u.P.ent->kind == k_entity); - } - assert ( val->u.P.xname || val->u.P.ent - || !tarval_P_void || (val == tarval_P_void)); - break; - case irm_b: - assert ((unsigned)val->u.b <= 1); break; - default: - assert (val->mode == mode_T); - break; + case float_number: + fc_val_from_str(str, len); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode); + + case int_number: + case character: + sc_val_from_str(str, len); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), mode); + + case reference: + return get_tarval(str, len, mode); } -} -#endif + assert(0); /* can't be reached, can it? */ +} -#ifdef STATS +#if 0 +int tarval_is_str(tarval *tv) +{ + ANNOUNCE(); + assert(tv); -static void -tarval_stats (void) + return ((get_mode_sort(tv->mode) == reference) && (tv->value != NULL) && (tv->length > 0)); +} +char *tarval_to_str(tarval *tv) { - pset_stats (tarvals); + ANNOUNCE(); + assert(tarval_is_str(tv)); + return (char *)tv->value; } - #endif - -/* Return the canonical tarval * for tv. - May destroy everything allocated on tv_obst after tv! */ -static tarval * -tarval_identify (tarval *tv) +tarval *new_tarval_from_long(long l, ir_mode *mode) { - tarval *o; + ANNOUNCE(); + assert(mode && !(get_mode_sort(mode) == auxiliary)); - o = pset_insert (tarvals, tv, tarval_hash (tv)); + switch(get_mode_sort(mode)) + { + case internal_boolean: + /* XXX C-Semantics ! */ + return (l)?(tarval_b_true):(tarval_b_false); - if (o != tv) { - obstack_free (&tv_obst, (void *)tv); - } + case int_number: + case character: + sc_val_from_long(l); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), mode); - TARVAL_VRFY (o); - return o; -} + case float_number: + return new_tarval_from_double((long double)l, mode); + case reference: + return (l)?(tarval_bad):(get_tarval(NULL, 0, mode)); /* null pointer or tarval_bad */ -/* Return 0 iff a equals b. Bitwise identical NaNs compare equal. */ -static int -tarval_cmp (const void *p, const void *q) -{ - const tarval *a = p; - const tarval *b = q; - - TARVAL_VRFY (a); - TARVAL_VRFY (b); - - if (a == b) return 0; - if ((char *)a->mode - (char *)b->mode) - return (char *)a->mode - (char *)b->mode; - - switch (get_mode_modecode(a->mode)) { - /* floating */ - case irm_F: - return memcmp (&a->u.F, &b->u.F, sizeof (a->u.F)); - case irm_D: - return memcmp (&a->u.D, &b->u.D, sizeof (a->u.D)); - case irm_E: - return memcmp (&a->u.E, &b->u.E, sizeof (a->u.E)); - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - if (sizeof (int) == sizeof (tarval_uInt)) { - return a->u.uInt - b->u.uInt; - } - return a->u.uInt != b->u.uInt; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - if (sizeof (int) == sizeof (tarval_sInt)) { - return a->u.sInt - b->u.sInt; - } - return a->u.sInt != b->u.sInt; - case irm_C: - return a->u.C - b->u.C; - case irm_U: - return a->u.U - b->u.U; - case irm_P: - if (a->u.P.ent || b->u.P.ent) - return (char *)a->u.P.ent - (char *)b->u.P.ent; - if (a->u.P.xname && b->u.P.xname) - return strcmp (a->u.P.xname, b->u.P.xname); - return a->u.P.xname - b->u.P.xname; - case irm_b: - return a->u.b - b->u.b; - default: assert (0); + default: + assert(0); } } +int tarval_is_long(tarval *tv) +{ + ANNOUNCE(); + return ((get_mode_sort(tv->mode) == int_number) || (get_mode_sort(tv->mode) == character)); +} +/* this might overflow the machine's long, so use only with + * small values */ +long tarval_to_long(tarval* tv) +{ + ANNOUNCE(); + assert(tv && get_mode_sort(tv->mode) == int_number); + return sc_val_to_long(tv->value); /* might overflow */ +} -unsigned -tarval_hash (tarval *tv) +tarval *new_tarval_from_double(long double d, ir_mode *mode) { - unsigned h; - - h = get_mode_modecode(tv->mode) * 0x421u; - switch (get_mode_modecode(tv->mode)) { - case irm_T: - h = 0x94b527ce; break; - case irm_F: - /* quick & dirty */ - { union { float f; unsigned u; } u; - assert (sizeof (float) <= sizeof (unsigned)); - u.u = 0; u.f = tv->u.F; - h ^= u.u; - break; - } - case irm_D: - /* quick & dirty */ - { union { double d; unsigned u[2]; } u; - assert (sizeof (double) <= 2*sizeof (unsigned)); - u.u[0] = u.u[1] = 0; u.d = tv->u.D; - h ^= u.u[0] ^ u.u[1]; - break; - } - case irm_E: - { union { long double e; unsigned u[3]; } u; - assert (sizeof (long double) <= 3*sizeof (unsigned)); - u.u[0] = u.u[1] = u.u[2] = 0; u.e = tv->u.E; - h ^= u.u[0] ^ u.u[1] ^ u.u[2]; - break; - } - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - h ^= tv->u.uInt; break; - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - h ^= tv->u.sInt; break; - case irm_C: - h ^= tv->u.C; break; - case irm_U: - h ^= tv->u.U; break; - case irm_P: - if (tv->u.P.ent) { - /* @@@ lower bits not random, watch for collisions; perhaps - replace by tv->u.p.ent - (entity *)0 */ - h ^= ((char *)tv->u.P.ent - (char *)0) / 64; - } else if (tv->u.P.xname) { - /* Of course, strlen() in a hash function is a mistake, but this - case should be really rare. */ - h ^= ID_HASH (tv->u.P.xname, strlen (tv->u.P.xname)); - } else { /* void */ - h^= 0x2b592b88; - } - break; - case irm_b: - h ^= tv->u.b; break; - default: - assert(0); - } - return h; + ANNOUNCE(); + assert(mode && (get_mode_sort(mode) == float_number)); + + fc_val_from_float(d); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode); } +int tarval_is_double(tarval *tv) +{ + ANNOUNCE(); + assert(tv); + return (get_mode_sort(tv->mode) == float_number); +} +long double tarval_to_double(tarval *tv) +{ + ANNOUNCE(); + assert(tarval_is_double(tv)); -/*** ***************** Initialization ************************************* ***/ + return fc_val_to_float(tv->value); +} -void -tarval_init_1 (void) +/* The tarval represents the address of the entity. As the address must + be constant the entity must have as owner the global type. */ +tarval *new_tarval_from_entity (entity *ent, ir_mode *mode) { - obstack_init (&tv_obst); - obstack_alignment_mask (&tv_obst) = ALIGNOF (tarval) - 1; - assert (IS_POW2 (ALIGNOF (tarval))); + ANNOUNCE(); + assert(ent); + assert(mode && (get_mode_sort(mode) == reference)); - /* initialize the target value table */ - tarvals = new_pset (tarval_cmp, TUNE_NCONSTANTS); + return get_tarval((void *)ent, 0, mode); } - -void -tarval_init_2 (void) +int tarval_is_entity(tarval *tv) { - tarval *tv; - union ieee754_double x; - - /* assumed by tarval_hash(): */ - assert (sizeof (float) * CHAR_BIT == 32); - assert (sizeof (double) * CHAR_BIT == 64); - -# if 0 - /* assumed by tarval_sInt & friends: */ - assert ( (irm_C == irm_c+1) && (irm_h == irm_C+1) - && (irm_H == irm_h+1) && (irm_i == irm_H+1) - && (irm_I == irm_i+1) && (irm_l == irm_I+1) - && (irm_L == irm_l+1)); - - /* assumed everywhere: */ - for (i = 0; i <= irm_L-irm_c; i += 2) { - assert ( IS_POW2 (max_sInt[i+1]+1) - && (min_sInt[i] == -max_sInt[i]-1) - && ((tarval_uInt)max_sInt[i+1] == (tarval_uInt)max_sInt[i]-min_sInt[i])); - } -# endif - - - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = mode_T; - tarval_bad = tarval_identify (tv); - - tarval_b_false = tarval_from_long (mode_b, 0); - tarval_b_true = tarval_from_long (mode_b, 1); - - /* IsInf <-> exponent == 0x7ff && ! (bits | fraction_low) */ - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = mode_D; - x.ieee.negative = 0; - x.ieee.exponent = 0x7ff; - x.ieee.mantissa0 = 0; - x.ieee.mantissa1 = 0; - tv->u.D = x.d; - tarval_D_Inf = tarval_identify (tv); - - /* IsNaN <-> exponent==0x7ff && (qnan_bit | bits | fraction_low) */ - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = mode_D; - x.ieee_nan.negative = 0; - x.ieee_nan.exponent = 0x7ff; - x.ieee_nan.quiet_nan = 1; /* @@@ quiet or signalling? */ - x.ieee_nan.mantissa0 = 42; - x.ieee_nan.mantissa1 = 0; - assert(x.d != x.d /* x.d is NaN */); - tv->u.D = x.d; - tarval_D_NaN = tarval_identify (tv); - - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = mode_P; - tv->u.P.xname = NULL; - tv->u.P.ent = NULL; - tv->u.P.tv = NULL; - tarval_P_void = tarval_identify (tv); - - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - - - tarval_mode_null [irm_F] = tarval_from_long (mode_F, 0); - tarval_mode_null [irm_D] = tarval_from_long (mode_D, 0); - tarval_mode_null [irm_E] = tarval_from_long (mode_E, 0); - tarval_mode_null [irm_Bs] = tarval_from_long (mode_Bs, 0); - tarval_mode_null [irm_Bu] = tarval_from_long (mode_Bu, 0); - tarval_mode_null [irm_Hs] = tarval_from_long (mode_Hs, 0); - tarval_mode_null [irm_Hu] = tarval_from_long (mode_Hu, 0); - tarval_mode_null [irm_Is] = tarval_from_long (mode_Is, 0); - tarval_mode_null [irm_Iu] = tarval_from_long (mode_Iu, 0); - tarval_mode_null [irm_Ls] = tarval_from_long (mode_Ls, 0); - tarval_mode_null [irm_Lu] = tarval_from_long (mode_Lu, 0); - tarval_mode_null [irm_C] = tarval_from_long (mode_C, 0); - tarval_mode_null [irm_U] = tarval_from_long (mode_U, 0); - tarval_mode_null [irm_b] = tarval_b_false; - tarval_mode_null [irm_P] = tarval_P_void; + ANNOUNCE(); + assert(tv); + /* tv->value == NULL means dereferencing a null pointer */ + return ((get_mode_sort(tv->mode) == reference) && (tv->value != NULL) && (tv->length == 0)); } +entity *tarval_to_entity(tarval *tv) +{ + ANNOUNCE(); + assert(tarval_is_entity(tv)); + return (entity *)tv->value; +} -/*** ********************** Constructors for tarvals ********************** ***/ - -/* copy from src to dst len chars omitting '_'. */ -static char * -stripcpy (char *dst, const char *src, size_t len) +/* + * Access routines for tarval fields ======================================== + */ +#ifdef TARVAL_ACCESS_DEFINES +# undef get_tarval_mode +#endif +ir_mode *get_tarval_mode (tarval *tv) /* get the mode of the tarval */ { - char *d = dst; + ANNOUNCE(); + assert(tv); + return tv->mode; +} +#ifdef TARVAL_ACCESS_DEFINES +# define get_tarval_mode(tv) (tv)->mode +#endif - while (len--) { - if (*src == '_') src++; - else *d++ = *src++; - } - *d = 0; /* make it 0-terminated. */ +/* + * Special value query functions ============================================ + * + * These functions calculate and return a tarval representing the requested + * value. + * The functions get_mode_{Max,Min,...} return tarvals retrieved from these + * functions, but these are stored on initialization of the irmode module and + * therefore the irmode functions should be prefered to the functions below. + */ - return dst; +tarval *get_tarval_bad(void) +{ + ANNOUNCE(); + return tarval_bad; +} +tarval *get_tarval_undefined(void) +{ + ANNOUNCE(); + return tarval_undefined; +} +tarval *get_tarval_b_false(void) +{ + ANNOUNCE(); + return tarval_b_false; +} +tarval *get_tarval_b_true(void) +{ + ANNOUNCE(); + return tarval_b_true; +} +tarval *get_tarval_P_void(void) +{ + ANNOUNCE(); + return tarval_P_void; } -tarval * -tarval_F_from_str (const char *s, size_t len) +tarval *get_tarval_max(ir_mode *mode) { - tarval *tv; - char *buf; - char *eptr; + ANNOUNCE(); + assert(mode); - assert (!BUILDING); + switch(get_mode_sort(mode)) + { + case reference: + case auxiliary: + assert(0); + break; - buf = alloca (len+1); - stripcpy (buf, s, len); + case internal_boolean: + return tarval_b_true; - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = mode_F; - tv->u.F = (float)strtod (buf, &eptr); - assert (eptr == buf+strlen(buf)); + case float_number: + fc_get_max(get_mode_size(mode)); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode); - return tarval_identify (tv); + case int_number: + case character: + sc_max_from_bits(get_mode_size(mode), mode_is_signed(mode)); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), mode); + } + return tarval_bad; } - -tarval * -tarval_D_from_str (const char *s, size_t len) +tarval *get_tarval_min(ir_mode *mode) { - tarval *tv; - char *buf; - char *eptr; + ANNOUNCE(); + assert(mode); - assert (!BUILDING); + switch(get_mode_sort(mode)) + { + case reference: + case auxiliary: + assert(0); + break; - buf = alloca (len+1); - stripcpy (buf, s, len); + case internal_boolean: + return tarval_b_false; - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = mode_D; - tv->u.D = strtod (buf, &eptr); - assert (eptr == buf+strlen(buf)); + case float_number: + fc_get_min(get_mode_size(mode)); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode); - return tarval_identify (tv); + case int_number: + case character: + sc_min_from_bits(get_mode_size(mode), mode_is_signed(mode)); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), mode); + } + return tarval_bad; } -tarval * -tarval_int_from_str (const char *s, size_t len, int base, ir_mode *m) +tarval *get_tarval_null(ir_mode *mode) { - long val; - char *eptr; - char *buf; - - assert (mode_is_int(m)); - assert (!BUILDING); - - buf = alloca (len+1); - stripcpy (buf, s, len); - - errno = 0; - val = strtol(buf, &eptr, base); /* strtoll */ - assert (eptr == buf+strlen(buf)); - if ((errno == ERANGE) && - ((m == mode_Ls) || (m == mode_Lu)) ) { - printf("WARNING: Constant %s not representable. Continuing with %ld.\n", - s, val); - } + ANNOUNCE(); + assert(mode); - return tarval_from_long(m, val); -} + switch(get_mode_sort(mode)) + { + case auxiliary: + case internal_boolean: + assert(0); + break; -/* Create a tarval with mode `m' and value `val' casted to the type that - represents such tarvals on host. The resulting value must be legal - for mode `m'. */ -tarval * -tarval_from_long (ir_mode *m, long val) -{ - tarval *tv; + case float_number: + return new_tarval_from_double(0.0, mode); - assert (!BUILDING); - - if (m == mode_T) return tarval_bad; - - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - - tv->mode = m; - switch (get_mode_modecode(m)) { - /* floating */ - case irm_F: - tv->u.F = val; break; - case irm_D: - tv->u.D = val; break; - case irm_E: - /* @@@ not yet implemented */ - break; - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - tv->u.uInt = val; break; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - tv->u.sInt = val; break; - case irm_P: - assert(!val); - obstack_free (&tv_obst, tv); - return tarval_P_void; - case irm_C: - tv->u.C = val; break; - case irm_U: - tv->u.U = val; break; - case irm_b: - tv->u.b = !!val; /* u.b must be 0 or 1 */ - break; - default: - assert(0); - } + case int_number: + case character: + return new_tarval_from_long(0l, mode); - return tarval_identify (tv); + case reference: + return tarval_P_void; + } + return tarval_bad; } - -tarval * -tarval_P_from_str (const char *xname) +tarval *get_tarval_one(ir_mode *mode) { - tarval *tv; + ANNOUNCE(); + assert(mode); - assert (!BUILDING); + switch(get_mode_sort(mode)) + { + case auxiliary: + case internal_boolean: + case reference: + assert(0); + break; - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); + case float_number: + return new_tarval_from_double(1.0, mode); - tv->mode = mode_P; - tv->u.P.xname = obstack_copy0 (&tv_obst, xname, strlen (xname)); - tv->u.P.ent = NULL; - tv->u.P.tv = NULL; - return tarval_identify (tv); + case int_number: + case character: + return new_tarval_from_long(1l, mode); + break; + } + return tarval_bad; } - -tarval * -tarval_P_from_entity (entity *ent) +tarval *get_tarval_nan(ir_mode *mode) { - tarval *tv; - - assert (!BUILDING); - //assert(ent && "no entity given"); + ANNOUNCE(); + assert(mode); + assert(get_mode_sort(mode) == float_number); - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - - tv->mode = mode_P; - tv->u.P.xname = NULL; - tv->u.P.ent = ent; - tv->u.P.tv = NULL; - return tarval_identify (tv); + fc_get_nan(); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode); } - -/* Routines for building a tarval step by step follow. - Legal calling sequences: - tarval_start() - No constructors except tarval_append() and tarval_append1 () - tarval_finish_as() or tarval_cancel() */ - -/* Begin building a tarval. */ -void -tarval_start (void) +tarval *get_tarval_inf(ir_mode *mode) { - assert (!BUILDING); - obstack_blank (&tv_obst, sizeof (tarval)); -} - + ANNOUNCE(); + assert(mode); + assert(get_mode_sort(mode) == float_number); -/* Append `n' chars from `p' to the tarval currently under construction. */ -void -tarval_append (const char *p, size_t n) -{ - assert (BUILDING); - obstack_grow (&tv_obst, p, n); + fc_get_inf(); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode); } +/* + * Arithmethic operations on tarvals ======================================== + */ -/* Append `ch' to the tarval currently under construction. */ -void -tarval_append1 (char ch) +/* test if negative number, 1 means 'yes' */ +int tarval_is_negative(tarval *a) { - assert (BUILDING); - obstack_1grow (&tv_obst, ch); -} + ANNOUNCE(); + assert(a); + switch (get_mode_sort(a->mode)) + { + case int_number: + if (!mode_is_signed(a->mode)) return 0; + else return sc_comp(a->value, get_mode_null(a->mode)->value); -/* Finish the tarval currently under construction and give id mode `m'. - `m' must be irm_Bu, - Return NULL if the value does not make sense for this mode, this - can only happen in mode C. */ -tarval * -tarval_finish_as (ir_mode *m) -{ - int size = obstack_object_size (&tv_obst) - sizeof (tarval); - tarval *tv; - unsigned char *p; - char ch = 0; /* initialized to shut up gcc */ - - assert (BUILDING && (size >= 0)); - if (m == mode_Bu) { - if (size != 1) return tarval_cancel(); - p = (unsigned char *)obstack_base (&tv_obst) + sizeof (tarval); - ch = *p; - obstack_blank (&tv_obst, -size); - } - tv = obstack_finish (&tv_obst); - p = (unsigned char *)tv + sizeof (tarval); - tv->mode = m; - - switch (get_mode_modecode(m)) { - case irm_Bu: - tv->u.uInt = ch; - break; - case irm_P: - tv->u.P.tv = NULL; - break; - default: - assert (0); - } + case float_number: + return fc_comp(a->value, get_mode_null(a->mode)->value); - return tarval_identify (tv); + default: + assert(0 && "not implemented"); + } } - -/* Cancel tarval building and return tarval_bad. */ -tarval * -tarval_cancel (void) +/* comparison */ +pnc_number tarval_cmp(tarval *a, tarval *b) { - assert (BUILDING); - obstack_free (&tv_obst, obstack_finish (&tv_obst)); - return tarval_bad; -} + ANNOUNCE(); + assert(a); + assert(b); + if (a == tarval_bad || b == tarval_bad) assert(0 && "Comparison with tarval_bad"); + if (a == tarval_undefined || b == tarval_undefined) return False; + if (a == b) return Eq; + if (get_tarval_mode(a) != get_tarval_mode(b)) return Uo; -/*** ****************** Arithmethic operations on tarvals ***************** ***/ + /* Here the two tarvals are unequal and of the same mode */ + switch (get_mode_sort(a->mode)) + { + case auxiliary: + return False; -/* Return `src' converted to mode `m' if representable, else NULL. - @@@ lots of conversions missing */ -tarval * -tarval_convert_to (tarval *src, ir_mode *m) -{ - tarval *tv; + case float_number: + return (fc_comp(a->value, b->value)==1)?(Gt):(Lt); - if (m == src->mode) return src; + case int_number: + case character: + return (sc_comp(a->value, b->value)==1)?(Gt):(Lt); - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = m; + case internal_boolean: + return (a == tarval_b_true)?(Gt):(Lt); - switch (get_mode_modecode(src->mode)) { + case reference: + return Uo; + } + return False; +} + +tarval *tarval_convert_to(tarval *src, ir_mode *m) +{ + ANNOUNCE(); + tarval tv; - case irm_D: - if (m != mode_F) goto fail; - tv->u.F = src->u.D; - break; + assert(src); + assert(m); - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - switch (get_mode_modecode(m)) { - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - tv->u.sInt = src->u.sInt; - if (sInt_overflow (tv->u.sInt, m)) goto fail; + if (src->mode == m) return src; + + switch (get_mode_sort(src->mode)) + { + case auxiliary: break; - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - tv->u.uInt = src->u.sInt; - if (uInt_overflow (tv->u.uInt, m)) goto fail; + case float_number: break; - case irm_b: - tv->u.b = !!src->u.sInt; + case int_number: + switch (get_mode_sort(m)) + { + case int_number: + case character: + tv.mode = m; + tv.length = src->length; + tv.value = src->value; + if (overflows(&tv)) + { + return tarval_bad; + } + return INSERT_TARVAL(&tv); + + case internal_boolean: + /* XXX C semantics */ + if (src == get_mode_null(src->mode)) return tarval_b_false; + else return tarval_b_true; + + default: + break; + } break; - default: goto fail; - } + case internal_boolean: + switch (get_mode_sort(m)) + { + case int_number: + if (src == tarval_b_true) return get_mode_one(m); + else return get_mode_null(m); - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - switch (get_mode_modecode(m)) { - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - tv->u.sInt = src->u.uInt; - if (sInt_overflow (tv->u.sInt, m)) goto fail; + default: + break; + } break; - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - tv->u.uInt = src->u.uInt; - if (uInt_overflow (tv->u.uInt, m)) goto fail; + case character: break; - - case irm_b: - tv->u.b = !!src->u.uInt; + case reference: break; + } - default: goto fail; - } - break; + return tarval_bad; +} - case irm_b: - switch (get_mode_modecode(m)) { - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - tv->u.sInt = src->u.b; - break; +tarval *tarval_neg(tarval *a) /* negation */ +{ + ANNOUNCE(); + assert(a); + assert(mode_is_num(a->mode)); /* negation only for numerical values */ + assert(mode_is_signed(a->mode)); /* negation is difficult without negative numbers, isn't it */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - tv->u.uInt = src->u.b; + switch (get_mode_sort(a->mode)) + { + case int_number: + sc_neg(a->value); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); - default: goto fail; - } - break; + case float_number: + fc_neg(a->value); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), a->mode); - default: - fail: - obstack_free (&tv_obst, tv); - return NULL; + default: + return tarval_bad; } - - return tarval_identify (tv); } - -/* GL Why are there no ArmRoq comments, why is this not used? */ -tarval * -tarval_neg (tarval *a) +tarval *tarval_add(tarval *a, tarval *b) /* addition */ { - tarval *tv; - - TARVAL_VRFY (a); - - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - - tv->mode = a->mode; - - switch (get_mode_modecode(a->mode)) { - /* floating */ - case irm_F: tv->u.F = -a->u.F; break; - case irm_D: tv->u.D = -a->u.D; break; - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - tv->u.uInt = -a->u.uInt & tv_val_uInt (get_mode_max(a->mode)); - break; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - tv->u.sInt = -a->u.sInt; - if ( sInt_overflow (tv->u.sInt, a->mode) - || ((tv->u.sInt >= 0) == (a->u.sInt >= 0))) { - obstack_free (&tv_obst, tv); - return NULL; - } - break; - case irm_b: tv->u.b = !a->u.b; break; - default: assert(0); - } - - return tarval_identify (tv); -} + ANNOUNCE(); + assert(a); + assert(b); + assert((a->mode == b->mode) || (get_mode_sort(a->mode) == character && mode_is_int(b->mode))); + switch (get_mode_sort(a->mode)) + { + case character: + case int_number: + /* modes of a,b are equal, so result has mode of a as this might be the character */ + sc_add(a->value, b->value); + /* FIXME: Check for overflow */ + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); -/* Compare `a' with `b'. - Return one of irpn_Lt, irpn_Eq, irpn_Gt, irpn_Uo, or irpn_False if - result is unknown. */ -ir_pncmp -tarval_comp (tarval *a, tarval *b) -{ + case float_number: + /* FIXME: Overflow/Underflow/transition to inf when mode < 80bit */ + fc_add(a->value, b->value); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), a->mode); - TARVAL_VRFY (a); - TARVAL_VRFY (b); - - assert (a->mode == b->mode); - - switch (get_mode_modecode(a->mode)) { - /* floating */ - case irm_F: return ( a->u.F == b->u.F ? irpn_Eq - : a->u.F > b->u.F ? irpn_Gt - : a->u.F < b->u.F ? irpn_Lt - : irpn_Uo); - case irm_D: return ( a->u.D == b->u.D ? irpn_Eq - : a->u.D > b->u.D ? irpn_Gt - : a->u.D < b->u.D ? irpn_Lt - : irpn_Uo); - case irm_E: return ( a->u.E == b-> u.E ? irpn_Eq - : a->u.E > b->u.E ? irpn_Gt - : a->u.E < b->u.E ? irpn_Lt - : irpn_Uo); - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - return ( a->u.uInt == b->u.uInt ? irpn_Eq - : a->u.uInt > b->u.uInt ? irpn_Gt - : irpn_Lt); - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - return ( a->u.sInt == b->u.sInt ? irpn_Eq - : a->u.sInt > b->u.sInt ? irpn_Gt - : irpn_Lt); - case irm_b: return ( a->u.b == b->u.b ? irpn_Eq - : a->u.b > b->u.b ? irpn_Gt - : irpn_Lt); - /* The following assumes that pointers are unsigned, which is valid - for all sane CPUs (transputers are insane). */ - case irm_P: return ( a == b ? irpn_Eq - : a == tarval_P_void ? irpn_Lt - : b == tarval_P_void ? irpn_Gt - : irpn_False); /* unknown */ - default: assert (0); + default: + return tarval_bad; } } - -/* Return `a+b' if computable, else NULL. Modes must be equal. */ -tarval * -tarval_add (tarval *a, tarval *b) +tarval *tarval_sub(tarval *a, tarval *b) /* subtraction */ { - tarval *tv; + ANNOUNCE(); + assert(a); + assert(b); + assert((a->mode == b->mode) || (get_mode_sort(a->mode) == character && mode_is_int(b->mode))); - TARVAL_VRFY (a); TARVAL_VRFY (b); - assert (a->mode == b->mode); - - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - - tv->mode = a->mode; - - switch (get_mode_modecode(a->mode)) { - /* floating */ - case irm_F: tv->u.F = a->u.F + b->u.F; break; /* @@@ overflow etc */ - case irm_D: tv->u.D = a->u.D + b->u.D; break; /* @@@ dto. */ - case irm_E: tv->u.E = a->u.E + b->u.E; break; /* @@@ dto. */ - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - tv->u.uInt = (a->u.uInt + b->u.uInt) & tv_val_uInt (get_mode_max(a->mode)); - break; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - tv->u.sInt = a->u.sInt + b->u.sInt; - if ( sInt_overflow (tv->u.sInt, a->mode) - || ((tv->u.sInt > a->u.sInt) ^ (b->u.sInt > 0))) { - obstack_free (&tv_obst, tv); - return NULL; - } - break; - case irm_b: tv->u.b = a->u.b | b->u.b; break; /* u.b is in canonical form */ - default: assert(0); - } + switch (get_mode_sort(a->mode)) + { + case character: + case int_number: + /* modes of a,b are equal, so result has mode of a as this might be the character */ + sc_sub(a->value, b->value); + /* FIXME: check for overflow */ + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); - return tarval_identify (tv); -} - - -/* Return `a-b' if computable, else NULL. Modes must be equal. */ -tarval * -tarval_sub (tarval *a, tarval *b) -{ - tarval *tv; + case float_number: + /* FIXME: Overflow/Underflow/transition to inf when mode < 80bit */ + fc_add(a->value, b->value); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), a->mode); - TARVAL_VRFY (a); TARVAL_VRFY (b); - assert (a->mode == b->mode); - - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - - tv->mode = a->mode; - - switch (get_mode_modecode(a->mode)) { - /* floating */ - case irm_F: tv->u.F = a->u.F - b->u.F; break; /* @@@ overflow etc */ - case irm_D: tv->u.D = a->u.D - b->u.D; break; /* @@@ dto. */ - case irm_E: tv->u.E = a->u.E - b->u.E; break; /* @@@ dto. */ - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - tv->u.uInt = (a->u.uInt - b->u.uInt) & tv_val_uInt (get_mode_max(a->mode)); - break; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - tv->u.sInt = a->u.sInt - b->u.sInt; - if ( sInt_overflow (tv->u.sInt, a->mode) - || ((tv->u.sInt > a->u.sInt) ^ (b->u.sInt < 0))) { - obstack_free (&tv_obst, tv); - return NULL; - } - break; - case irm_b: tv->u.b = a->u.b & ~b->u.b; break; /* u.b is in canonical form */ - default: assert(0); + default: + return tarval_bad; } - - return tarval_identify (tv); } -/* Return `a*b' if computable, else NULL. Modes must be equal. */ -tarval * -tarval_mul (tarval *a, tarval *b) +tarval *tarval_mul(tarval *a, tarval *b) /* multiplication */ { - tarval *tv; - - TARVAL_VRFY (a); TARVAL_VRFY (b); - assert (a->mode == b->mode); - - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - - tv->mode = a->mode; - - switch (get_mode_modecode(a->mode)) { - /* floating */ - case irm_F: tv->u.F = a->u.F * b->u.F; break; /* @@@ overflow etc */ - case irm_D: tv->u.D = a->u.D * b->u.D; break; /* @@@ dto. */ - case irm_E: tv->u.E = a->u.E * b->u.E; break; /* @@@ dto. */ - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - tv->u.uInt = (a->u.uInt * b->u.uInt) & tv_val_uInt (get_mode_max(a->mode)); - break; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - tv->u.sInt = a->u.sInt * b->u.sInt; - if ( sInt_overflow (tv->u.sInt, a->mode) - || (b->u.sInt && (tv->u.sInt / b->u.sInt != a->u.sInt))) { - obstack_free (&tv_obst, tv); - return NULL; - } - break; - case irm_b: tv->u.b = a->u.b & b->u.b; break; /* u.b is in canonical form */ - default: assert(0); - } + ANNOUNCE(); + assert(a); + assert(b); + assert((a->mode == b->mode) && mode_is_num(a->mode)); - return tarval_identify (tv); -} + switch (get_mode_sort(a->mode)) + { + case int_number: + /* modes of a,b are equal */ + sc_mul(a->value, b->value); + /* FIXME: check for overflow */ + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); + case float_number: + /* FIXME: Overflow/Underflow/transition to inf when mode < 80bit */ + fc_add(a->value, b->value); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), a->mode); -/* Return floating-point `a/b' if computable, else NULL. - Modes must be equal, non-floating-point operands are converted to irm_D. */ -tarval * -tarval_quo (tarval *a, tarval *b) -{ - tarval *tv; - - TARVAL_VRFY (a); TARVAL_VRFY (b); - assert (a->mode == b->mode); - - switch (get_mode_modecode(a->mode)) { - /* floating */ - case irm_F: - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = mode_F; - tv->u.F = a->u.F / b->u.F; /* @@@ overflow etc */ - break; - case irm_D: - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = mode_D; - tv->u.D = a->u.D / b->u.D; /* @@@ overflow etc */ - break; - default: - a = tarval_convert_to (a, mode_D); - b = tarval_convert_to (b, mode_D); - return a && b ? tarval_quo (a, b) : NULL; + default: + return tarval_bad; } - - return tarval_identify (tv); } - -/* Return `a/b' if computable, else NULL. Modes must be equal. */ -tarval * -tarval_div (tarval *a, tarval *b) +tarval *tarval_quo(tarval *a, tarval *b) /* floating point division */ { - tarval *tv; + ANNOUNCE(); + assert(a); + assert(b); + assert((a->mode == b->mode) && mode_is_float(a->mode)); - TARVAL_VRFY (a); TARVAL_VRFY (b); - assert (a->mode == b->mode); - - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - - tv->mode = a->mode; - - switch (get_mode_modecode(a->mode)) { - /* floating */ - case irm_F: tv->u.F = floor (a->u.F / b->u.F); break; /* @@@ overflow etc */ - case irm_D: tv->u.D = floor (a->u.D / b->u.D); break; /* @@@ dto. */ - case irm_E: tv->u.E = floor (a->u.E / b->u.E); break; /* @@@ dto. */ - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - if (!b->u.uInt) goto fail; - tv->u.uInt = a->u.uInt / b->u.uInt; - break; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - if ( !b->u.sInt - || ((b->u.sInt == -1) && (a->u.sInt == tv_val_sInt (get_mode_max(a->mode)) ))) { - fail: - obstack_free (&tv_obst, tv); - return NULL; - } - tv->u.sInt = a->u.sInt / b->u.sInt; - break; - case irm_b: tv->u.b = a->u.b ^ b->u.b; break; /* u.b is in canonical form */ - default: assert(0); - } - - return tarval_identify (tv); + /* FIXME: Overflow/Underflow/transition to inf when mode < 80bit */ + fc_div(a->value, b->value); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), a->mode); } - -/* Return `a%b' if computable, else NULL. Modes must be equal. */ -tarval * -tarval_mod (tarval *a, tarval *b) +tarval *tarval_div(tarval *a, tarval *b) /* integer division */ { - tarval *tv; - - TARVAL_VRFY (a); TARVAL_VRFY (b); - assert (a->mode == b->mode); - - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - - tv->mode = a->mode; - - switch (get_mode_modecode(a->mode)) { - /* floating */ - case irm_F: tv->u.F = fmod (a->u.F, b->u.F); break; /* @@@ overflow etc */ - case irm_D: tv->u.D = fmod (a->u.D, b->u.D); break; /* @@@ dto */ - case irm_E: tv->u.E = fmod (a->u.E, b->u.E); break; /* @@@ dto. */ - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - if (!b->u.uInt) goto fail; - tv->u.uInt = a->u.uInt % b->u.uInt; - break; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - if (!b->u.sInt) { - fail: - obstack_free (&tv_obst, tv); - return NULL; - } - tv->u.sInt = a->u.sInt % b->u.sInt; - break; - case irm_b: tv->u.b = a->u.b ^ b->u.b; break; /* u.b is in canonical form */ - default: assert(0); - } - - return tarval_identify (tv); -} + ANNOUNCE(); + assert(a); + assert(b); + assert((a->mode == b->mode) && mode_is_int(a->mode)); -/* Return |a| if computable, else Null. */ -/* is -max == min?? */ -tarval * -tarval_abs (tarval *a) { - TARVAL_VRFY (a); - if (tv_is_negative(a)) return tarval_neg(a); - return a; + /* modes of a,b are equal */ + sc_div(a->value, b->value); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); } -int -tv_is_negative(tarval *a) { - TARVAL_VRFY (a); - switch (get_mode_modecode(a->mode)) { - /* floating */ - case irm_F: return (a->u.F<0); - case irm_D: return (a->u.D<0); - case irm_E: return (a->u.E<0); - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - return 0; - break; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - return (a->u.sInt < 0); - break; - case irm_b: break; - default: assert(0); - } +tarval *tarval_mod(tarval *a, tarval *b) /* remainder */ +{ + ANNOUNCE(); + assert(a); + assert(b); + assert((a->mode == b->mode) && mode_is_int(a->mode)); - return 0; + /* modes of a,b are equal */ + sc_mod(a->value, b->value); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); } - -/* Return `a&b'. Modes must be equal. */ -tarval * -tarval_and (tarval *a, tarval *b) +tarval *tarval_abs(tarval *a) /* absolute value */ { - tarval *tv; + ANNOUNCE(); + assert(a); + assert(mode_is_num(a->mode)); - TARVAL_VRFY (a); TARVAL_VRFY (b); - assert (a->mode == b->mode); + switch (get_mode_sort(a->mode)) + { + case int_number: + if (sc_comp(a->value, get_mode_null(a->mode)->value) == -1) + { + sc_neg(a->value); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); + } + return a; - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - - tv->mode = a->mode; + case float_number: + break; - switch (get_mode_modecode(a->mode)) { - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - tv->u.uInt = a->u.uInt & b->u.uInt; break; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - tv->u.sInt = a->u.sInt & b->u.sInt; break; - case irm_b: tv->u.b = a->u.b & b->u.b; break; /* u.b is in canonical form */ - default: assert(0); + default: + return tarval_bad; } - - return tarval_identify (tv); + return tarval_bad; } - -/* Return `a|b'. Modes must be equal. */ -tarval * -tarval_or (tarval *a, tarval *b) +tarval *tarval_and(tarval *a, tarval *b) /* bitwise and */ { - tarval *tv; - - TARVAL_VRFY (a); TARVAL_VRFY (b); - assert (a->mode == b->mode); - - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - - tv->mode = a->mode; + ANNOUNCE(); + assert(a); + assert(b); + assert((a->mode == b->mode) && mode_is_int(a->mode)); - switch (get_mode_modecode(a->mode)) { - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - tv->u.uInt = a->u.uInt | b->u.uInt; break; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - tv->u.sInt = a->u.sInt | b->u.sInt; break; - case irm_b: tv->u.b = a->u.b | b->u.b; break; /* u.b is in canonical form */ - default: assert(0); - } - - return tarval_identify (tv); + sc_and(a->value, b->value); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); } - - -/* Return `a^b'. Modes must be equal. */ -tarval * -tarval_eor (tarval *a, tarval *b) +tarval *tarval_or (tarval *a, tarval *b) /* bitwise or */ { - tarval *tv; - - TARVAL_VRFY (a); TARVAL_VRFY (b); - assert (a->mode == b->mode); - - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - - tv->mode = a->mode; + ANNOUNCE(); + assert(a); + assert(b); + assert((a->mode == b->mode) && mode_is_int(a->mode)); - switch (get_mode_modecode(a->mode)) { - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - tv->u.uInt = a->u.uInt ^ b->u.uInt; break; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - tv->u.sInt = a->u.sInt ^ b->u.sInt; break; - case irm_b: tv->u.b = a->u.b ^ b->u.b; break; /* u.b is in canonical form */ - default: assert(0); - } - - return tarval_identify (tv); + sc_or(a->value, b->value); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); } +tarval *tarval_eor(tarval *a, tarval *b) /* bitwise exclusive or (xor) */ +{ + ANNOUNCE(); + assert(a); + assert(b); + assert((a->mode == b->mode) && mode_is_int(a->mode)); + sc_or(a->value, b->value); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); +} -/* Return `a<mode) && mode_is_int(b->mode)); - TARVAL_VRFY (a); TARVAL_VRFY (b); - - shift = tarval_ord (b, &b_is_huge); - if ( b_is_huge - || (shift < 0) - || ((shift >= get_mode_size(mode_Ls)*target_bits))) { - return NULL; - } + sc_shl(a->value, b->value, get_mode_size(a->mode), mode_is_signed(a->mode)); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); +} +tarval *tarval_shr(tarval *a, tarval *b) /* bitwise unsigned right shift */ +{ + ANNOUNCE(); + assert(a); + assert(b); + assert(mode_is_int(a->mode) && mode_is_int(b->mode)); - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = a->mode; - - switch (get_mode_modecode(a->mode)) { - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - tv->u.uInt = a->u.uInt << shift; - break; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - tv->u.sInt = a->u.sInt << shift; - break; - default: assert (0); - } + sc_shr(a->value, b->value, get_mode_size(a->mode), mode_is_signed(a->mode)); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); +} +tarval *tarval_shrs(tarval *a, tarval *b) /* bitwise signed right shift */ +{ + ANNOUNCE(); + assert(a); + assert(b); + assert(mode_is_int(a->mode) && mode_is_int(b->mode)); - return tarval_identify (tv); + sc_shrs(a->value, b->value, get_mode_size(a->mode), mode_is_signed(a->mode)); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); } +tarval *tarval_rot(tarval *a, tarval *b) /* bitwise rotation */ +{ + ANNOUNCE(); + assert(a); + assert(b); + assert(mode_is_int(a->mode) && mode_is_int(b->mode)); + sc_rot(a->value, b->value, get_mode_size(a->mode), mode_is_signed(a->mode)); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); +} -/* Return `a>>b' if computable, else NULL. - The interpretation of >> (sign extended or not) is implementaion - dependent, i.e. this is neither shr nor shrs!! */ -tarval * -tarval_shr (tarval *a, tarval *b) +/** *********** Output of tarvals *********** **/ +int tarval_print(XP_PAR1, const xprintf_info *info ATTRIBUTE((unused)), XP_PARN) { - int b_is_huge; - long shift; + ANNOUNCE(); tarval *tv; + char *str; + int offset; + + tv = XP_GETARG(tarval *, 0); + switch (get_mode_sort(tv->mode)) + { + case int_number: + case character: + offset = 16 - (get_mode_size(tv->mode)/4); + str = sc_print_hex(tv->value); + return XPF1R("0x%s", str + offset); + + case float_number: + return XPF1R("%s", fc_print_dec(tv->value)); + + case reference: + if (tv->value != NULL) + if (tarval_is_entity(tv)) + if (get_entity_peculiarity((entity *)tv->value) == existent) + return XPF1R("&(%I)", get_entity_ld_ident((entity *)tv->value)); + else + return XPSR("NULL"); + else + return XPMR((char*)tv->value, tv->length); + else + return XPSR("void"); - TARVAL_VRFY (a); TARVAL_VRFY (b); - - shift = tarval_ord (b, &b_is_huge); - if ( b_is_huge - || (shift < 0) - || ((shift >= get_mode_size(mode_Ls)*target_bits))) { - return NULL; - } + case internal_boolean: + if (tv == tarval_b_true) return XPSR("true"); + else return XPSR("false"); - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = a->mode; - - switch (get_mode_modecode(a->mode)) { - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - tv->u.uInt = a->u.uInt >> shift; - break; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - tv->u.sInt = a->u.sInt >> shift; - break; - default: assert (0); + case auxiliary: + return XPSR(""); } - return tarval_identify (tv); + return 0; } +char *tarval_bitpattern(tarval *tv) +{ + return NULL; +} -/* Classify `tv', which may be NULL. - Return 0 if `tv' is the additive neutral element, 1 if `tv' is the - multiplicative neutral element, and -1 if `tv' is the neutral - element of bitwise and. */ -long -tarval_classify (tarval *tv) +/* Identifying some tarvals ??? */ +/* Implemented in old tv.c as such: + * return 0 for additive neutral, + * 1 for multiplicative neutral, + * -1 for bitwise-and neutral + * 2 else + * + * Implemented for completeness */ +long tarval_classify(tarval *tv) { - if (!tv) return 2; - - TARVAL_VRFY (tv); - - switch (get_mode_modecode(tv->mode)) { - /* floating */ - case irm_F: case irm_D: case irm_E: - return 2; - /* unsigned */ - case irm_Bu: - return (long)((tv->u.uInt+1) & tv_val_uInt (get_mode_max(mode_Bu))) - 1; - case irm_Hu: - return (long)((tv->u.uInt+1) & tv_val_uInt (get_mode_max(mode_Hu))) - 1; - case irm_Iu: - return (long)((tv->u.uInt+1) & tv_val_uInt (get_mode_max(mode_Iu))) - 1; - case irm_Lu: - return (long)((tv->u.uInt+1) & tv_val_uInt (get_mode_max(mode_Lu))) - 1; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - return tv->u.sInt; - case irm_b: - return tv->u.b; - default: - return 2; - } + ANNOUNCE(); + if (!tv || tv == tarval_bad) return 2; + + if (tv == get_mode_null(tv->mode)) return 0; + else if (tv == get_mode_one(tv->mode)) return 1; + else if ((get_mode_sort(tv->mode) == int_number) + && (tv == new_tarval_from_long(-1, tv->mode))) return -1; + + return 2; } -/* Convert `tv' into type `long', set `fail' if not representable. - If `fail' gets set for an unsigned `tv', the correct result can be - obtained by casting the result to `unsigned long'. */ -long -tarval_ord (tarval *tv, int *fail) +/** Initialization of the tarval module **/ +void init_tarval_1(void) { - TARVAL_VRFY (tv); - - switch (get_mode_modecode(tv->mode)) { - /* unsigned */ - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - *fail = tv->u.uInt > tv_val_uInt (get_mode_max(mode_Ls)); - return tv->u.uInt; - /* signed */ - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: - *fail = 0; - return tv->u.sInt; - case irm_b: - *fail = 0; - return tv->u.b; - default: ; - *fail = 1; - return 0; - } + ANNOUNCE(); + /* initialize the sets holding the tarvals with a comparison function and + * an initial size, which is the expected number of constants */ + tarvals = new_set(memcmp, TUNE_NCONSTANTS); + values = new_set(memcmp, TUNE_NCONSTANTS); } -int -tarval_print (XP_PAR1, const xprintf_info *info ATTRIBUTE((unused)), XP_PARN) +void init_tarval_2(void) { - tarval *val = XP_GETARG (tarval *, 0); - int printed; - char buf[40]; - - TARVAL_VRFY (val); - - switch (get_mode_modecode(val->mode)) { - - case irm_T: /* none */ - printed = XPSR (""); - break; - - case irm_F: /* float */ - sprintf (buf, "%1.9e", (float)(val->u.F)); - printed = XPF1R ("%s", buf); - break; - case irm_D: /* double */ - printed = XPF1R ("%1.30g", (double)(val->u.D)); - break; - - case irm_C: /* character */ - if ((isprint (val->u.C)) && - (val->u.C != '\\') && (val->u.C != '\'')) { - printed = XPF1R ("'%c'", val->u.C); - } else { - printed = XPF1R ("0x%x", (unsigned long)val->u.C); - } - break; - case irm_U: /* unicode character */ - printed = XPF1R ("0x%x", (unsigned long)val->u.U); - break; - - case irm_Bs: case irm_Hs: case irm_Is: case irm_Ls: /* signed num */ - printed = XPF1R ("%ld", (long)val->u.sInt); - break; - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: /* unsigned num */ - printed = XPF1R ("%lu", (unsigned long)val->u.uInt); - break; - - case irm_P: /* pointer */ - if (val->u.P.xname) { - printed = XPR (val->u.P.xname); - } else if (val->u.P.ent) { - if (get_entity_peculiarity(val->u.P.ent) == existent) - printed = XPF1R ("&(%I)", get_entity_ld_ident(val->u.P.ent)); - else - printed = XPSR ("(NULL)"); - } else { - assert (val == tarval_P_void); - printed = XPSR ("(NULL)"); - } - break; - - case irm_b: /* boolean */ - if (val->u.b) printed = XPSR ("true"); - else printed = XPSR ("false"); - break; - - case irm_M: /* memory */ - case irm_BB: /* region */ - default: - assert (0); - } + ANNOUNCE(); - return printed; -} + tarval_bad = (tarval*)malloc(sizeof(tarval)); + tarval_bad->mode = NULL; + tarval_undefined = (tarval*)malloc(sizeof(tarval)); + tarval_undefined->mode = NULL; -ir_mode * -get_tv_mode (tarval *tv) -{ - return tv->mode; -} + tarval_b_true = (tarval*)malloc(sizeof(tarval)); + tarval_b_true->mode = mode_b; -/* Returns the entity if the tv is a pointer to an entity, else - returns NULL; */ -entity *get_tv_entity(tarval *tv) { - entity *ent = NULL; + tarval_b_false = (tarval*)malloc(sizeof(tarval)); + tarval_b_false->mode = mode_b; - if (tv->mode == mode_P) { - if (tv->u.P.xname) { - assert(0); - /* not an entity */ - } else if (tv->u.P.ent) { - ent = tv->u.P.ent; - } else { - /* not an entity */ - } - } - return ent; + tarval_P_void = (tarval*)malloc(sizeof(tarval)); + tarval_P_void->mode = mode_P; } +/**************************************************************************** + * end of tv.c + ****************************************************************************/ void -free_tv_entity(entity *ent) { +free_tarval_entity(entity *ent) { /* There can be a tarval referencing this entity. Even if the tarval is not used by the code any more, it can still reference the entity as tarvals live forever (They live on an obstack.). @@ -1448,13 +970,6 @@ free_tv_entity(entity *ent) { it contains a proper entity and we will crash if the entity is freed. We cannot remove tarvals from the obstack but we can remove the entry in the hash table. */ - tarval *found = NULL; - tarval *tv = (tarval *)pset_first(tarvals); - while (tv) { - entity *tv_ent = get_tv_entity(tv); - if ((tv_ent) && (tv_ent == ent)) found = tv; - tv = pset_next(tarvals); - } - if (found) - pset_remove(tarvals, found, tarval_hash(found)); + /* this will be re-implemented later */ + ANNOUNCE(); } diff --git a/ir/tv/tv.h b/ir/tv/tv.h index 39decd5e5..0cd28cde5 100644 --- a/ir/tv/tv.h +++ b/ir/tv/tv.h @@ -1,7 +1,3 @@ -/* Declarations for Target Values. - Copyright (C) 1995, 1996 Christian von Roques -*/ - /** * @file tv.h * @@ -51,164 +47,449 @@ Discussion of new interface, proposals by Prof. Waite: # include "irmode.h" # include "entity.h" # include +# include "irnode.h" /* for pnc_number enum */ + +/****h* libfirm/tv + * + * NAME + * tv -- TargetValue, short tarval. + * Internal representation for machine values. + * + * AUTHORS + * Christian von Roques + * Matthias Heil + * + * DESCRIPTION + * Tarvals represent target machine values. They are typed by modes. + * Tarvals only represent values of mode_sort: + * int_number, + * float_number, + * boolean, + * reference, + * character + * + * In case of references the module accepts an entity to represent the + * value. + * Furthermore, computations and conversions of these values can + * be performed. + * + * USES + * This module is closely related to the irmode module, as the modes + * defined there are thoroughly used throughout the whole module. + * Also, the comparison functions rely on the definition of comparison + * values in the irnode module. + * + * HISTORY + * The original tv module originated in the fiasco compiler written ... + * This is the new version, described in the tech report 1999-14 by ... + * + * SEE ALSO + * Techreport 1999-14 + * irmode.h for the modes definitions + * irnode.h for the pnc_numbers table + * + * tarval_init1 and tarval_init2 for initialization of the + * module + * + ******/ #ifndef _TARVAL_TYPEDEF_ #define _TARVAL_TYPEDEF_ -typedef struct tarval tarval; + typedef struct tarval tarval; #endif -/*@{*/ -/** how to represent target types on host */ -typedef float tarval_F; -typedef double tarval_D; -typedef long double tarval_E; -typedef long tarval_sInt; -typedef unsigned long tarval_uInt; -typedef char tarval_C; -typedef unsigned short tarval_U; /* 16 bit ?! wchar could be defined as char... */ -/*@}*/ - -/** tarval_P */ -typedef struct { - /** if ent then xname is missing or mangled from ent, - else if xname then xname is a linker symbol that is not mangled - from an entity, - else this is tarval_p_void. - if this tarval describes a symbolic address of another tarval, tv points - to this val */ - const char *xname; - entity *ent; - tarval *tv; -} tarval_P; - -/** a trval */ -struct tarval { - union { - tarval_F F; /**< float */ - tarval_D D; /**< double */ - tarval_E E; /**< extended */ - tarval_sInt sInt; /**< signed integral */ - tarval_uInt uInt; /**< unsigned integral */ - tarval_C C; /**< character */ - tarval_U U; /**< unicode character */ - tarval_P P; /**< pointer */ - bool b; /**< boolean */ - } u; - ir_mode *mode; -}; +/* ************************ Constructors for tarvals ************************ */ +/****f* tv/new_tarval_from_str + * + * NAME + * new_tarval_from_str + * Constructor function for new tarvals. + * + * SYNOPSIS + * tarval *new_tarval_from_str(const char *s, size_t len, ir_mode *mode) + * + * DESCRIPTION + * This function creates a new tarval representing the value represented + * by a CString, aka char array. If a tarval representing this value already + * exists, this tarval is returned instead of a new one. So tarvals are + * directly comparable since their representation is unique. + * + * PARAMETERS + * str - The String representing the target value + * len - The length of the string + * mode - The mode requested for the result tarval + * + * This function accepts the following strings: + * if mode is int_number: + * 0(x|X)[0-9a-fA-F]+ (hexadecimal representation) + * 0[0-7]* (octal representation) + * (+|-)?[1-9][0-9]* (decimal representation) + * if mode if float_number: + * (+|-)?(decimal int) (. (decimal int))? ((e|E)(+|-)?(decimal int))? + * if mode is boolean: true, True, TRUE ... False... 0, 1, + * if mode is reference: hexadecimal of decimal number as int + * if mode is character: hex or dec + * Leading and/or trailing spaces are ignored + * + * RESULT + * A tarval of proper type representing the requested value is returned. + * Tarvals are unique, so for any value/mode pair at most one tarval will + * exist, which will be returned upon further requests with an identical + * value/mode pair. + * + * NOTES + * If the string is not representable in the given mode an assertion is + * thrown. + * + * SEE ALSO + * irmode.h for predefined modes + * new_tarval_from_long + * new_tarval_from_double + * + ******/ +tarval *new_tarval_from_str(const char *str, size_t len, ir_mode *mode); +/****f* tv/new_tarval_from_long + * + * NAME + * new_tarval_from_long + * Constructor function for new tarvals + * + * SYNOPSIS + * tarval *new_tarval_from_long(const long l. ir_mode *mode) + * + * DESCRIPTION + * This function creates a new tarval representing the value represented + * by a long integer. If a tarval representing this value already exists, + * this tarval is returned instead of a new one. So tarvals are directly + * comparable since their representation is unique. + * + * PARAMETERS + * l - The long representing the value + * mode - The mode requested for the result tarval + * + * RESULT + * A tarval of proper type representing the requested value is returned. + * Tarvals are unique, so for any value/mode pair at most one tarval will + * exist, which will be returned upon further requests with an identical + * value/mode pair. + * + * NOTES + * If the long is not representable in the given mode an assertion is + * thrown. + * + * SEE ALSO + * irmode.h for predefined modes + * new_tarval_from_str + * new_tarval_from_double + * + ******/ -extern tarval *tarval_bad; tarval *get_tarval_bad(void); -/* We should have a tarval_undefined */ -extern tarval *tarval_b_false; tarval *get_tarval_b_false (void); -extern tarval *tarval_b_true; tarval *get_tarval_b_true (void); -extern tarval *tarval_D_NaN; tarval *get_tarval_D_NaN (void); -extern tarval *tarval_D_Inf; tarval *get_tarval_D_Inf (void); -extern tarval *tarval_P_void; tarval *get_tarval_P_void (void); -extern tarval *tarval_mode_null[]; tarval *get_tarval_mode_null(ir_mode *mode); - -/*@{*/ -/** @bug These are not initialized!! Don't use. */ -extern tarval *tarval_mode_min[]; tarval *get_tarval_mode_min (ir_mode *mode); -extern tarval *tarval_mode_max[]; tarval *get_tarval_mode_max (ir_mode *mode); -/*@}*/ - -void tarval_init_1 (void); -void tarval_init_2 (void); - -/*@{*/ -/** Constructors for tarvals */ -tarval *tarval_F_from_str (const char *s, size_t len); -tarval *tarval_D_from_str (const char *s, size_t len); -tarval *tarval_int_from_str (const char *s, size_t len, int base, ir_mode *m); -tarval *tarval_from_long (ir_mode *m, long val); -/*@}*/ - -tarval *tarval_P_from_str (const char *xname); +tarval *new_tarval_from_long(long l, ir_mode *mode); +/** + * This returns a long int with the value represented value, or + * gibberish, depending on the size of long int and the size of the + * stored value. It works for e.g. 1 as mode_Ls, but not for + * get_mode_max(mode_Ls). + * This will overflow silently, so use only if you know what + * you are doing! (better check with tarval_is_long...) + */ +long tarval_to_long(tarval *tv); +/** + * This validates if tarval_to_long will return a satisfying + * result. I.e. if tv is an int_number and between min, max + * of long int (signed!) + */ +int tarval_is_long(tarval *tv); + +/****f* tv/new_tarval_from_double + * + * NAME + * new_tarval_from_double + * Constructor function for new tarvals + * + * SYNOPSIS + * tarval *new_tarval_from_double(const long double d, ir_mode *mode) + * + * DESCRIPTION + * This function creates a new tarval representing the value represented + * by a long double. If a tarval representing this value already exists, + * this tarval is returned instead of a new one. So tarvals are directly + * comparable since their representation is unique. + * + * PARAMETERS + * d - The long double representing the value + * mode - The mode requested for the result tarval + * + * Only modes of sort float_number can be constructed this way. + * + * RESULT + * A tarval of proper type representing the requested value is returned. + * Tarvals are unique, so for any value/mode pair at most one tarval will + * exist, which will be returned upon further requests with an identical + * value/mode pair. + * + * NOTES + * If the long double is not representable in the given mode an assertion + * is thrown. This will happen for any mode not of sort float_number + * + * SEE ALSO + * irmode.h for predefined values + * new_tarval_from_str + * new_tarval_from_long + * + ******/ +tarval *new_tarval_from_double(long double d, ir_mode *mode); +long double tarval_to_double(tarval *tv); +int tarval_is_double(tarval *tv); /* The tarval represents the address of the entity. As the address must be constant the entity must have as owner the global type. */ -tarval *tarval_P_from_entity (entity *ent); - -tarval *tarval_convert_to (tarval *src, ir_mode *m); - -/* Building an irm_C, irm_s, irm_S or irm_B target value step by step. */ -void tarval_start (void); -void tarval_append (const char *p, size_t n); -void tarval_append1 (char ch); -tarval *tarval_finish_as (ir_mode *m); -tarval *tarval_cancel (void); /* returns tarval_bad */ - -/** The flags for projecting a comparison result */ -typedef enum { - irpn_False=0, /**< 0000 false */ - irpn_Eq, /**< 0001 equal */ - irpn_Lt, /**< 0010 less */ - irpn_Le, /**< 0011 less or equal */ - irpn_Gt, /**< 0100 greater */ - irpn_Ge, /**< 0101 greater of equal */ - irpn_Lg, /**< 0110 less or greater */ - irpn_Leg, /**< 0111 less, equal or greater = ordered */ - irpn_Uo, /**< 1000 unordered */ - irpn_Ue, /**< 1001 unordered or equal */ - irpn_Ul, /**< 1010 unordered or less */ - irpn_Ule, /**< 1011 unordered, less or equal */ - irpn_Ug, /**< 1100 unordered or greater */ - irpn_Uge, /**< 1101 unordered, greater or equal */ - irpn_Ne, /**< 1110 unordered, less or greater = not equal */ - irpn_True /**< 1111 true */ - /*irpn_notmask = irpn_Leg @@@ removed for JNI builder */ -} ir_pncmp; -#define irpn_notmask irpn_Leg - -/*@{*/ -/** Arithmethic operations on tarvals */ -tarval *tarval_neg (tarval *a); -tarval *tarval_add (tarval *a, tarval *b); -tarval *tarval_sub (tarval *a, tarval *b); -tarval *tarval_mul (tarval *a, tarval *b); -tarval *tarval_quo (tarval *a, tarval *b); -tarval *tarval_div (tarval *a, tarval *b); -tarval *tarval_mod (tarval *a, tarval *b); -tarval *tarval_abs (tarval *a); -tarval *tarval_and (tarval *a, tarval *b); -tarval *tarval_or (tarval *a, tarval *b); -tarval *tarval_eor (tarval *a, tarval *b); -tarval *tarval_shl (tarval *a, tarval *b); -tarval *tarval_shr (tarval *a, tarval *b); -/*@}*/ - -/** Compare a with b and return an ir_pncmp describing the relation - between a and b. This is either Uo, Lt, Eq, Gt, or False if a or b - are symbolic pointers which can not be compared at all. */ -ir_pncmp tarval_comp (tarval *a, tarval *b); - - -/* Identifying some tarvals */ -long tarval_classify (tarval *tv); -long tarval_ord (tarval *tv, int *fail); - -/*@{*/ -/** return a mode-specific value */ -tarval_F tv_val_F (tarval *tv); -tarval_D tv_val_D (tarval *tv); -tarval_sInt tv_val_sInt (tarval *tv); -tarval_uInt tv_val_uInt (tarval *tv); -/* @@@ temporarily removed. - jni builder can not deal with the return value. - All definitions of types are interpreted as pointer values until - type analysis exists for crecoder. - tarval_p tv_val_p (tarval *tv); -*/ -bool tv_val_b (tarval *tv); -/*@}*/ - -ir_mode *get_tv_mode (tarval *tv); -/** Returns the entity if the tv is a pointer to an entity, else - returns NULL; */ -entity *get_tv_entity(tarval *tv); -/* Removes tarvals that are pointers to ent. */ -void free_tv_entity(entity *ent); - -/** Returns 0 if tv is positive, else > 0. @todo not tested! */ -int tv_is_negative(tarval *a); +tarval *new_tarval_from_entity (entity *ent, ir_mode *mode); +entity *tarval_to_entity(tarval *tv); +int tarval_is_entity(tarval *tv); + +/** ********** Access routines for tarval fields ********** **/ + +/****f* tv/get_tarval_* + * + * NAME + * get_tarval_mode + * get_tarval_ ... + * + * SYNOPSIS + * ir_mode *get_tarval_mode(tarval *tv) + * ... + * + * DESCRIPTION + * These are access function for tarval struct members. It is encouraged + * to use them instead of direct access to the struct fields. + * + * PARAMETERS + * tv - The tarval to access fields of + * + * RESULT + * get_tv_mode: The mode of the tarval + * + * SEE ALSO + * the struct tarval + * + ******/ +/* get the mode of the tarval */ +#ifdef TARVAL_ACCESS_DEFINES +# include "tv_t.h" +# define get_tarval_mode(tv) (tv)->mode +#else +ir_mode *get_tarval_mode (tarval *tv); +#endif +/** Testing properties of the represented values **/ +/* Returns 0 if tv is positive, else > 0. @@@ not tested! */ +int tarval_is_negative(tarval *a); + +/** Some special values **/ +extern tarval *tarval_bad; tarval *get_tarval_bad(void); +extern tarval *tarval_undefined; tarval *get_tarval_undefined(void); +/* These two are the only valid mode_b tarvals! */ +extern tarval *tarval_b_false; tarval *get_tarval_b_false(void); +extern tarval *tarval_b_true; tarval *get_tarval_b_true(void); + +extern tarval *tarval_P_void; tarval *get_tarval_P_void(void); + +/* These functions calculate and return a tarval representing the requested + * value. + * The functions get_mode_{Max,Min,...} return tarvals retrieved from these + * functions, but these are stored on initialization of the irmode module and + * therefore the irmode functions should be prefered to the functions below. */ +tarval *get_tarval_max(ir_mode *mode); +tarval *get_tarval_min(ir_mode *mode); +tarval *get_tarval_null(ir_mode *mode); +tarval *get_tarval_one(ir_mode *mode); +tarval *get_tarval_nan(ir_mode *mode); +tarval *get_tarval_inf(ir_mode *mode); + +/* ******************** Arithmethic operations on tarvals ******************** */ + +/****f* tv/tarval_cmp + * + * NAME + * tarval_cmp + * Compares two tarvals + * + * SYNOPSIS + * pnc_number tarval_comp(tarval *a, tarval *b) + * + * DESCRIPTION + * Compare a with b and return a pnc_number describing the relation + * between a and b. This is either Uo, Lt, Eq, Gt, or False if a or b + * are symbolic pointers which can not be compared at all. + * + * PARAMETERS + * a - A tarval + * b - A tarval + * a and b are tarvals to be compared + * + * RESULT + * The pnc_number best describing the relation between a and b is returned. + * This means the mode with the least bits set is returned, e.g. if the + * tarvals are equal the pnc_number 'Eq' is returned, not 'Ge' which + * indicates 'greater or equal' + * + * SEE ALSO + * irnode.h for the definition of pnc_numbers + * + ******/ +pnc_number tarval_cmp(tarval *a, tarval *b); + +/****f* tv/tarval_convert_to + * + * NAME + * tarval_convert_to + * Converts a tarval to another mode + * + * SYNOPSIS + * tarval *tarval_convert_to(tarval *src, ir_mode *mode) + * + * DESCRIPTION + * Convert tarval 'src' to mode 'mode', this will suceed if and only if mode + * 'mode' is wider than the mode of src, as defined in the firm documentation + * and as returned by the function mode_is_smaller defined in irmode.h. + * + * PARAMETERS + * src - The tarval to convert + * mode - Tho mode to convert to + * + * RESULT + * If a tarval of mode 'mode' with the result of the conversion of the 'src' + * tarvals value already exists, it will be returned, else a new tarval is + * constructed and returned + * + * NOTES + * Illegal conversations will trigger an assertion + * + * SEE ALSO + * FIRM documentation for conversion rules + * mode_is_smaller defined in irmode.h + * + ******/ +tarval *tarval_convert_to(tarval *src, ir_mode *m); + +/****f* tv/tarval_calculations + * + * NAME + * tarval_neg - Negation of a tarval + * tarval_add - Addition of two tarvals + * tarval_sub - Subtraction from a tarval + * tarval_mul - Multiplication of tarvals + * tarval_quo - 'Exact' division + * tarval_div - Integer division + * tarval_mod - Remainder of integer division + * tarval_abs - Absolute value + * tarval_and - Bitwise and + * tarval_or - Bitwise or + * tarval_eor - Bitwise exclusive or + * tarval_shl - Left shift + * tarval_shr - Unsigned right shift + * tarval_shrs - Signed right shift + * tarval_rot - Rotation + * + * SYNOPSIS + * tarval *tarval_neg (tarval *a) + * tarval *tarval_add (tarval *a, tarval *b) + * tarval *tarval_sub (tarval *a, tarval *b) + * tarval *tarval_mul (tarval *a, tarval *b) + * tarval *tarval_quo (tarval *a, tarval *b) + * tarval *tarval_div (tarval *a, tarval *b) + * tarval *tarval_mod (tarval *a, tarval *b) + * tarval *tarval_abs (tarval *a) + * tarval *tarval_and (tarval *a, tarval *b) + * tarval *tarval_or (tarval *a, tarval *b) + * tarval *tarval_eor (tarval *a, tarval *b) + * tarval *tarval_shl (tarval *a, tarval *b) + * tarval *tarval_shr (tarval *a, tarval *b) + * tarval *tarval_shrs(tarval *a, tarval *b) + * tarval *tarval_rot (tarval *a, tarval *b) + * + * DESCRIPTION + * These function implement basic computations representable as opcodes + * in FIRM nodes. + * + * PARAMETERS + * tarval_neg: + * traval_abs: + * a - the tarval to operate on + * + * all oters: + * a - the first operand tarval + * b - the second operand tarval + * + * RESULT + * If neccessary a new tarval is constructed for the resulting value, + * or the one already carrying the computation result is retrieved and + * returned as result. + * + * NOTES + * The order the arguments are given in is important, imagine postfix + * notation. + * Illegal operations will trigger an assertion. + * The sort member of the struct mode defines which operations are valid + * + ******/ +tarval *tarval_neg(tarval *a); /* negation */ +tarval *tarval_add(tarval *a, tarval *b); /* addition */ +tarval *tarval_sub(tarval *a, tarval *b); /* subtraction */ +tarval *tarval_mul(tarval *a, tarval *b); /* multiplication */ +tarval *tarval_quo(tarval *a, tarval *b); /* floating point division */ +tarval *tarval_div(tarval *a, tarval *b); /* integer division */ +tarval *tarval_mod(tarval *a, tarval *b); /* remainder */ +tarval *tarval_abs(tarval *a); /* absolute value */ +tarval *tarval_and(tarval *a, tarval *b); /* bitwise and */ +tarval *tarval_or (tarval *a, tarval *b); /* bitwise or */ +tarval *tarval_eor(tarval *a, tarval *b); /* bitwise exclusive or (xor) */ +tarval *tarval_shl(tarval *a, tarval *b); /* bitwise left shift */ +tarval *tarval_shr(tarval *a, tarval *b); /* bitwise unsigned right shift */ +tarval *tarval_shrs(tarval *a, tarval *b); /* bitwise signed right shift */ +tarval *tarval_rot(tarval *a, tarval *b); /* bitwise rotation */ + +/** *********** Output of tarvals *********** **/ +/****f* tv/tarval_bitpattern + * + * NAME + * tarval_bitpattern + * Bit representation of a tarval value, as string of '0' and '1' + * + * SYNOPSIS + * char *tarval_bitpattern(tarval *tv) + * + * DESCRIPTION + * This function returns a printable bit representation of any value + * stored as tarval. This representation is a null terminated C string. + * + * PARAMETERS + * tv - The tarval + * + * RESULT + * As usual in C a pointer to a char is returned. The length of the + * returned string if fixed, just read as many chars as the mode defines + * as size. + * + * NOTE + * The string is allocated using malloc() and is free()ed on the next call + * of this function. + * The string consists of the ascii characters '0' and '1' and is + * null terminated + * + * SEE ALSO + * irmode.h for the definition of the ir_mode struct + * the size member of aforementioned struct + * + ******/ +char *tarval_bitpattern(tarval *tv); + +/* Identifying some tarvals ??? */ +/* This function is deprecated and its use strongly discouraged */ +long tarval_classify(tarval *tv); + +/** Initialization of the tarval module **/ +void init_tarval_1(void); /* call before init_mode */ +void init_tarval_2(void); /* call after init_mode */ + #endif /* _TV_H_ */ diff --git a/ir/tv/tv_t.h b/ir/tv/tv_t.h index 6400829d8..1ea32e49c 100644 --- a/ir/tv/tv_t.h +++ b/ir/tv/tv_t.h @@ -12,26 +12,38 @@ #ifndef _TV_T_H_ #define _TV_T_H_ -# include "tv.h" -# include "misc.h" - +#include "tv.h" +#include "xprintf.h" + +/****s* tv/tarval + * + * NAME + * tarval + * This struct represents the aforementioned tarvals. + * + * DESCRIPTION + * A tarval struct consists of an internal representation of the + * value and some additional fields further describing the value. + * + * ATTRIBUTES + * ir_mode *mode The mode of the stored value + * void *value The internal representation + * + * SEE ALSO + * irmode.h for predefined modes + * + ******/ + +struct tarval { + ir_mode *mode; /* mode of the stored value */ + const void *value; /* the value stored in an internal way... */ + unsigned int length; /* the length of the stored value */ +}; + +/* xfprint output */ int tarval_print (XP_PAR1, const xprintf_info *, XP_PARN); -/** Hash function on tarvals */ -unsigned tarval_hash (tarval *); - - -#ifdef NDEBUG -#define TARVAL_VRFY(val) ((void)0) -#else -#define TARVAL_VRFY(val) _tarval_vrfy ((val)) -extern void _tarval_vrfy (const tarval *); -#endif - -#ifdef STATS -void tarval_stats (void); -#else -#define tarval_stats() ((void)0) -#endif +/** remove tarval representing an entity that is about to be destroyed */ +void free_tarval_entity(entity *ent); #endif /* _TV_T_H_ */ -- 2.20.1