diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/Makefile.in | 6 | ||||
-rw-r--r-- | gcc/double-int.c | 344 | ||||
-rw-r--r-- | gcc/double-int.h | 169 | ||||
-rw-r--r-- | gcc/gengtype.c | 1 | ||||
-rw-r--r-- | gcc/system.h | 2 | ||||
-rw-r--r-- | gcc/tree.h | 8 |
7 files changed, 531 insertions, 9 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8a226e6..a2508b6 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2006-03-03 Zdenek Dvorak <dvorakz@suse.cz> + + * gengtype.c (main): Handle double_int type. + * tree.h (struct tree_int_cst): Make type of int_cst double_int. + * double-int.c: New file. + * double-int.h: New file. + * system.h: Include doubleint.h. + * Makefile.in (SYSTEM_H): Include double-int.h. + (double-int.o): Add. + 2006-03-03 Joseph S. Myers <joseph@codesourcery.com> PR bootstrap/26478 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index f567223..4b9526a 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -773,7 +773,7 @@ INSN_ATTR_H = insn-attr.h $(srcdir)/insn-addr.h $(srcdir)/varray.h C_COMMON_H = c-common.h $(SPLAY_TREE_H) $(CPPLIB_H) $(GGC_H) C_PRAGMA_H = c-pragma.h $(CPPLIB_H) C_TREE_H = c-tree.h $(C_COMMON_H) toplev.h $(DIAGNOSTIC_H) -SYSTEM_H = system.h hwint.h $(srcdir)/../include/libiberty.h +SYSTEM_H = system.h hwint.h double-int.h $(srcdir)/../include/libiberty.h PREDICT_H = predict.h predict.def CPPLIB_H = $(srcdir)/../libcpp/include/line-map.h \ $(srcdir)/../libcpp/include/cpplib.h @@ -952,7 +952,7 @@ C_OBJS = c-lang.o stub-objc.o $(C_AND_OBJC_OBJS) # Language-independent object files. OBJS-common = \ - tree-chrec.o tree-scalar-evolution.o tree-data-ref.o \ + double-int.o tree-chrec.o tree-scalar-evolution.o tree-data-ref.o \ tree-cfg.o tree-dfa.o tree-eh.o tree-ssa.o tree-optimize.o tree-gimple.o \ gimplify.o tree-pretty-print.o tree-into-ssa.o \ tree-outof-ssa.o tree-ssa-ccp.o tree-vn.o tree-ssa-uncprop.o \ @@ -1781,6 +1781,8 @@ prefix.o: prefix.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) prefix.h \ convert.o: convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(FLAGS_H) convert.h toplev.h langhooks.h real.h +double-int.o: double-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) + langhooks.o : langhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) toplev.h $(TREE_INLINE_H) $(RTL_H) insn-config.h $(INTEGRATE_H) \ langhooks.h $(LANGHOOKS_DEF_H) $(FLAGS_H) $(GGC_H) $(DIAGNOSTIC_H) intl.h \ diff --git a/gcc/double-int.c b/gcc/double-int.c new file mode 100644 index 0000000..ab1975f --- /dev/null +++ b/gcc/double-int.c @@ -0,0 +1,344 @@ +/* Operations with long integers. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GCC 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 General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" + +/* Returns mask for PREC bits. */ + +static inline double_int +double_int_mask (unsigned prec) +{ + unsigned HOST_WIDE_INT m; + double_int mask; + + if (prec > HOST_BITS_PER_WIDE_INT) + { + prec -= HOST_BITS_PER_WIDE_INT; + m = ((unsigned HOST_WIDE_INT) 2 << (prec - 1)) - 1; + mask.high = (HOST_WIDE_INT) m; + mask.low = ALL_ONES; + } + else + { + mask.high = 0; + mask.low = ((unsigned HOST_WIDE_INT) 2 << (prec - 1)) - 1; + } + + return mask; +} + +/* Clears the bits of CST over the precision PREC. If UNS is false, the bits + outside of the precision are set to the sign bit (i.e., the PREC-th one), + otherwise they are set to zero. + + This corresponds to returning the value represented by PREC lowermost bits + of CST, with the given signedness. */ + +double_int +double_int_ext (double_int cst, unsigned prec, bool uns) +{ + if (uns) + return double_int_zext (cst, prec); + else + return double_int_sext (cst, prec); +} + +/* The same as double_int_ext with UNS = true. */ + +double_int +double_int_zext (double_int cst, unsigned prec) +{ + double_int mask = double_int_mask (prec); + double_int r; + + r.low = cst.low & ~mask.low; + r.high = cst.high & ~mask.high; + + return r; +} + +/* The same as double_int_ext with UNS = false. */ + +double_int +double_int_sext (double_int cst, unsigned prec) +{ + double_int mask = double_int_mask (prec); + double_int r; + unsigned HOST_WIDE_INT snum; + + if (prec <= HOST_BITS_PER_WIDE_INT) + snum = cst.low; + else + { + prec -= HOST_BITS_PER_WIDE_INT; + snum = (unsigned HOST_WIDE_INT) cst.high; + } + if (((snum >> (prec - 1)) & 1) == 1) + { + r.low = cst.low | mask.low; + r.high = cst.high | mask.high; + } + else + { + r.low = cst.low & ~mask.low; + r.high = cst.high & ~mask.high; + } + + return r; +} + +/* Constructs long integer from tree CST. The extra bits over the precision of + the number are filled with sign bit if CST is signed, and with zeros if it + is unsigned. */ + +double_int +tree_to_double_int (tree cst) +{ + /* We do not need to call double_int_restrict here to ensure the semantics as + described, as this is the default one for trees. */ + return TREE_INT_CST (cst); +} + +/* Returns true if CST fits in unsigned HOST_WIDE_INT. */ + +bool +double_int_fits_in_uhwi_p (double_int cst) +{ + return cst.high == 0; +} + +/* Returns true if CST fits in signed HOST_WIDE_INT. */ + +bool +double_int_fits_in_shwi_p (double_int cst) +{ + if (cst.high == 0) + return (HOST_WIDE_INT) cst.low >= 0; + else if (cst.high == -1) + return (HOST_WIDE_INT) cst.low < 0; + else + return false; +} + +/* Returns true if CST fits in HOST_WIDE_INT if UNS is false, or in + unsigned HOST_WIDE_INT if UNS is true. */ + +bool +double_int_fits_in_hwi_p (double_int cst, bool uns) +{ + if (uns) + return double_int_fits_in_uhwi_p (cst); + else + return double_int_fits_in_shwi_p (cst); +} + +/* Returns value of CST as a signed number. CST must satisfy + double_int_fits_in_shwi_p. */ + +HOST_WIDE_INT +double_int_to_shwi (double_int cst) +{ + return (HOST_WIDE_INT) cst.low; +} + +/* Returns value of CST as an unsigned number. CST must satisfy + double_int_fits_in_uhwi_p. */ + +unsigned HOST_WIDE_INT +double_int_to_uhwi (double_int cst) +{ + return cst.low; +} + +/* Returns A * B. */ + +double_int +double_int_mul (double_int a, double_int b) +{ + double_int ret; + mul_double (a.low, a.high, b.low, b.high, &ret.low, &ret.high); + return ret; +} + +/* Returns A + B. */ + +double_int +double_int_add (double_int a, double_int b) +{ + double_int ret; + add_double (a.low, a.high, b.low, b.high, &ret.low, &ret.high); + return ret; +} + +/* Returns -A. */ + +double_int +double_int_neg (double_int a) +{ + double_int ret; + neg_double (a.low, a.high, &ret.low, &ret.high); + return ret; +} + +/* Returns A / B (computed as unsigned depending on UNS, and rounded as + specified by CODE). CODE is enum tree_code in fact, but double_int.h + must be included before tree.h. */ + +double_int +double_int_div (double_int a, double_int b, bool uns, unsigned code) +{ + unsigned HOST_WIDE_INT rem_lo; + HOST_WIDE_INT rem_hi; + double_int ret; + + div_and_round_double (code, uns, a.low, a.high, b.low, b.high, + &ret.low, &ret.high, &rem_lo, &rem_hi); + return ret; +} + +/* The same as double_int_div with UNS = false. */ + +double_int +double_int_sdiv (double_int a, double_int b, unsigned code) +{ + return double_int_div (a, b, false, code); +} + +/* The same as double_int_div with UNS = true. */ + +double_int +double_int_udiv (double_int a, double_int b, unsigned code) +{ + return double_int_div (a, b, true, code); +} + +/* Constructs tree in type TYPE from with value given by CST. */ + +tree +double_int_to_tree (tree type, double_int cst) +{ + cst = double_int_ext (cst, TYPE_PRECISION (type), TYPE_UNSIGNED (type)); + + return build_int_cst_wide (type, cst.low, cst.high); +} + +/* Returns true if CST is negative. Of course, CST is considered to + be signed. */ + +bool +double_int_negative_p (double_int cst) +{ + return cst.high < 0; +} + +/* Returns -1 if A < B, 0 if A == B and 1 if A > B. Signedness of the + comparison is given by UNS. */ + +int +double_int_cmp (double_int a, double_int b, bool uns) +{ + if (uns) + return double_int_ucmp (a, b); + else + return double_int_scmp (a, b); +} + +/* Compares two unsigned values A and B. Returns -1 if A < B, 0 if A == B, + and 1 if A > B. */ + +int +double_int_ucmp (double_int a, double_int b) +{ + if ((unsigned HOST_WIDE_INT) a.high < (unsigned HOST_WIDE_INT) b.high) + return -1; + if ((unsigned HOST_WIDE_INT) a.high > (unsigned HOST_WIDE_INT) b.high) + return 1; + if (a.low < b.low) + return -1; + if (a.low > b.low) + return 1; + + return 0; +} + +/* Compares two signed values A and B. Returns -1 if A < B, 0 if A == B, + and 1 if A > B. */ + +int +double_int_scmp (double_int a, double_int b) +{ + if (a.high < b.high) + return -1; + if (a.high > b.high) + return 1; + if ((HOST_WIDE_INT) a.low < (HOST_WIDE_INT) b.low) + return -1; + if ((HOST_WIDE_INT) a.low > (HOST_WIDE_INT) b.low) + return 1; + + return 0; +} + +/* Splits last digit of *CST (taken as unsigned) in BASE and returns it. */ + +static unsigned +double_int_split_digit (double_int *cst, unsigned base) +{ + unsigned HOST_WIDE_INT resl, reml; + HOST_WIDE_INT resh, remh; + + div_and_round_double (FLOOR_DIV_EXPR, true, cst->low, cst->high, base, 0, + &resl, &resh, &reml, &remh); + cst->high = resh; + cst->low = resl; + + return reml; +} + +/* Dumps CST to FILE. If UNS is true, CST is considered to be unsigned, + otherwise it is signed. */ + +void +dump_double_int (FILE *file, double_int cst, bool uns) +{ + unsigned digits[100], n; + int i; + + if (double_int_zero_p (cst)) + { + fprintf (file, "0"); + return; + } + + if (!uns && double_int_negative_p (cst)) + { + fprintf (file, "-"); + cst = double_int_neg (cst); + } + + for (n = 0; !double_int_zero_p (cst); n++) + digits[n] = double_int_split_digit (&cst, 10); + for (i = n - 1; i >= 0; i--) + fprintf (file, "%u", digits[i]); +} diff --git a/gcc/double-int.h b/gcc/double-int.h new file mode 100644 index 0000000..c6113f3 --- /dev/null +++ b/gcc/double-int.h @@ -0,0 +1,169 @@ +/* Operations with long integers. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +GCC 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 General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +#ifndef DOUBLE_INT_H +#define DOUBLE_INT_H + +/* A large integer is currently represented as a pair of HOST_WIDE_INTs. + It therefore represents a number with precision of + 2 * HOST_BITS_PER_WIDE_INT bits (it is however possible that the + internal representation will change, if numbers with greater precision + are needed, so the users should not rely on it). The representation does + not contain any information about signedness of the represented value, so + it can be used to represent both signed and unsigned numbers. For + operations where the results depend on signedness (division, comparisons), + it must be specified separately. For each such operation, there are three + versions of the function -- double_int_op, that takes an extra UNS argument + giving the signedness of the values, and double_int_sop and double_int_uop + that stand for its specializations for signed and unsigned values. + + You may also represent with numbers in smaller precision using double_int. + You however need to use double_int_ext (that fills in the bits of the + number over the prescribed precision with zeros or with the sign bit) before + operations that do not perform arithmetics modulo 2^precision (comparisons, + division), and possibly before storing the results, if you want to keep + them in some canonical form). In general, the signedness of double_int_ext + should match the signedness of the operation. + + ??? The components of double_int differ in signedness mostly for + historical reasons (they replace an older structure used to represent + numbers with precision wigher than HOST_WIDE_INT). It might be less + confusing to have them both signed or both unsigned. */ + +typedef struct +{ + unsigned HOST_WIDE_INT low; + HOST_WIDE_INT high; +} double_int; + +union tree_node; + +/* Constructors and conversions. */ + +union tree_node *double_int_to_tree (union tree_node *, double_int); +double_int tree_to_double_int (union tree_node *tree); + +/* Constructs double_int from integer CST. The bits over the precision of + HOST_WIDE_INT are filled with the sign bit. */ + +static inline double_int +shwi_to_double_int (HOST_WIDE_INT cst) +{ + double_int r; + + r.low = (unsigned HOST_WIDE_INT) cst; + r.high = cst < 0 ? -1 : 0; + + return r; +} + +/* Some useful constants. */ + +#define double_int_minus_one (shwi_to_double_int (-1)) +#define double_int_zero (shwi_to_double_int (0)) +#define double_int_one (shwi_to_double_int (1)) +#define double_int_two (shwi_to_double_int (2)) +#define double_int_ten (shwi_to_double_int (10)) + +/* Constructs double_int from unsigned integer CST. The bits over the + precision of HOST_WIDE_INT are filled with zeros. */ + +static inline double_int +uhwi_to_double_int (unsigned HOST_WIDE_INT cst) +{ + double_int r; + + r.low = cst; + r.high = 0; + + return r; +} + +/* The following operations perform arithmetics modulo 2^precision, + so you do not need to call double_int_ext between them, even if + you are representing numbers with precision less than + 2 * HOST_BITS_PER_WIDE_INT bits. */ + +double_int double_int_mul (double_int, double_int); +double_int double_int_add (double_int, double_int); +double_int double_int_neg (double_int); + +/* You must ensure that double_int_ext is called on the operands + of the following operations, if the precision of the numbers + is less than 2 * HOST_BITS_PER_WIDE_INT bits. */ +bool double_int_fits_in_hwi_p (double_int, bool); +bool double_int_fits_in_shwi_p (double_int); +bool double_int_fits_in_uhwi_p (double_int); +HOST_WIDE_INT double_int_to_shwi (double_int); +unsigned HOST_WIDE_INT double_int_to_uhwi (double_int); +double_int double_int_div (double_int, double_int, bool, unsigned); +double_int double_int_sdiv (double_int, double_int, unsigned); +double_int double_int_udiv (double_int, double_int, unsigned); +bool double_int_negative_p (double_int); +int double_int_cmp (double_int, double_int, bool); +int double_int_scmp (double_int, double_int); +int double_int_ucmp (double_int, double_int); +void dump_double_int (FILE *, double_int, bool); + +/* Zero and sign extension of numbers in smaller precisions. */ + +double_int double_int_ext (double_int, unsigned, bool); +double_int double_int_sext (double_int, unsigned); +double_int double_int_zext (double_int, unsigned); + +#define ALL_ONES (~((unsigned HOST_WIDE_INT) 0)) + +/* The operands of the following comparison functions must be processed + with double_int_ext, if their precision is less than + 2 * HOST_BITS_PER_WIDE_INT bits. */ + +/* Returns true if CST is zero. */ + +static inline bool +double_int_zero_p (double_int cst) +{ + return cst.low == 0 && cst.high == 0; +} + +/* Returns true if CST is one. */ + +static inline bool +double_int_one_p (double_int cst) +{ + return cst.low == 1 && cst.high == 0; +} + +/* Returns true if CST is minus one. */ + +static inline bool +double_int_minus_one_p (double_int cst) +{ + return (cst.low == ALL_ONES && cst.high == -1); +} + +/* Returns true if CST1 == CST2. */ + +static inline bool +double_int_equal_p (double_int cst1, double_int cst2) +{ + return cst1.low == cst2.low && cst1.high == cst2.high; +} + +#endif /* DOUBLE_INT_H */ diff --git a/gcc/gengtype.c b/gcc/gengtype.c index 0ec45c5..a30e294 100644 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@ -3037,6 +3037,7 @@ main(int ARG_UNUSED (argc), char ** ARG_UNUSED (argv)) do_scalar_typedef ("CUMULATIVE_ARGS", &pos); do_scalar_typedef ("REAL_VALUE_TYPE", &pos); + do_scalar_typedef ("double_int", &pos); do_scalar_typedef ("uint8", &pos); do_scalar_typedef ("jword", &pos); do_scalar_typedef ("JCF_u2", &pos); diff --git a/gcc/system.h b/gcc/system.h index 0769cde..d3100e1 100644 --- a/gcc/system.h +++ b/gcc/system.h @@ -609,6 +609,8 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN; # define FALSE false #endif /* !__cplusplus */ +/* Get definition of double_int. */ +#include "double-int.h" /* Some compilers do not allow the use of unsigned char in bitfields. */ #define BOOL_BITFIELD unsigned int @@ -1239,13 +1239,7 @@ extern void omp_clause_range_check_failed (const tree, const char *, int, struct tree_int_cst GTY(()) { struct tree_common common; - /* A sub-struct is necessary here because the function `const_hash' - wants to scan both words as a unit and taking the address of the - sub-struct yields the properly inclusive bounded pointer. */ - struct tree_int_cst_lowhi { - unsigned HOST_WIDE_INT low; - HOST_WIDE_INT high; - } int_cst; + double_int int_cst; }; /* In a REAL_CST node. struct real_value is an opaque entity, with |