diff options
-rw-r--r-- | gcc/ChangeLog | 10 | ||||
-rw-r--r-- | gcc/builtins.c | 10 | ||||
-rw-r--r-- | gcc/fold-const.c | 116 | ||||
-rw-r--r-- | gcc/tree.c | 67 | ||||
-rw-r--r-- | gcc/tree.h | 2 |
5 files changed, 100 insertions, 105 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index df844328b80..319ed868045 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2007-01-08 Richard Guenther <rguenther@suse.de> + + * builtins.c (fold_builtin_int_roundingfn): Use fit_double_type. + * tree.c (build_int_cst_type): Likewise. + (size_in_bytes): Don't call force_fit_type on the result. + (int_fits_type_p): Use fit_double_type. + * fold-const.c (fit_double_type): New function. + (force_fit_type): Use it. + * tree.h (fit_double_type): Export. + 2007-01-08 Jan Hubicka <jh@suse.cz> * tree-vectorizer.c (gate_increase_alignment): Fix return type. diff --git a/gcc/builtins.c b/gcc/builtins.c index e97e3bb57cb..a39a4c16241 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -7576,7 +7576,8 @@ fold_builtin_int_roundingfn (tree fndecl, tree arglist) if (! REAL_VALUE_ISNAN (x) && ! REAL_VALUE_ISINF (x)) { tree itype = TREE_TYPE (TREE_TYPE (fndecl)); - tree ftype = TREE_TYPE (arg), result; + tree ftype = TREE_TYPE (arg); + unsigned HOST_WIDE_INT lo2; HOST_WIDE_INT hi, lo; REAL_VALUE_TYPE r; @@ -7602,11 +7603,8 @@ fold_builtin_int_roundingfn (tree fndecl, tree arglist) } REAL_VALUE_TO_INT (&lo, &hi, r); - result = build_int_cst_wide (itype, lo, hi); - result = force_fit_type (result, 0, false, false); - if (TREE_INT_CST_LOW (result) == lo - && TREE_INT_CST_HIGH (result) == hi) - return result; + if (!fit_double_type (lo, hi, &lo2, &hi, itype)) + return build_int_cst_wide (itype, lo2, hi); } } diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 559acf018ad..d082ed34088 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -192,58 +192,44 @@ decode (HOST_WIDE_INT *words, unsigned HOST_WIDE_INT *low, *hi = words[2] + words[3] * BASE; } -/* T is an INT_CST node. OVERFLOWABLE indicates if we are interested - in overflow of the value, when >0 we are only interested in signed - overflow, for <0 we are interested in any overflow. OVERFLOWED - indicates whether overflow has already occurred. CONST_OVERFLOWED - indicates whether constant overflow has already occurred. We force - T's value to be within range of T's type (by setting to 0 or 1 all - the bits outside the type's range). We set TREE_OVERFLOWED if, - OVERFLOWED is nonzero, - or OVERFLOWABLE is >0 and signed overflow occurs - or OVERFLOWABLE is <0 and any overflow occurs - We set TREE_CONSTANT_OVERFLOWED if, - CONST_OVERFLOWED is nonzero - or we set TREE_OVERFLOWED. - We return either the original T, or a copy. */ +/* Force the double-word integer L1, H1 to be within the range of the + integer type TYPE. Stores the properly truncated and sign-extended + double-word integer in *LV, *HV. Returns true if the operation + overflows, that is, argument and result are different. */ -tree -force_fit_type (tree t, int overflowable, - bool overflowed, bool overflowed_const) +int +fit_double_type (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, + unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv, tree type) { - unsigned HOST_WIDE_INT low; - HOST_WIDE_INT high; + unsigned HOST_WIDE_INT low0 = l1; + HOST_WIDE_INT high0 = h1; unsigned int prec; int sign_extended_type; - gcc_assert (TREE_CODE (t) == INTEGER_CST); - - low = TREE_INT_CST_LOW (t); - high = TREE_INT_CST_HIGH (t); - - if (POINTER_TYPE_P (TREE_TYPE (t)) - || TREE_CODE (TREE_TYPE (t)) == OFFSET_TYPE) + if (POINTER_TYPE_P (type) + || TREE_CODE (type) == OFFSET_TYPE) prec = POINTER_SIZE; else - prec = TYPE_PRECISION (TREE_TYPE (t)); + prec = TYPE_PRECISION (type); + /* Size types *are* sign extended. */ - sign_extended_type = (!TYPE_UNSIGNED (TREE_TYPE (t)) - || (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE - && TYPE_IS_SIZETYPE (TREE_TYPE (t)))); + sign_extended_type = (!TYPE_UNSIGNED (type) + || (TREE_CODE (type) == INTEGER_TYPE + && TYPE_IS_SIZETYPE (type))); /* First clear all bits that are beyond the type's precision. */ - if (prec >= 2 * HOST_BITS_PER_WIDE_INT) ; else if (prec > HOST_BITS_PER_WIDE_INT) - high &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT)); + h1 &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT)); else { - high = 0; + h1 = 0; if (prec < HOST_BITS_PER_WIDE_INT) - low &= ~((HOST_WIDE_INT) (-1) << prec); + l1 &= ~((HOST_WIDE_INT) (-1) << prec); } + /* Then do sign extension if necessary. */ if (!sign_extended_type) /* No sign extension */; else if (prec >= 2 * HOST_BITS_PER_WIDE_INT) @@ -251,28 +237,70 @@ force_fit_type (tree t, int overflowable, else if (prec > HOST_BITS_PER_WIDE_INT) { /* Sign extend top half? */ - if (high & ((unsigned HOST_WIDE_INT)1 - << (prec - HOST_BITS_PER_WIDE_INT - 1))) - high |= (HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT); + if (h1 & ((unsigned HOST_WIDE_INT)1 + << (prec - HOST_BITS_PER_WIDE_INT - 1))) + h1 |= (HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT); } else if (prec == HOST_BITS_PER_WIDE_INT) { - if ((HOST_WIDE_INT)low < 0) - high = -1; + if ((HOST_WIDE_INT)l1 < 0) + h1 = -1; } else { /* Sign extend bottom half? */ - if (low & ((unsigned HOST_WIDE_INT)1 << (prec - 1))) + if (l1 & ((unsigned HOST_WIDE_INT)1 << (prec - 1))) { - high = -1; - low |= (HOST_WIDE_INT)(-1) << prec; + h1 = -1; + l1 |= (HOST_WIDE_INT)(-1) << prec; } } + *lv = l1; + *hv = h1; + + /* If the value didn't fit, signal overflow. */ + return l1 != low0 || h1 != high0; +} + +/* T is an INT_CST node. OVERFLOWABLE indicates if we are interested + in overflow of the value, when >0 we are only interested in signed + overflow, for <0 we are interested in any overflow. OVERFLOWED + indicates whether overflow has already occurred. CONST_OVERFLOWED + indicates whether constant overflow has already occurred. We force + T's value to be within range of T's type (by setting to 0 or 1 all + the bits outside the type's range). We set TREE_OVERFLOWED if, + OVERFLOWED is nonzero, + or OVERFLOWABLE is >0 and signed overflow occurs + or OVERFLOWABLE is <0 and any overflow occurs + We set TREE_CONSTANT_OVERFLOWED if, + CONST_OVERFLOWED is nonzero + or we set TREE_OVERFLOWED. + We return either the original T, or a copy. */ + +tree +force_fit_type (tree t, int overflowable, + bool overflowed, bool overflowed_const) +{ + unsigned HOST_WIDE_INT low; + HOST_WIDE_INT high; + int sign_extended_type; + bool overflow; + + gcc_assert (TREE_CODE (t) == INTEGER_CST); + + /* Size types *are* sign extended. */ + sign_extended_type = (!TYPE_UNSIGNED (TREE_TYPE (t)) + || (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE + && TYPE_IS_SIZETYPE (TREE_TYPE (t)))); + + low = TREE_INT_CST_LOW (t); + high = TREE_INT_CST_HIGH (t); + + overflow = fit_double_type (low, high, &low, &high, TREE_TYPE (t)); + /* If the value changed, return a new node. */ - if (overflowed || overflowed_const - || low != TREE_INT_CST_LOW (t) || high != TREE_INT_CST_HIGH (t)) + if (overflowed || overflowed_const || overflow) { t = build_int_cst_wide (TREE_TYPE (t), low, high); diff --git a/gcc/tree.c b/gcc/tree.c index e3eb4be8b05..348d288f50f 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -779,53 +779,14 @@ build_int_cstu (tree type, unsigned HOST_WIDE_INT low) tree build_int_cst_type (tree type, HOST_WIDE_INT low) { - unsigned HOST_WIDE_INT val = (unsigned HOST_WIDE_INT) low; - unsigned HOST_WIDE_INT hi, mask; - unsigned bits; - bool signed_p; - bool negative; + unsigned HOST_WIDE_INT low1; + HOST_WIDE_INT hi; - if (!type) - type = integer_type_node; - - bits = TYPE_PRECISION (type); - signed_p = !TYPE_UNSIGNED (type); - - if (bits >= HOST_BITS_PER_WIDE_INT) - negative = (low < 0); - else - { - /* If the sign bit is inside precision of LOW, use it to determine - the sign of the constant. */ - negative = ((val >> (bits - 1)) & 1) != 0; - - /* Mask out the bits outside of the precision of the constant. */ - mask = (((unsigned HOST_WIDE_INT) 2) << (bits - 1)) - 1; - - if (signed_p && negative) - val |= ~mask; - else - val &= mask; - } - - /* Determine the high bits. */ - hi = (negative ? ~(unsigned HOST_WIDE_INT) 0 : 0); + gcc_assert (type); - /* For unsigned type we need to mask out the bits outside of the type - precision. */ - if (!signed_p) - { - if (bits <= HOST_BITS_PER_WIDE_INT) - hi = 0; - else - { - bits -= HOST_BITS_PER_WIDE_INT; - mask = (((unsigned HOST_WIDE_INT) 2) << (bits - 1)) - 1; - hi &= mask; - } - } + fit_double_type (low, low < 0 ? -1 : 0, &low1, &hi, type); - return build_int_cst_wide (type, val, hi); + return build_int_cst_wide (type, low1, hi); } /* These are the hash table functions for the hash table of INTEGER_CST @@ -1818,9 +1779,6 @@ size_in_bytes (tree type) return size_zero_node; } - if (TREE_CODE (t) == INTEGER_CST) - t = force_fit_type (t, 0, false, false); - return t; } @@ -6009,12 +5967,13 @@ int_fits_type_p (tree c, tree type) tree type_low_bound = TYPE_MIN_VALUE (type); tree type_high_bound = TYPE_MAX_VALUE (type); bool ok_for_low_bound, ok_for_high_bound; - tree tmp; + unsigned HOST_WIDE_INT low; + HOST_WIDE_INT high; /* If at least one bound of the type is a constant integer, we can check ourselves and maybe make a decision. If no such decision is possible, but this type is a subtype, try checking against that. Otherwise, use - force_fit_type, which checks against the precision. + fit_double_type, which checks against the precision. Compute the status for each possibly constant bound, and return if we see one does not match. Use ok_for_xxx_bound for this purpose, assigning -1 @@ -6069,12 +6028,10 @@ int_fits_type_p (tree c, tree type) && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (type))) return int_fits_type_p (c, TREE_TYPE (type)); - /* Or to force_fit_type, if nothing else. */ - tmp = copy_node (c); - TREE_TYPE (tmp) = type; - tmp = force_fit_type (tmp, -1, false, false); - return TREE_INT_CST_HIGH (tmp) == TREE_INT_CST_HIGH (c) - && TREE_INT_CST_LOW (tmp) == TREE_INT_CST_LOW (c); + /* Or to fit_double_type, if nothing else. */ + low = TREE_INT_CST_LOW (c); + high = TREE_INT_CST_HIGH (c); + return !fit_double_type (low, high, &low, &high, type); } /* Subprogram of following function. Called by walk_tree. diff --git a/gcc/tree.h b/gcc/tree.h index 9f2d7076c45..fd9e14a585a 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -4321,6 +4321,8 @@ extern tree fold_indirect_ref_1 (tree, tree); extern tree force_fit_type (tree, int, bool, bool); +extern int fit_double_type (unsigned HOST_WIDE_INT, HOST_WIDE_INT, + unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, tree); extern int add_double_with_sign (unsigned HOST_WIDE_INT, HOST_WIDE_INT, unsigned HOST_WIDE_INT, HOST_WIDE_INT, unsigned HOST_WIDE_INT *, HOST_WIDE_INT *, |