diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 386d898e70a..b1f1205eb41 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2007-04-30 Brooks Moses + + * double-int.c (mpz_set_double_int): Moved from + tree-ssa-loop-niter.c. + (mpz_get_double_int): Likewise; also, add option to wrap + out-of-range integers. + * double-int.h: New prototypes for above. + * tree.c (get_static_type_bounds): Moved from + tree-ssa-loop-niter.c; now returns TYPE_MIN_VALUE and + TYPE_MAX_VALUE if they exist.. + * tree.h: New prototype for above. + * tree-ssa-loop-niter.c: Adjust mpz_to_double_int and + get_type_bounds calls. + (mpz_set_double_int): Move to double-int.c. + (get_type_bounds): Move to tree.c, rename to + get_static_type_bounds. + (mpz_to_double_int): Move to double-int.c, rename to + mpz_get_double_int. + 2007-04-30 Bob Wilson * config/xtensa/lib1funcs.asm (__umodsi3, __modsi3): Rearrange so that diff --git a/gcc/double-int.c b/gcc/double-int.c index 45a833a0654..8cbd3abc653 100644 --- a/gcc/double-int.c +++ b/gcc/double-int.c @@ -413,3 +413,81 @@ dump_double_int (FILE *file, double_int cst, bool uns) for (i = n - 1; i >= 0; i--) fprintf (file, "%u", digits[i]); } + + +/* Sets RESULT to VAL, taken unsigned if UNS is true and as signed + otherwise. */ + +void +mpz_set_double_int (mpz_t result, double_int val, bool uns) +{ + bool negate = false; + unsigned HOST_WIDE_INT vp[2]; + + if (!uns && double_int_negative_p (val)) + { + negate = true; + val = double_int_neg (val); + } + + vp[0] = val.low; + vp[1] = (unsigned HOST_WIDE_INT) val.high; + mpz_import (result, 2, -1, sizeof (HOST_WIDE_INT), 0, 0, vp); + + if (negate) + mpz_neg (result, result); +} + +/* Returns VAL converted to TYPE. If WRAP is true, then out-of-range + values of VAL will be wrapped; otherwise, they will be set to the + appropriate minimum or maximum TYPE bound. */ + +double_int +mpz_get_double_int (tree type, mpz_t val, bool wrap) +{ + unsigned HOST_WIDE_INT *vp; + size_t count, numb; + double_int res; + + if (!wrap) + { + mpz_t min, max; + + mpz_init (min); + mpz_init (max); + get_type_static_bounds (type, min, max); + + if (mpz_cmp (val, min) < 0) + mpz_set (val, min); + else if (mpz_cmp (val, max) > 0) + mpz_set (val, max); + + mpz_clear (min); + mpz_clear (max); + } + + /* Determine the number of unsigned HOST_WIDE_INT that are required + for representing the value. The code to calculate count is + extracted from the GMP manual, section "Integer Import and Export": + http://gmplib.org/manual/Integer-Import-and-Export.html */ + numb = 8*sizeof(HOST_WIDE_INT); + count = (mpz_sizeinbase (val, 2) + numb-1) / numb; + if (count < 2) + count = 2; + vp = (unsigned HOST_WIDE_INT *) alloca (count * sizeof(HOST_WIDE_INT)); + + vp[0] = 0; + vp[1] = 0; + mpz_export (vp, &count, -1, sizeof (HOST_WIDE_INT), 0, 0, val); + + gcc_assert (wrap || count <= 2); + + res.low = vp[0]; + res.high = (HOST_WIDE_INT) vp[1]; + + res = double_int_ext (res, TYPE_PRECISION (type), TYPE_UNSIGNED (type)); + if (mpz_sgn (val) < 0) + res = double_int_neg (res); + + return res; +} diff --git a/gcc/double-int.h b/gcc/double-int.h index 807166b8957..33641bd06dc 100644 --- a/gcc/double-int.h +++ b/gcc/double-int.h @@ -21,6 +21,9 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #ifndef DOUBLE_INT_H #define DOUBLE_INT_H +#include +#include "coretypes.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 @@ -174,4 +177,10 @@ double_int_equal_p (double_int cst1, double_int cst2) return cst1.low == cst2.low && cst1.high == cst2.high; } +/* Conversion to and from GMP integer representations. */ + +void mpz_set_double_int (mpz_t, double_int, bool); +double_int mpz_get_double_int (tree, mpz_t, bool); + + #endif /* DOUBLE_INT_H */ diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c index 2e733f93168..814b23a7843 100644 --- a/gcc/tree-ssa-loop-niter.c +++ b/gcc/tree-ssa-loop-niter.c @@ -64,92 +64,6 @@ typedef struct mpz_t below, up; } bounds; -/* Sets RESULT to VAL, taken unsigned if UNS is true and as signed - otherwise. */ - -static void -mpz_set_double_int (mpz_t result, double_int val, bool uns) -{ - bool negate = false; - unsigned HOST_WIDE_INT vp[2]; - - if (!uns && double_int_negative_p (val)) - { - negate = true; - val = double_int_neg (val); - } - - vp[0] = val.low; - vp[1] = (unsigned HOST_WIDE_INT) val.high; - mpz_import (result, 2, -1, sizeof (HOST_WIDE_INT), 0, 0, vp); - - if (negate) - mpz_neg (result, result); -} - -/* Stores bounds of TYPE to MIN and MAX. */ - -static void -get_type_bounds (tree type, mpz_t min, mpz_t max) -{ - if (TYPE_UNSIGNED (type)) - { - mpz_set_ui (min, 0); - mpz_set_double_int (max, double_int_mask (TYPE_PRECISION (type)), true); - } - else - { - double_int mx, mn; - - mx = double_int_mask (TYPE_PRECISION (type) - 1); - mn = double_int_sext (double_int_add (mx, double_int_one), - TYPE_PRECISION (type)); - mpz_set_double_int (max, mx, true); - mpz_set_double_int (min, mn, false); - } -} - -/* Returns VAL converted to TYPE. If VAL does not fit in TYPE, - the minimum or maximum value of the type is returned instead. */ - -static double_int -mpz_to_double_int (tree type, mpz_t val) -{ - mpz_t min, max; - unsigned HOST_WIDE_INT vp[2]; - bool negate = false; - size_t count; - double_int res; - - mpz_init (min); - mpz_init (max); - get_type_bounds (type, min, max); - - if (mpz_cmp (val, min) < 0) - mpz_set (val, min); - else if (mpz_cmp (val, max) > 0) - mpz_set (val, max); - - if (mpz_sgn (val) < 0) - negate = true; - - vp[0] = 0; - vp[1] = 0; - mpz_export (vp, &count, -1, sizeof (HOST_WIDE_INT), 0, 0, val); - gcc_assert (count <= 2); - - mpz_clear (min); - mpz_clear (max); - - res.low = vp[0]; - res.high = (HOST_WIDE_INT) vp[1]; - - res = double_int_ext (res, TYPE_PRECISION (type), TYPE_UNSIGNED (type)); - if (negate) - res = double_int_neg (res); - - return res; -} /* Splits expression EXPR to a variable part VAR and constant OFFSET. */ @@ -212,7 +126,7 @@ determine_value_range (tree type, tree var, mpz_t off, /* If the computation may wrap, we know nothing about the value, except for the range of the type. */ - get_type_bounds (type, min, max); + get_type_static_bounds (type, min, max); if (!nowrap_type_p (type)) return; @@ -703,7 +617,7 @@ number_of_iterations_ne (tree type, affine_iv *iv, tree final, mpz_init (max); number_of_iterations_ne_max (max, iv->no_overflow, c, s, bnds); - niter->max = mpz_to_double_int (niter_type, max); + niter->max = mpz_get_double_int (niter_type, max, false); mpz_clear (max); /* First the trivial cases -- when the step is 1. */ @@ -1081,7 +995,7 @@ number_of_iterations_lt (tree type, affine_iv *iv0, affine_iv *iv1, niter->may_be_zero = fold_build2 (LT_EXPR, boolean_type_node, iv1->base, iv0->base); niter->niter = delta; - niter->max = mpz_to_double_int (niter_type, bnds->up); + niter->max = mpz_get_double_int (niter_type, bnds->up, false); return true; } @@ -1128,7 +1042,7 @@ number_of_iterations_lt (tree type, affine_iv *iv0, affine_iv *iv1, mpz_add (tmp, bnds->up, mstep); mpz_sub_ui (tmp, tmp, 1); mpz_fdiv_q (tmp, tmp, mstep); - niter->max = mpz_to_double_int (niter_type, tmp); + niter->max = mpz_get_double_int (niter_type, tmp, false); mpz_clear (mstep); mpz_clear (tmp); diff --git a/gcc/tree.c b/gcc/tree.c index fbaeb737cc8..472477c49ae 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -6138,6 +6138,47 @@ int_fits_type_p (tree c, tree type) return !fit_double_type (low, high, &low, &high, type); } +/* Stores bounds of an integer TYPE in MIN and MAX. If TYPE has non-constant + bounds or is a POINTER_TYPE, the maximum and/or minimum values that can be + represented (assuming two's-complement arithmetic) within the bit + precision of the type are returned instead. */ + +void +get_type_static_bounds (tree type, mpz_t min, mpz_t max) +{ + if (!POINTER_TYPE_P (type) && TYPE_MIN_VALUE (type) + && TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST) + mpz_set_double_int (min, tree_to_double_int (TYPE_MIN_VALUE (type)), + TYPE_UNSIGNED (type)); + else + { + if (TYPE_UNSIGNED (type)) + mpz_set_ui (min, 0); + else + { + double_int mn; + mn = double_int_mask (TYPE_PRECISION (type) - 1); + mn = double_int_sext (double_int_add (mn, double_int_one), + TYPE_PRECISION (type)); + mpz_set_double_int (min, mn, false); + } + } + + if (!POINTER_TYPE_P (type) && TYPE_MAX_VALUE (type) + && TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST) + mpz_set_double_int (max, tree_to_double_int (TYPE_MAX_VALUE (type)), + TYPE_UNSIGNED (type)); + else + { + if (TYPE_UNSIGNED (type)) + mpz_set_double_int (max, double_int_mask (TYPE_PRECISION (type)), + true); + else + mpz_set_double_int (max, double_int_mask (TYPE_PRECISION (type) - 1), + true); + } +} + /* Subprogram of following function. Called by walk_tree. Return *TP if it is an automatic variable or parameter of the diff --git a/gcc/tree.h b/gcc/tree.h index 0444ae04c5e..c076fc1aa7a 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -4539,6 +4539,7 @@ extern int objects_must_conflict_p (tree, tree); /* In tree.c */ extern int really_constant_p (tree); extern int int_fits_type_p (tree, tree); +extern void get_type_static_bounds (tree, mpz_t, mpz_t); extern bool variably_modified_type_p (tree, tree); extern int tree_log2 (tree); extern int tree_floor_log2 (tree);