X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Ftv%2Ftv.c;h=b6bb7709459d0a72ccd5b96639b6373cfd541c59;hb=89ecd499372006196a4c2f63a5e719b5f1288572;hp=01125de313bbca55b086949f89941f6aa860c8cc;hpb=4f262a24ef237a6c7f5562dce572dcacfeb40245;p=libfirm diff --git a/ir/tv/tv.c b/ir/tv/tv.c index 01125de31..b6bb77094 100644 --- a/ir/tv/tv.c +++ b/ir/tv/tv.c @@ -1,1434 +1,1771 @@ -/* TV --- Target Values, aka Constant Table. - Copyright (C) 1995, 1996 Christian von Roques */ - -/* $Id$ */ - -/* 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. */ - -#ifdef HAVE_CONFIG_H -# include -#endif +/* + * Copyright (C) 1995-2011 University of Karlsruhe. All right reserved. + * + * This file is part of libFirm. + * + * This file may be distributed and/or modified under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation and appearing in the file LICENSE.GPL included in the + * packaging of this file. + * + * Licensees holding valid libFirm Professional Edition licenses may use + * this file in accordance with the libFirm Commercial License. + * Agreement provided with the Software. + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE. + */ + +/** + * @file + * @brief Representation of and static computations on target machine + * values. + * @date 2003 + * @author Mathias Heil + * @brief + * + * Values are stored in a format depending upon chosen arithmetic + * module. Default uses strcalc and fltcalc. + * This implementation assumes: + * - target has IEEE-754 floating-point arithmetic. + */ +#include "config.h" -# 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 +#include + +#include "bitfiddle.h" #include "tv_t.h" +#include "set.h" #include "entity_t.h" -#include "ident_t.h" -#include "irmode.h" - -static struct obstack tv_obst; /* obstack for all the target values */ -static pset *tarvals; /* pset containing pointers to _all_ tarvals */ - -/* currently building an object with tarval_start() & friends ? */ -#define BUILDING obstack_object_size (&tv_obst) - -/* bcopy is not ISO C */ -#define bcopy(X, Y, Z) memcpy((Y), (X), (Z)) - - -/* 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 +#include "irmode_t.h" +#include "irnode.h" +#include "strcalc.h" +#include "fltcalc.h" +#include "util.h" +#include "xmalloc.h" +#include "firm_common.h" +#include "error.h" + +/** Size of hash tables. Should correspond to average number of distinct constant + target values */ +#define N_CONSTANTS 2048 + +/* unused, float to int doesn't work yet */ +typedef enum float_to_int_mode { + TRUNCATE, + ROUND +} float_to_int_mode; + +static float_to_int_mode current_float_to_int_mode = TRUNCATE; + +/* set this to true if infinity should be clipped to +/- MAX_FLOAT */ +#define SWITCH_NOINFINITY 0 +/* set this to true if denormals should be clipped to zero */ +#define SWITCH_NODENORMALS 0 + +/**************************************************************************** + * local definitions and macros + ****************************************************************************/ +#ifndef NDEBUG +# define TARVAL_VERIFY(a) tarval_verify((a)) +#else +# define TARVAL_VERIFY(a) ((void)0) +#endif + +#define INSERT_TARVAL(tv) ((ir_tarval*)set_insert(tarvals, (tv), sizeof(ir_tarval), hash_tv((tv)))) +#define FIND_TARVAL(tv) ((ir_tarval*)set_find(tarvals, (tv), sizeof(ir_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))) + +#define fail_verify(a) _fail_verify((a), __FILE__, __LINE__) + +/** A set containing all existing tarvals. */ +static struct set *tarvals = NULL; +/** A set containing all existing values. */ +static struct set *values = NULL; + +/** The carry flag for SOME operations. -1 means UNDEFINED here */ +static int carry_flag = -1; + +/** The integer overflow mode. */ +static tarval_int_overflow_mode_t int_overflow_mode = TV_OVERFLOW_WRAP; -/* Used to be in irmode.h, replaced now. */ -# define is_Int(m) ((m) <= irm_Lu && (m) >= irm_Bs) /* old */ +/** if this is set non-zero, the constant folding for floating point is OFF */ +static int no_float = 0; -/* return a mode-specific value */ +/**************************************************************************** + * private functions + ****************************************************************************/ +#ifndef NDEBUG +static unsigned hash_val(const void *value, size_t length); +static unsigned hash_tv(ir_tarval *tv); +static void _fail_verify(ir_tarval *tv, const char* file, int line) +{ + /* print a memory image of the tarval and throw an assertion */ + if (tv) + panic("%s:%d: Invalid tarval: mode: %F\n value: [%p]", file, line, tv->mode, tv->value); + else + panic("%s:%d: Invalid tarval (null)", file, line); +} -tarval_F -tv_val_F (tarval *tv) +inline static +#ifdef __GNUC__ + __attribute__((unused)) +#endif +void tarval_verify(ir_tarval *tv) { - return tv->u.F; + assert(tv); + assert(tv->mode); + assert(tv->value); + + 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); +} +#endif /* NDEBUG */ + +/** Hash a tarval. */ +static unsigned hash_tv(ir_tarval *tv) +{ + return (unsigned)((PTR_TO_INT(tv->value) ^ PTR_TO_INT(tv->mode)) + tv->length); +} + +/** Hash a value. Treat it as a byte array. */ +static unsigned hash_val(const void *value, size_t length) +{ + size_t i; + unsigned 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_D -tv_val_D (tarval *tv) +static int cmp_tv(const void *p1, const void *p2, size_t n) { - return tv->u.D; + const ir_tarval *tv1 = (const ir_tarval*) p1; + const ir_tarval *tv2 = (const ir_tarval*) p2; + (void) n; + + assert(tv1->kind == k_tarval); + assert(tv2->kind == k_tarval); + if (tv1->mode < tv2->mode) + return -1; + if (tv1->mode > tv2->mode) + return 1; + if (tv1->length < tv2->length) + return -1; + if (tv1->length > tv2->length) + return 1; + if (tv1->value < tv2->value) + return -1; + if (tv1->value > tv2->value) + return 1; + + return 0; } -tarval_E -tv_val_E (tarval *tv) +/** finds tarval with value/mode or creates new tarval */ +static ir_tarval *get_tarval(const void *value, size_t length, ir_mode *mode) { - return tv->u.E; + ir_tarval tv; + + tv.kind = k_tarval; + 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 */ + char *temp = (char*) alloca(length); + memcpy(temp, value, length); + if (get_mode_arithmetic(mode) == irma_twos_complement) { + sign_extend(temp, mode); + } + tv.value = INSERT_VALUE(temp, length); + } else { + tv.value = value; + } + /* if there is such a tarval, it is returned, else tv is copied + * into the set */ + return (ir_tarval *)INSERT_TARVAL(&tv); } -tarval_sInt -tv_val_sInt (tarval *tv) +/** + * handle overflow + */ +static ir_tarval *get_tarval_overflow(const void *value, size_t length, ir_mode *mode) { - return tv->u.sInt; + char *temp; + + switch (get_mode_sort(mode)) { + case irms_reference: + /* addresses always wrap around */ + temp = (char*) alloca(sc_get_buffer_length()); + memcpy(temp, value, sc_get_buffer_length()); + sc_truncate(get_mode_size_bits(mode), temp); + /* the sc_ module expects that all bits are set ... */ + sign_extend(temp, mode); + return get_tarval(temp, length, mode); + + case irms_int_number: + if (sc_comp(value, get_mode_max(mode)->value) == 1) { + switch (tarval_get_integer_overflow_mode()) { + case TV_OVERFLOW_SATURATE: + return get_mode_max(mode); + case TV_OVERFLOW_WRAP: + temp = (char*) alloca(sc_get_buffer_length()); + memcpy(temp, value, sc_get_buffer_length()); + sc_truncate(get_mode_size_bits(mode), temp); + /* the sc_ module expects that all bits are set ... */ + sign_extend(temp, mode); + return get_tarval(temp, length, mode); + case TV_OVERFLOW_BAD: + return tarval_bad; + default: + return get_tarval(value, length, mode); + } + } + if (sc_comp(value, get_mode_min(mode)->value) == -1) { + switch (tarval_get_integer_overflow_mode()) { + case TV_OVERFLOW_SATURATE: + return get_mode_min(mode); + case TV_OVERFLOW_WRAP: { + temp = (char*) alloca(sc_get_buffer_length()); + memcpy(temp, value, sc_get_buffer_length()); + sc_truncate(get_mode_size_bits(mode), temp); + return get_tarval(temp, length, mode); + } + case TV_OVERFLOW_BAD: + return tarval_bad; + default: + return get_tarval(value, length, mode); + } + } + break; + + case irms_float_number: +#if SWITCH_NOINFINITY + if (fc_is_inf((const fp_value*) value)) { + /* clip infinity to maximum value */ + return fc_is_negative((const fp_value*) value) ? get_mode_min(mode) : get_mode_max(mode); + } +#endif +#if SWITCH_NODENORMALS + if (fc_is_subnormal((const fp_value*) value)) { + /* clip denormals to zero */ + return get_mode_null(mode); + } +#endif + break; + + default: + break; + } + return get_tarval(value, length, mode); } -tarval_uInt -tv_val_uInt (tarval *tv) +/* + * public variables declared in tv.h + */ +static ir_tarval reserved_tv[6]; + +ir_tarval *tarval_b_false = &reserved_tv[0]; +ir_tarval *tarval_b_true = &reserved_tv[1]; +ir_tarval *tarval_bad = &reserved_tv[2]; +ir_tarval *tarval_undefined = &reserved_tv[3]; +ir_tarval *tarval_reachable = &reserved_tv[4]; +ir_tarval *tarval_unreachable = &reserved_tv[5]; + +/** + * get the float descriptor for given mode. + */ +static const float_descriptor_t *get_descriptor(const ir_mode *mode) { - return tv->u.uInt; + return &mode->float_desc; } -tarval_P -tv_val_P (tarval *tv) +ir_tarval *new_integer_tarval_from_str(const char *str, size_t len, char sign, + unsigned char base, ir_mode *mode) { - return tv->u.P; + void *buffer; + int ok; + + buffer = alloca(sc_get_buffer_length()); + + ok = sc_val_from_str(sign, base, str, len, buffer); + if (!ok) + return tarval_bad; + + return get_tarval_overflow(buffer, sc_get_buffer_length(), mode); } -bool -tv_val_b (tarval *tv) +static ir_tarval *new_tarval_from_str_int(const char *str, size_t len, + ir_mode *mode) { - return tv->u.b; + void *buffer; + unsigned base = 10; + char sign = 1; + int ok; + + /* skip leading spaces */ + while (len > 0 && str[0] == ' ') { + ++str; + --len; + } + if (len == 0) + return tarval_bad; + + /* 1 sign character allowed */ + if (str[0] == '-') { + sign = -1; + ++str; + --len; + } else if (str[0] == '+') { + ++str; + --len; + } + + /* a number starting with '0x' is hexadeciaml, + * a number starting with '0' (and at least 1 more char) is octal */ + if (len >= 2 && str[0] == '0') { + if (str[1] == 'x' || str[1] == 'X') { + str += 2; + len -= 2; + base = 16; + } else { + ++str; + --len; + base = 8; + } + } + if (len == 0) + return tarval_bad; + + buffer = alloca(sc_get_buffer_length()); + + ok = sc_val_from_str(sign, base, str, len, buffer); + if (!ok) + return tarval_bad; + + return get_tarval_overflow(buffer, sc_get_buffer_length(), mode); } +/* + * Constructors ============================================================= + */ +ir_tarval *new_tarval_from_str(const char *str, size_t len, ir_mode *mode) +{ + const float_descriptor_t *desc; + + assert(str); + assert(len); + assert(mode); + + switch (get_mode_sort(mode)) { + case irms_internal_boolean: + /* match [tT][rR][uU][eE]|[fF][aA][lL][sS][eE] */ + if (!strcasecmp(str, "true")) + return tarval_b_true; + else if (!strcasecmp(str, "false")) + return tarval_b_false; + else + /* XXX This is C semantics */ + return atoi(str) ? tarval_b_true : tarval_b_false; + + case irms_float_number: + desc = get_descriptor(mode); + fc_val_from_str(str, len, desc, NULL); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode); + + case irms_reference: + if (!strcasecmp(str, "null")) + return get_tarval_null(mode); + /* FALLTHROUGH */ + case irms_int_number: + return new_tarval_from_str_int(str, len, mode); + default: + panic("Unsupported tarval creation with mode %F", mode); + } +} -/* Overflows `sInt' signed integral `mode'? */ -static INLINE bool -sInt_overflow (tarval_sInt sInt, ir_mode *mode) +/* + * helper function, create a tarval from long + */ +ir_tarval *new_tarval_from_long(long l, 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)); + assert(mode); + + switch (get_mode_sort(mode)) { + case irms_internal_boolean: + /* XXX C semantics ! */ + return l ? tarval_b_true : tarval_b_false ; + + case irms_reference: + /* same as integer modes */ + case irms_int_number: + sc_val_from_long(l, NULL); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), mode); + + case irms_float_number: + return new_tarval_from_double((long double)l, mode); + + default: + panic("unsupported mode sort"); + } } +/* returns non-zero if can be converted to long */ +int tarval_is_long(ir_tarval *tv) +{ + if (!mode_is_int(tv->mode) && !mode_is_reference(tv->mode)) + return 0; + + if (get_mode_size_bits(tv->mode) > (int) (sizeof(long) << 3)) { + /* the value might be too big to fit in a long */ + sc_max_from_bits(sizeof(long) << 3, 0, NULL); + if (sc_comp(sc_get_buffer(), tv->value) == -1) { + /* really doesn't fit */ + return 0; + } + } + return 1; +} -/* Overflows `uInt' unsigned integral `mode'? */ -static INLINE bool -uInt_overflow (tarval_uInt uInt, ir_mode *mode) +/* this might overflow the machine's long, so use only with small values */ +long get_tarval_long(ir_tarval* tv) { - 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); + assert(tarval_is_long(tv) && "tarval too big to fit in long"); + + return sc_val_to_long(tv->value); } +ir_tarval *new_tarval_from_long_double(long double d, ir_mode *mode) +{ + const float_descriptor_t *desc; -#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); - } + assert(mode && (get_mode_sort(mode) == irms_float_number)); + desc = get_descriptor(mode); + fc_val_from_ieee754(d, desc, NULL); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode); } -#endif +ir_tarval *new_tarval_from_double(double d, ir_mode *mode) +{ + return new_tarval_from_long_double(d, mode); +} + +/* returns non-zero if can be converted to double */ +int tarval_is_double(ir_tarval *tv) +{ + assert(tv); -#ifdef STATS + return (get_mode_sort(tv->mode) == irms_float_number); +} -static void -tarval_stats (void) +long double get_tarval_long_double(ir_tarval *tv) { - pset_stats (tarvals); + assert(tarval_is_double(tv)); + + return fc_val_to_ieee754((const fp_value*) tv->value); } -#endif +double get_tarval_double(ir_tarval *tv) +{ + return get_tarval_long_double(tv); +} -/* Return the canonical tarval * for tv. - May destroy everything allocated on tv_obst after tv! */ -static tarval * -tarval_identify (tarval *tv) -{ - tarval *o; - - o = pset_insert (tarvals, tv, tarval_hash (tv)); - - if (o != tv) { - obstack_free (&tv_obst, (void *)tv); - } - - TARVAL_VRFY (o); - return o; -} - - -/* 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 ((void *)a->mode - (void *)b->mode) - return (void *)a->mode - (void *)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); - } -} - - -unsigned -tarval_hash (tarval *tv) -{ - 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; -} - - -/*** ***************** Initialization ************************************* ***/ - -void -tarval_init_1 (void) -{ - obstack_init (&tv_obst); - obstack_alignment_mask (&tv_obst) = ALIGNOF (tarval) - 1; - assert (IS_POW2 (ALIGNOF (tarval))); - - /* initialize the target value table */ - tarvals = new_pset (tarval_cmp, TUNE_NCONSTANTS); -} - -void -tarval_init_2 (void) -{ - 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)); +/* + * Access routines for tarval fields ======================================== + */ +/* get the mode of the tarval */ +ir_mode *(get_tarval_mode)(const ir_tarval *tv) +{ + return _get_tarval_mode(tv); +} - 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; +/* + * 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 preferred to the functions below. + */ + +ir_tarval *(get_tarval_bad)(void) +{ + return _get_tarval_bad(); } +ir_tarval *(get_tarval_undefined)(void) +{ + return _get_tarval_undefined(); +} -/*** ********************** Constructors for tarvals ********************** ***/ +ir_tarval *(get_tarval_b_false)(void) +{ + return _get_tarval_b_false(); +} -/* copy from src to dst len chars omitting '_'. */ -static char * -stripcpy (char *dst, const char *src, size_t len) +ir_tarval *(get_tarval_b_true)(void) { - char *d = dst; + return _get_tarval_b_true(); +} - while (len--) { - if (*src == '_') src++; - else *d++ = *src++; - } - *d = 0; /* make it 0-terminated. */ +ir_tarval *(get_tarval_reachable)(void) +{ + return _get_tarval_reachable(); +} - return dst; +ir_tarval *(get_tarval_unreachable)(void) +{ + return _get_tarval_unreachable(); } -tarval * -tarval_F_from_str (const char *s, size_t len) -{ - tarval *tv; - char *buf; - char *eptr; - - assert (!BUILDING); - - buf = alloca (len+1); - stripcpy (buf, s, len); - - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = mode_F; - tv->u.F = (float)strtod (buf, &eptr); - assert (eptr == buf+strlen(buf)); +ir_tarval *get_tarval_max(ir_mode *mode) +{ + const float_descriptor_t *desc; + + switch (get_mode_sort(mode)) { + case irms_internal_boolean: + return tarval_b_true; + + case irms_float_number: + desc = get_descriptor(mode); + fc_get_max(desc, NULL); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode); + + case irms_reference: + case irms_int_number: + sc_max_from_bits(get_mode_size_bits(mode), mode_is_signed(mode), NULL); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), mode); + default: + panic("mode %F does not support maximum value", mode); + } +} - return tarval_identify (tv); +ir_tarval *get_tarval_min(ir_mode *mode) +{ + const float_descriptor_t *desc; + + switch (get_mode_sort(mode)) { + case irms_internal_boolean: + return tarval_b_false; + + case irms_float_number: + desc = get_descriptor(mode); + fc_get_min(desc, NULL); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode); + + case irms_reference: + case irms_int_number: + sc_min_from_bits(get_mode_size_bits(mode), mode_is_signed(mode), NULL); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), mode); + default: + panic("mode %F does not support minimum value", mode); + } } +/** The bit pattern for the pointer NULL */ +static long _null_value = 0; -tarval * -tarval_D_from_str (const char *s, size_t len) +ir_tarval *get_tarval_null(ir_mode *mode) { - tarval *tv; - char *buf; - char *eptr; + switch (get_mode_sort(mode)) { + case irms_float_number: + return new_tarval_from_double(0.0, mode); + + case irms_internal_boolean: + case irms_int_number: + return new_tarval_from_long(0l, mode); + + case irms_reference: + return new_tarval_from_long(_null_value, mode); + default: + panic("mode %F does not support null value", mode); + } +} - assert (!BUILDING); +ir_tarval *get_tarval_one(ir_mode *mode) +{ + switch (get_mode_sort(mode)) { + case irms_internal_boolean: + return tarval_b_true; + + case irms_float_number: + return new_tarval_from_double(1.0, mode); + + case irms_reference: + case irms_int_number: + return new_tarval_from_long(1l, mode); + default: + panic("mode %F does not support one value", mode); + } +} - buf = alloca (len+1); - stripcpy (buf, s, len); +ir_tarval *get_tarval_all_one(ir_mode *mode) +{ + switch (get_mode_sort(mode)) { + case irms_int_number: + case irms_internal_boolean: + case irms_reference: + return tarval_not(get_mode_null(mode)); + + case irms_float_number: + return new_tarval_from_double(1.0, mode); + + default: + panic("mode %F does not support all-one value", mode); + } +} - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = mode_D; - tv->u.D = strtod (buf, &eptr); - assert (eptr == buf+strlen(buf)); +int tarval_is_constant(ir_tarval *tv) +{ + size_t const num_res = ARRAY_SIZE(reserved_tv); - return tarval_identify (tv); + /* reserved tarvals are NOT constants. Note that although + tarval_b_true and tarval_b_false are reserved, they are constants of course. */ + return (tv < &reserved_tv[2] || tv > &reserved_tv[num_res - 1]); } -tarval * -tarval_int_from_str (const char *s, size_t len, int base, ir_mode *m) +ir_tarval *get_tarval_minus_one(ir_mode *mode) { - long val; - char *eptr; - char *buf; + switch (get_mode_sort(mode)) { + case irms_reference: + return tarval_bad; + + case irms_float_number: + return mode_is_signed(mode) ? new_tarval_from_double(-1.0, mode) : tarval_bad; - assert (mode_is_int(m)); - assert (!BUILDING); + case irms_int_number: + return new_tarval_from_long(-1l, mode); - buf = alloca (len+1); - stripcpy (buf, s, len); + default: + panic("mode %F does not support minus one value", mode); + } +} + +ir_tarval *get_tarval_nan(ir_mode *mode) +{ + const float_descriptor_t *desc; + + if (get_mode_sort(mode) == irms_float_number) { + desc = get_descriptor(mode); + fc_get_qnan(desc, NULL); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode); + } else + panic("mode %F does not support NaN value", mode); +} - 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); - } +ir_tarval *get_tarval_plus_inf(ir_mode *mode) +{ + if (get_mode_sort(mode) == irms_float_number) { + const float_descriptor_t *desc = get_descriptor(mode); + fc_get_plusinf(desc, NULL); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode); + } else + panic("mode %F does not support +inf value", mode); +} - return tarval_from_long(m, val); +ir_tarval *get_tarval_minus_inf(ir_mode *mode) +{ + if (get_mode_sort(mode) == irms_float_number) { + const float_descriptor_t *desc = get_descriptor(mode); + fc_get_minusinf(desc, NULL); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode); + } else + panic("mode %F does not support -inf value", mode); } -/* 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) +/* + * Arithmetic operations on tarvals ======================================== + */ + +/* + * test if negative number, 1 means 'yes' + */ +int tarval_is_negative(ir_tarval *a) { - tarval *tv; + switch (get_mode_sort(a->mode)) { + case irms_int_number: + if (!mode_is_signed(a->mode)) return 0; + else + return sc_comp(a->value, get_mode_null(a->mode)->value) == -1 ? 1 : 0; + + case irms_float_number: + return fc_is_negative((const fp_value*) a->value); + + default: + panic("mode %F does not support negation value", a->mode); + } +} - assert (!BUILDING); +/* + * test if null, 1 means 'yes' + */ +int tarval_is_null(ir_tarval *a) +{ + return + a != tarval_bad && + a == get_mode_null(get_tarval_mode(a)); +} - if (m == mode_T) return tarval_bad; +/* + * test if one, 1 means 'yes' + */ +int tarval_is_one(ir_tarval *a) +{ + return + a != tarval_bad && + a == get_mode_one(get_tarval_mode(a)); +} - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); +int tarval_is_all_one(ir_tarval *tv) +{ + return + tv != tarval_bad && + tv == get_mode_all_one(get_tarval_mode(tv)); +} - 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); - } +/* + * test if one, 1 means 'yes' + */ +int tarval_is_minus_one(ir_tarval *a) +{ + return + a != tarval_bad && + a == get_mode_minus_one(get_tarval_mode(a)); +} - return tarval_identify (tv); +/* + * comparison + */ +ir_relation tarval_cmp(ir_tarval *a, ir_tarval *b) +{ + carry_flag = -1; + + if (a == tarval_bad || b == tarval_bad) { + panic("Comparison with tarval_bad"); + } + + if (a == tarval_undefined || b == tarval_undefined) + return ir_relation_false; + + if (a->mode != b->mode) + return ir_relation_false; + + /* Here the two tarvals are unequal and of the same mode */ + switch (get_mode_sort(a->mode)) { + case irms_float_number: + /* + * BEWARE: we cannot compare a == b here, because + * a NaN is always Unordered to any other value, even to itself! + */ + switch (fc_comp((const fp_value*) a->value, (const fp_value*) b->value)) { + case -1: return ir_relation_less; + case 0: return ir_relation_equal; + case 1: return ir_relation_greater; + case 2: return ir_relation_unordered; + default: return ir_relation_false; + } + case irms_reference: + case irms_int_number: + if (a == b) + return ir_relation_equal; + return sc_comp(a->value, b->value) == 1 ? ir_relation_greater : ir_relation_less; + + case irms_internal_boolean: + if (a == b) + return ir_relation_equal; + return a == tarval_b_true ? ir_relation_greater : ir_relation_less; + + default: + panic("can't compare values of mode %F", a->mode); + } } +/* + * convert to other mode + */ +ir_tarval *tarval_convert_to(ir_tarval *src, ir_mode *dst_mode) +{ + char *buffer; + fp_value *res = NULL; + const float_descriptor_t *desc; + int len; + + carry_flag = -1; + + assert(src); + assert(dst_mode); + + if (src->mode == dst_mode) + return src; + + switch (get_mode_sort(src->mode)) { + /* cast float to something */ + case irms_float_number: + switch (get_mode_sort(dst_mode)) { + case irms_float_number: + desc = get_descriptor(dst_mode); + fc_cast((const fp_value*) src->value, desc, NULL); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), dst_mode); + + case irms_int_number: + switch (current_float_to_int_mode) { + case TRUNCATE: + res = fc_int((const fp_value*) src->value, NULL); + break; + case ROUND: + res = fc_rnd((const fp_value*) src->value, NULL); + break; + } + buffer = (char*) alloca(sc_get_buffer_length()); + if (! fc_flt2int(res, buffer, dst_mode)) + return tarval_bad; + return get_tarval(buffer, sc_get_buffer_length(), dst_mode); + + default: + break; + } + /* the rest can't be converted */ + return tarval_bad; + + /* cast int/characters to something */ + case irms_int_number: + switch (get_mode_sort(dst_mode)) { + + case irms_reference: + case irms_int_number: + buffer = (char*) alloca(sc_get_buffer_length()); + memcpy(buffer, src->value, sc_get_buffer_length()); + return get_tarval_overflow(buffer, src->length, dst_mode); + + case irms_internal_boolean: + /* XXX C semantics */ + if (src == get_mode_null(src->mode)) return tarval_b_false; + else return tarval_b_true; + + case irms_float_number: + /* XXX floating point unit does not understand internal integer + * representation, convert to string first, then create float from + * string */ + buffer = (char*) alloca(100); + /* decimal string representation because hexadecimal output is + * interpreted unsigned by fc_val_from_str, so this is a HACK */ + len = snprintf(buffer, 100, "%s", + sc_print(src->value, get_mode_size_bits(src->mode), SC_DEC, mode_is_signed(src->mode))); + buffer[100 - 1] = '\0'; + desc = get_descriptor(dst_mode); + fc_val_from_str(buffer, len, desc, NULL); + return get_tarval(fc_get_buffer(), fc_get_buffer_length(), dst_mode); + + default: + break; + } + break; + + case irms_internal_boolean: + /* beware: this is C semantic for the INTERNAL boolean mode */ + if (get_mode_sort(dst_mode) == irms_int_number) + return src == tarval_b_true ? get_mode_one(dst_mode) : get_mode_null(dst_mode); + break; + + case irms_reference: + if (get_mode_sort(dst_mode) == irms_int_number) { + buffer = (char*) alloca(sc_get_buffer_length()); + memcpy(buffer, src->value, sc_get_buffer_length()); + sign_extend(buffer, src->mode); + return get_tarval_overflow(buffer, src->length, dst_mode); + } + break; + default: + return tarval_bad; + } + + return tarval_bad; +} -tarval * -tarval_P_from_str (const char *xname) +/* + * bitwise negation + */ +ir_tarval *tarval_not(ir_tarval *a) { - tarval *tv; + char *buffer; - assert (!BUILDING); + carry_flag = -1; - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); + /* works for vector mode without changes */ - 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); + switch (get_mode_sort(a->mode)) { + case irms_reference: + case irms_int_number: + buffer = (char*) alloca(sc_get_buffer_length()); + sc_not(a->value, buffer); + return get_tarval(buffer, a->length, a->mode); + + case irms_internal_boolean: + if (a == tarval_b_true) + return tarval_b_false; + if (a == tarval_b_false) + return tarval_b_true; + return tarval_bad; + + default: + panic("bitwise negation is only allowed for integer and boolean"); + } } +/* + * arithmetic negation + */ +ir_tarval *tarval_neg(ir_tarval *a) +{ + char *buffer; + + assert(mode_is_num(a->mode)); /* negation only for numerical values */ + + carry_flag = -1; + + /* note: negation is allowed even for unsigned modes. */ + + switch (get_mode_sort(a->mode)) { + case irms_int_number: + buffer = (char*) alloca(sc_get_buffer_length()); + sc_neg(a->value, buffer); + return get_tarval_overflow(buffer, a->length, a->mode); + + case irms_float_number: + /* it should be safe to enable this even if other arithmetic is disabled */ + /*if (no_float) + return tarval_bad;*/ + + fc_neg((const fp_value*) a->value, NULL); + return get_tarval_overflow(fc_get_buffer(), fc_get_buffer_length(), a->mode); -tarval * -tarval_P_from_entity (entity *ent) + default: + return tarval_bad; + } +} + +/* + * addition + */ +ir_tarval *tarval_add(ir_tarval *a, ir_tarval *b) { - tarval *tv; + char *buffer; + + carry_flag = -1; + + if (mode_is_reference(a->mode) && a->mode != b->mode) { + b = tarval_convert_to(b, a->mode); + } else if (mode_is_reference(b->mode) && b->mode != a->mode) { + a = tarval_convert_to(a, b->mode); + } - assert (!BUILDING); + assert(a->mode == b->mode); - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); + switch (get_mode_sort(a->mode)) { + case irms_reference: + case irms_int_number: + /* modes of a,b are equal, so result has mode of a as this might be the character */ + buffer = (char*) alloca(sc_get_buffer_length()); + sc_add(a->value, b->value, buffer); + carry_flag = sc_get_bit_at(buffer, get_mode_size_bits(a->mode)); + return get_tarval_overflow(buffer, a->length, a->mode); - tv->mode = mode_P; - tv->u.P.xname = NULL; - tv->u.P.ent = ent; - tv->u.P.tv = NULL; - return tarval_identify (tv); + case irms_float_number: + if (no_float) + return tarval_bad; + + fc_add((const fp_value*) a->value, (const fp_value*) b->value, NULL); + return get_tarval_overflow(fc_get_buffer(), fc_get_buffer_length(), a->mode); + + default: + return tarval_bad; + } } +/* + * subtraction + */ +ir_tarval *tarval_sub(ir_tarval *a, ir_tarval *b, ir_mode *dst_mode) +{ + char *buffer; + + carry_flag = -1; + + if (dst_mode != NULL) { + if (a->mode != dst_mode) + a = tarval_convert_to(a, dst_mode); + if (b->mode != dst_mode) + b = tarval_convert_to(b, dst_mode); + } + assert(a->mode == b->mode); + + switch (get_mode_sort(a->mode)) { + case irms_reference: + case irms_int_number: + /* modes of a,b are equal, so result has mode of a as this might be the character */ + buffer = (char*) alloca(sc_get_buffer_length()); + sc_sub(a->value, b->value, buffer); + carry_flag = sc_get_bit_at(buffer, get_mode_size_bits(a->mode)); + return get_tarval_overflow(buffer, a->length, a->mode); + + case irms_float_number: + if (no_float) + return tarval_bad; + + fc_sub((const fp_value*) a->value, (const fp_value*) b->value, NULL); + return get_tarval_overflow(fc_get_buffer(), fc_get_buffer_length(), a->mode); + + default: + return tarval_bad; + } +} + +/* + * multiplication + */ +ir_tarval *tarval_mul(ir_tarval *a, ir_tarval *b) +{ + char *buffer; + + assert(a->mode == b->mode); + + carry_flag = -1; + + switch (get_mode_sort(a->mode)) { + case irms_int_number: + /* modes of a,b are equal */ + buffer = (char*) alloca(sc_get_buffer_length()); + sc_mul(a->value, b->value, buffer); + return get_tarval_overflow(buffer, a->length, a->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() */ + case irms_float_number: + if (no_float) + return tarval_bad; -/* Begin building a tarval. */ -void -tarval_start (void) + fc_mul((const fp_value*) a->value, (const fp_value*) b->value, NULL); + return get_tarval_overflow(fc_get_buffer(), fc_get_buffer_length(), a->mode); + + default: + return tarval_bad; + } +} + +/* + * division + * overflow is impossible, but look out for division by zero + */ +ir_tarval *tarval_div(ir_tarval *a, ir_tarval *b) { - assert (!BUILDING); - obstack_blank (&tv_obst, sizeof (tarval)); + ir_mode *mode = a->mode; + assert(mode == b->mode); + + carry_flag = -1; + + if (mode_is_int(mode)) { + /* x/0 error */ + if (b == get_mode_null(mode)) + return tarval_bad; + + /* modes of a,b are equal */ + sc_div(a->value, b->value, NULL); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); + } else { + assert(mode_is_float(mode)); + fc_div((const fp_value*) a->value, (const fp_value*) b->value, NULL); + return get_tarval_overflow(fc_get_buffer(), fc_get_buffer_length(), mode); + } } +/* + * remainder + * overflow is impossible, but look out for division by zero + */ +ir_tarval *tarval_mod(ir_tarval *a, ir_tarval *b) +{ + assert((a->mode == b->mode) && mode_is_int(a->mode)); + + carry_flag = -1; + + /* x/0 error */ + if (b == get_mode_null(b->mode)) return tarval_bad; + /* modes of a,b are equal */ + sc_mod(a->value, b->value, NULL); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); +} -/* Append `n' chars from `p' to the tarval currently under construction. */ -void -tarval_append (const char *p, size_t n) +/* + * integer division AND remainder + * overflow is impossible, but look out for division by zero + */ +ir_tarval *tarval_divmod(ir_tarval *a, ir_tarval *b, ir_tarval **mod) { - assert (BUILDING); - obstack_grow (&tv_obst, p, n); + int len = sc_get_buffer_length(); + char *div_res = (char*) alloca(len); + char *mod_res = (char*) alloca(len); + + assert((a->mode == b->mode) && mode_is_int(a->mode)); + + carry_flag = -1; + + /* x/0 error */ + if (b == get_mode_null(b->mode)) return tarval_bad; + /* modes of a,b are equal */ + sc_divmod(a->value, b->value, div_res, mod_res); + *mod = get_tarval(mod_res, len, a->mode); + return get_tarval(div_res, len, a->mode); } +/* + * absolute value + */ +ir_tarval *tarval_abs(ir_tarval *a) +{ + char *buffer; + + carry_flag = -1; + assert(mode_is_num(a->mode)); + + switch (get_mode_sort(a->mode)) { + case irms_int_number: + if (sc_comp(a->value, get_mode_null(a->mode)->value) == -1) { + buffer = (char*) alloca(sc_get_buffer_length()); + sc_neg(a->value, buffer); + return get_tarval_overflow(buffer, a->length, a->mode); + } + return a; + + case irms_float_number: + /* it should be safe to enable this even if other arithmetic is disabled */ + /*if (no_float) + return tarval_bad;*/ + + if (fc_comp((const fp_value*) a->value, + (const fp_value*) get_mode_null(a->mode)->value) == -1) { + fc_neg((const fp_value*) a->value, NULL); + return get_tarval_overflow(fc_get_buffer(), fc_get_buffer_length(), a->mode); + } + return a; + + default: + break; + } + return tarval_bad; +} -/* Append `ch' to the tarval currently under construction. */ -void -tarval_append1 (char ch) +/* + * bitwise and + */ +ir_tarval *tarval_and(ir_tarval *a, ir_tarval *b) { - assert (BUILDING); - obstack_1grow (&tv_obst, ch); + assert(a->mode == b->mode); + + /* works even for vector modes */ + carry_flag = 0; + + switch (get_mode_sort(a->mode)) { + case irms_internal_boolean: + return (a == tarval_b_false) ? a : b; + + case irms_reference: + case irms_int_number: + sc_and(a->value, b->value, NULL); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); + + default: + panic("operation not defined on mode"); + } } +ir_tarval *tarval_andnot(ir_tarval *a, ir_tarval *b) +{ + assert(a->mode == b->mode); + + /* works even for vector modes */ + carry_flag = 0; + + switch (get_mode_sort(a->mode)) { + case irms_internal_boolean: + return a == tarval_b_true && b == tarval_b_false ? tarval_b_true : tarval_b_false; + + case irms_reference: + case irms_int_number: + sc_andnot(a->value, b->value, NULL); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); -/* 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) + default: + panic("operation not defined on mode"); + } +} + +/* + * bitwise or + */ +ir_tarval *tarval_or(ir_tarval *a, ir_tarval *b) { - int size = obstack_object_size (&tv_obst) - sizeof (tarval); - tarval *tv; - unsigned char *p; - char ch = 0; /* initialized to shut up gcc */ + assert(a->mode == b->mode); + + /* works even for vector modes */ + carry_flag = 0; - 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_sort(a->mode)) { + case irms_internal_boolean: + return (a == tarval_b_true) ? a : b; - 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 irms_reference: + case irms_int_number: + sc_or(a->value, b->value, NULL); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); - return tarval_identify (tv); + default: + panic("operation not defined on mode"); + } } +/* + * bitwise exclusive or (xor) + */ +ir_tarval *tarval_eor(ir_tarval *a, ir_tarval *b) +{ + assert((a->mode == b->mode)); + + /* works even for vector modes */ + carry_flag = 0; + + switch (get_mode_sort(a->mode)) { + case irms_internal_boolean: + return (a == b)? tarval_b_false : tarval_b_true; -/* Cancel tarval building and return tarval_bad. */ -tarval * -tarval_cancel (void) + case irms_reference: + case irms_int_number: + sc_xor(a->value, b->value, NULL); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); + + default: + panic("operation not defined on mode"); + } +} + +/* + * bitwise left shift + */ +ir_tarval *tarval_shl(ir_tarval *a, ir_tarval *b) { - assert (BUILDING); - obstack_free (&tv_obst, obstack_finish (&tv_obst)); - return tarval_bad; + char *temp_val = NULL; + + assert(mode_is_int(a->mode) && mode_is_int(b->mode)); + + carry_flag = -1; + + if (get_mode_modulo_shift(a->mode) != 0) { + temp_val = (char*) alloca(sc_get_buffer_length()); + + sc_val_from_ulong(get_mode_modulo_shift(a->mode), temp_val); + sc_mod(b->value, temp_val, temp_val); + } else + temp_val = (char*)b->value; + + sc_shl(a->value, temp_val, get_mode_size_bits(a->mode), mode_is_signed(a->mode), NULL); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); } +/* + * bitwise unsigned right shift + */ +ir_tarval *tarval_shr(ir_tarval *a, ir_tarval *b) +{ + char *temp_val = NULL; + + assert(mode_is_int(a->mode) && mode_is_int(b->mode)); + + carry_flag = -1; + + if (get_mode_modulo_shift(a->mode) != 0) { + temp_val = (char*) alloca(sc_get_buffer_length()); + + sc_val_from_ulong(get_mode_modulo_shift(a->mode), temp_val); + sc_mod(b->value, temp_val, temp_val); + } else + temp_val = (char*)b->value; -/*** ****************** Arithmethic operations on tarvals ***************** ***/ + sc_shr(a->value, temp_val, get_mode_size_bits(a->mode), mode_is_signed(a->mode), NULL); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); +} -/* Return `src' converted to mode `m' if representable, else NULL. - @@@ lots of conversions missing */ -tarval * -tarval_convert_to (tarval *src, ir_mode *m) +/* + * bitwise signed right shift + */ +ir_tarval *tarval_shrs(ir_tarval *a, ir_tarval *b) { - tarval *tv; + char *temp_val = NULL; + + assert(mode_is_int(a->mode) && mode_is_int(b->mode)); - if (m == src->mode) return src; + carry_flag = -1; - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = m; + if (get_mode_modulo_shift(a->mode) != 0) { + temp_val = (char*) alloca(sc_get_buffer_length()); - switch (get_mode_modecode(src->mode)) { + sc_val_from_ulong(get_mode_modulo_shift(a->mode), temp_val); + sc_mod(b->value, temp_val, temp_val); + } else + temp_val = (char*)b->value; - case irm_D: - if (m != mode_F) goto fail; - tv->u.F = src->u.D; - break; + sc_shrs(a->value, temp_val, get_mode_size_bits(a->mode), mode_is_signed(a->mode), NULL); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); +} - 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; - break; +/* + * bitwise rotation to left + */ +ir_tarval *tarval_rotl(ir_tarval *a, ir_tarval *b) +{ + char *temp_val = NULL; - 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; - break; + assert(mode_is_int(a->mode) && mode_is_int(b->mode)); - case irm_b: - tv->u.b = !!src->u.sInt; - break; + carry_flag = -1; - default: goto fail; - } + if (get_mode_modulo_shift(a->mode) != 0) { + temp_val = (char*) alloca(sc_get_buffer_length()); - 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; - break; + sc_val_from_ulong(get_mode_modulo_shift(a->mode), temp_val); + sc_mod(b->value, temp_val, temp_val); + } else + temp_val = (char*)b->value; - 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; - break; - - case irm_b: - tv->u.b = !!src->u.uInt; - break; - - default: goto fail; - } - break; - - 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; - - case irm_Bu: case irm_Hu: case irm_Iu: case irm_Lu: - tv->u.uInt = src->u.b; - - default: goto fail; - } - break; - - default: - fail: - obstack_free (&tv_obst, tv); - return NULL; - } - - return tarval_identify (tv); + sc_rotl(a->value, temp_val, get_mode_size_bits(a->mode), mode_is_signed(a->mode), NULL); + return get_tarval(sc_get_buffer(), sc_get_buffer_length(), a->mode); } +/* + * carry flag of the last operation + */ +int tarval_carry(void) +{ + if (carry_flag == -1) + panic("Carry undefined for the last operation"); + return carry_flag; +} -/* GL Why are there no ArmRoq comments, why is this not used? */ -tarval * -tarval_neg (tarval *a) +/* + * Output of tarvals + */ +int tarval_snprintf(char *buf, size_t len, ir_tarval *tv) { - 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); -} - - -/* 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) -{ - - 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); - } -} - - -/* Return `a+b' if computable, else NULL. Modes must be equal. */ -tarval * -tarval_add (tarval *a, tarval *b) -{ - 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) - || ((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); - } - - return tarval_identify (tv); -} - - -/* Return `a-b' if computable, else NULL. Modes must be equal. */ -tarval * -tarval_sub (tarval *a, tarval *b) -{ - 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) - || ((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); - } - - return tarval_identify (tv); -} - -/* Return `a*b' if computable, else NULL. Modes must be equal. */ -tarval * -tarval_mul (tarval *a, tarval *b) -{ - 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); - } - - return tarval_identify (tv); -} - - -/* 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; - } - - return tarval_identify (tv); -} - - -/* Return `a/b' if computable, else NULL. Modes must be equal. */ -tarval * -tarval_div (tarval *a, tarval *b) -{ - 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 = 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); -} - - -/* Return `a%b' if computable, else NULL. Modes must be equal. */ -tarval * -tarval_mod (tarval *a, tarval *b) -{ - 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); -} - -/* 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; + static const tarval_mode_info default_info = { TVO_NATIVE, NULL, NULL }; + + const char *str; + char tv_buf[100]; + const tarval_mode_info *mode_info; + const char *prefix, *suffix; + + mode_info = (const tarval_mode_info*) tv->mode->tv_priv; + if (! mode_info) + mode_info = &default_info; + prefix = mode_info->mode_prefix ? mode_info->mode_prefix : ""; + suffix = mode_info->mode_suffix ? mode_info->mode_suffix : ""; + + switch (get_mode_sort(tv->mode)) { + case irms_reference: + if (tv == tv->mode->null) return snprintf(buf, len, "NULL"); + /* FALLTHROUGH */ + case irms_int_number: + switch (mode_info->mode_output) { + + case TVO_DECIMAL: + str = sc_print(tv->value, get_mode_size_bits(tv->mode), SC_DEC, mode_is_signed(tv->mode)); + break; + + case TVO_OCTAL: + str = sc_print(tv->value, get_mode_size_bits(tv->mode), SC_OCT, 0); + break; + + case TVO_NATIVE: + prefix = "0x"; + case TVO_HEX: + default: + str = sc_print(tv->value, get_mode_size_bits(tv->mode), SC_HEX, 0); + break; + } + return snprintf(buf, len, "%s%s%s", prefix, str, suffix); + + case irms_float_number: + switch (mode_info->mode_output) { + case TVO_HEX: + return snprintf(buf, len, "%s%s%s", prefix, fc_print((const fp_value*) tv->value, tv_buf, sizeof(tv_buf), FC_PACKED), suffix); + + case TVO_HEXFLOAT: + return snprintf(buf, len, "%s%s%s", prefix, fc_print((const fp_value*) tv->value, tv_buf, sizeof(tv_buf), FC_HEX), suffix); + + case TVO_FLOAT: + case TVO_NATIVE: + default: + return snprintf(buf, len, "%s%s%s", prefix, fc_print((const fp_value*) tv->value, tv_buf, sizeof(tv_buf), FC_DEC), suffix); + } + + case irms_internal_boolean: + switch (mode_info->mode_output) { + + case TVO_DECIMAL: + case TVO_OCTAL: + case TVO_HEX: + case TVO_BINARY: + return snprintf(buf, len, "%s%c%s", prefix, (tv == tarval_b_true) ? '1' : '0', suffix); + + case TVO_NATIVE: + default: + return snprintf(buf, len, "%s%s%s", prefix, (tv == tarval_b_true) ? "true" : "false", suffix); + } + + default: + return snprintf(buf, len, ""); + } } -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); - } +/** + * Output of tarvals to stdio. + */ +int tarval_printf(ir_tarval *tv) +{ + char buf[1024]; + int res; - return 0; + res = tarval_snprintf(buf, sizeof(buf), tv); + assert(res < (int) sizeof(buf) && "buffer to small for tarval_snprintf"); + printf("%s", buf); + return res; } - - -/* Return `a&b'. Modes must be equal. */ -tarval * -tarval_and (tarval *a, tarval *b) + +char *get_tarval_bitpattern(ir_tarval *tv) +{ + int i, j, pos = 0; + int n = get_mode_size_bits(tv->mode); + int bytes = (n + 7) / 8; + char *res = XMALLOCN(char, n + 1); + unsigned char byte; + + for (i = 0; i < bytes; i++) { + byte = get_tarval_sub_bits(tv, i); + for (j = 1; j < 256; j <<= 1) + if (pos < n) + res[pos++] = j & byte ? '1' : '0'; + } + + res[n] = '\0'; + + return res; +} + +/* + * access to the bitpattern + */ +unsigned char get_tarval_sub_bits(ir_tarval *tv, unsigned byte_ofs) { - tarval *tv; + switch (get_mode_arithmetic(tv->mode)) { + case irma_twos_complement: + return sc_sub_bits(tv->value, get_mode_size_bits(tv->mode), byte_ofs); + case irma_ieee754: + case irma_x86_extended_float: + return fc_sub_bits((const fp_value*) tv->value, get_mode_size_bits(tv->mode), byte_ofs); + default: + panic("get_tarval_sub_bits(): arithmetic mode not supported"); + } +} - TARVAL_VRFY (a); TARVAL_VRFY (b); - assert (a->mode == b->mode); +/* + * Specify the output options of one mode. + * + * This functions stores the modinfo, so DO NOT DESTROY it. + * + * Returns zero on success. + */ +int set_tarval_mode_output_option(ir_mode *mode, const tarval_mode_info *modeinfo) +{ + assert(mode); - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); + mode->tv_priv = modeinfo; + return 0; +} - tv->mode = a->mode; +/* + * Returns the output options of one mode. + * + * This functions returns the mode info of a given mode. + */ +const tarval_mode_info *get_tarval_mode_output_option(ir_mode *mode) +{ + assert(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 (const tarval_mode_info*) mode->tv_priv; +} - return tarval_identify (tv); +/* + * Returns non-zero if a given (integer) tarval has only one single bit + * set. + */ +int tarval_is_single_bit(ir_tarval *tv) +{ + int i, l; + int bits; + + if (!tv || tv == tarval_bad) return 0; + if (! mode_is_int(tv->mode)) return 0; + + l = get_mode_size_bytes(tv->mode); + for (bits = 0, i = l - 1; i >= 0; --i) { + unsigned char v = get_tarval_sub_bits(tv, (unsigned)i); + + /* check for more than one bit in these */ + if (v) { + if (v & (v-1)) + return 0; + if (++bits > 1) + return 0; + } + } + return bits; } +/* + * Return the number of set bits in a given (integer) tarval. + */ +int get_tarval_popcount(ir_tarval *tv) +{ + int i, l; + int bits; + + if (!tv || tv == tarval_bad) return -1; + if (! mode_is_int(tv->mode)) return -1; + + l = get_mode_size_bytes(tv->mode); + for (bits = 0, i = l - 1; i >= 0; --i) { + unsigned char v = get_tarval_sub_bits(tv, (unsigned)i); -/* Return `a|b'. Modes must be equal. */ -tarval * -tarval_or (tarval *a, tarval *b) + bits += popcount(v); + } + return bits; +} + +/** + * Return the number of the lowest set bit in a given (integer) tarval. + * + * @param tv the tarval + * + * @return number of lowest set bit or -1 on error + */ +int get_tarval_lowest_bit(ir_tarval *tv) { - tarval *tv; + int i, l; + + if (!tv || tv == tarval_bad) return -1; + if (! mode_is_int(tv->mode)) return -1; - TARVAL_VRFY (a); TARVAL_VRFY (b); - assert (a->mode == b->mode); + l = get_mode_size_bytes(tv->mode); + for (i = 0; i < l; ++i) { + unsigned char v = get_tarval_sub_bits(tv, (unsigned)i); - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); + if (v) + return ntz(v) + i * 8; + } + return -1; +} - tv->mode = a->mode; +/* + * Returns non-zero if the mantissa of a floating point IEEE-754 + * tarval is zero (i.e. 1.0Exxx) + */ +int tarval_zero_mantissa(ir_tarval *tv) +{ + assert(get_mode_arithmetic(tv->mode) == irma_ieee754 + || get_mode_arithmetic(tv->mode) == irma_x86_extended_float); + return fc_zero_mantissa((const fp_value*) tv->value); +} - 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); - } +/* Returns the exponent of a floating point IEEE-754 tarval. */ +int tarval_get_exponent(ir_tarval *tv) +{ + assert(get_mode_arithmetic(tv->mode) == irma_ieee754 + || get_mode_arithmetic(tv->mode) == irma_x86_extended_float); + return fc_get_exponent((const fp_value*) tv->value); +} - return tarval_identify (tv); +/* + * Check if the tarval can be converted to the given mode without + * precision loss. + */ +int tarval_ieee754_can_conv_lossless(ir_tarval *tv, ir_mode *mode) +{ + const float_descriptor_t *desc = get_descriptor(mode); + return fc_can_lossless_conv_to((const fp_value*) tv->value, desc); } +/* Returns non-zero if the result of the last IEEE-754 operation was exact. */ +unsigned tarval_ieee754_get_exact(void) +{ + return fc_is_exact(); +} -/* Return `a^b'. Modes must be equal. */ -tarval * -tarval_eor (tarval *a, tarval *b) +/* check if its the a floating point NaN */ +int tarval_is_NaN(ir_tarval *tv) { - tarval *tv; + if (! mode_is_float(tv->mode)) + return 0; + return fc_is_nan((const fp_value*) tv->value); +} - TARVAL_VRFY (a); TARVAL_VRFY (b); - assert (a->mode == b->mode); +/* check if its the a floating point +inf */ +int tarval_is_plus_inf(ir_tarval *tv) +{ + if (! mode_is_float(tv->mode)) + return 0; + return fc_is_inf((const fp_value*) tv->value) + && !fc_is_negative((const fp_value*) tv->value); +} - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); +/* check if its the a floating point -inf */ +int tarval_is_minus_inf(ir_tarval *tv) +{ + if (! mode_is_float(tv->mode)) + return 0; + return fc_is_inf((const fp_value*) tv->value) + && fc_is_negative((const fp_value*) tv->value); +} - tv->mode = a->mode; +/* check if the tarval represents a finite value */ +int tarval_is_finite(ir_tarval *tv) +{ + if (mode_is_float(tv->mode)) + return !fc_is_nan((const fp_value*) tv->value) + && !fc_is_inf((const fp_value*) tv->value); + return 1; +} - 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); - } +/* + * Sets the overflow mode for integer operations. + */ +void tarval_set_integer_overflow_mode(tarval_int_overflow_mode_t ov_mode) +{ + int_overflow_mode = ov_mode; +} - return tarval_identify (tv); +/* Get the overflow mode for integer operations. */ +tarval_int_overflow_mode_t tarval_get_integer_overflow_mode(void) +{ + return int_overflow_mode; } +/* Enable/Disable floating point constant folding. */ +void tarval_enable_fp_ops(int enable) +{ + no_float = !enable; +} -/* Return `a<= get_mode_size(mode_Ls)*target_bits))) { - return NULL; - } +/* + * Initialization of the tarval module: called before init_mode() + */ +void init_tarval_1(long null_value, int support_quad_precision) +{ + /* if these assertion fail, tarval_is_constant() will follow ... */ + assert(tarval_b_false == &reserved_tv[0] && "b_false MUST be the first reserved tarval!"); + assert(tarval_b_true == &reserved_tv[1] && "b_true MUST be the second reserved tarval!"); + + _null_value = null_value; + + /* initialize the sets holding the tarvals with a comparison function and + * an initial size, which is the expected number of constants */ + tarvals = new_set(cmp_tv, N_CONSTANTS); + values = new_set(memcmp, N_CONSTANTS); + /* calls init_strcalc() with needed size */ + init_fltcalc(support_quad_precision ? 112 : 64); +} + +/* + * Initialization of the tarval module: called after init_mode() + */ +void init_tarval_2(void) +{ + tarval_bad->kind = k_tarval; + tarval_bad->mode = mode_BAD; + tarval_bad->value = INT_TO_PTR(resid_tarval_bad); + + tarval_undefined->kind = k_tarval; + tarval_undefined->mode = mode_ANY; + tarval_undefined->value = INT_TO_PTR(resid_tarval_undefined); + + tarval_b_true->kind = k_tarval; + tarval_b_true->mode = mode_b; + tarval_b_true->value = INT_TO_PTR(resid_tarval_b_true); + + tarval_b_false->kind = k_tarval; + tarval_b_false->mode = mode_b; + tarval_b_false->value = INT_TO_PTR(resid_tarval_b_false); + + tarval_unreachable->kind = k_tarval; + tarval_unreachable->mode = mode_X; + tarval_unreachable->value = INT_TO_PTR(resid_tarval_unreachable); + + tarval_reachable->kind = k_tarval; + tarval_reachable->mode = mode_X; + tarval_reachable->value = INT_TO_PTR(resid_tarval_reachable); + + /* + * assign output modes that are compatible with the + * old implementation: Hex output + */ + set_tarval_mode_output_option(mode_Bs, &hex_output); + set_tarval_mode_output_option(mode_Bu, &hex_output); + set_tarval_mode_output_option(mode_Hs, &hex_output); + set_tarval_mode_output_option(mode_Hu, &hex_output); + set_tarval_mode_output_option(mode_Is, &hex_output); + set_tarval_mode_output_option(mode_Iu, &hex_output); + set_tarval_mode_output_option(mode_Ls, &hex_output); + set_tarval_mode_output_option(mode_Lu, &hex_output); + set_tarval_mode_output_option(mode_P, &hex_output); +} - tv = (tarval *)obstack_alloc (&tv_obst, sizeof (tarval)); - tv->mode = a->mode; +/* free all memory occupied by tarval. */ +void finish_tarval(void) +{ + finish_strcalc(); + finish_fltcalc(); + del_set(tarvals); tarvals = NULL; + del_set(values); values = NULL; +} - 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); - } - - return tarval_identify (tv); -} - - -/* 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) +int (is_tarval)(const void *thing) { - int b_is_huge; - long shift; - tarval *tv; - - 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; - } - - 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); - } - - return tarval_identify (tv); -} - - -/* 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) -{ - 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; - } -} - -/* 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) -{ - 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; - } -} - -int -tarval_print (XP_PAR1, const xprintf_info *info ATTRIBUTE((unused)), XP_PARN) -{ - 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 ("(void)"); - } - 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); - } - - return printed; -} - - -ir_mode * -get_tv_mode (tarval *tv) -{ - return tv->mode; -} - -/* Returns the entity if the tv is a pointer to an entity, else - returns NULL; */ -entity *get_tv_entity(tarval *tv) { - entity *ent = NULL; - - 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; + return _is_tarval(thing); }