diff options
author | Zdenek Dvorak <dvorakz@suse.cz> | 2005-02-03 00:13:53 +0100 |
---|---|---|
committer | Zdenek Dvorak <rakdver@gcc.gnu.org> | 2005-02-02 23:13:53 +0000 |
commit | 89d12f5d49829d3dbf9a78040b88df833923c0df (patch) | |
tree | 3537b64131b90538c5df621e848c272621fac78d | |
parent | 740ca4b2b10f7b6bd13568988b659b436143b1a9 (diff) | |
download | gcc-89d12f5d49829d3dbf9a78040b88df833923c0df.zip gcc-89d12f5d49829d3dbf9a78040b88df833923c0df.tar.gz gcc-89d12f5d49829d3dbf9a78040b88df833923c0df.tar.bz2 |
tree.c (build_int_cst_type): Take sign of the value into account when deciding whether sign extend the value.
* tree.c (build_int_cst_type): Take sign of the value into account
when deciding whether sign extend the value.
From-SVN: r94633
-rw-r--r-- | gcc/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/tree.c | 47 |
2 files changed, 40 insertions, 12 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 21fe9ba..31c8ea8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2005-02-02 Zdenek Dvorak <dvorakz@suse.cz> + + * tree.c (build_int_cst_type): Take sign of the value into account + when deciding whether sign extend the value. + 2005-02-02 Joseph S. Myers <joseph@codesourcery.com> PR c/18502 @@ -497,39 +497,62 @@ build_int_cstu (tree type, unsigned HOST_WIDE_INT low) return build_int_cst_wide (type, low, 0); } -/* Create an INT_CST node with a LOW value zero or sign extended depending - on the type. */ +/* Create an INT_CST node with a LOW value in TYPE. The value is sign extended + if it is negative. This function is similar to build_int_cst, but + the extra bits outside of the type precision are cleared. Constants + with these extra bits may confuse the fold so that it detects overflows + even in cases when they do not occur, and in general should be avoided. + We cannot however make this a default behavior of build_int_cst without + more intrusive changes, since there are parts of gcc that rely on the extra + precision of the integer constants. */ 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; unsigned bits; bool signed_p; bool negative; - tree ret; if (!type) type = integer_type_node; bits = TYPE_PRECISION (type); signed_p = !TYPE_UNSIGNED (type); - negative = ((val >> (bits - 1)) & 1) != 0; - if (signed_p && negative) + if (bits >= HOST_BITS_PER_WIDE_INT) + negative = (low < 0); + else { - if (bits < HOST_BITS_PER_WIDE_INT) + /* 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. */ + if (signed_p && negative) val = val | ((~(unsigned HOST_WIDE_INT) 0) << bits); - ret = build_int_cst_wide (type, val, ~(unsigned HOST_WIDE_INT) 0); + else + val = val & ~((~(unsigned HOST_WIDE_INT) 0) << bits); } - else + + /* Determine the high bits. */ + hi = (negative ? ~(unsigned HOST_WIDE_INT) 0 : 0); + + /* 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) - val = val & ~((~(unsigned HOST_WIDE_INT) 0) << bits); - ret = build_int_cst_wide (type, val, 0); + if (bits <= HOST_BITS_PER_WIDE_INT) + hi = 0; + else + { + bits -= HOST_BITS_PER_WIDE_INT; + hi = hi & ~((~(unsigned HOST_WIDE_INT) 0) << bits); + } } - return ret; + return build_int_cst_wide (type, val, hi); } /* These are the hash table functions for the hash table of INTEGER_CST |