aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree.c
diff options
context:
space:
mode:
authorZdenek Dvorak <dvorakz@suse.cz>2005-02-02 23:13:53 +0000
committerZdenek Dvorak <dvorakz@suse.cz>2005-02-02 23:13:53 +0000
commit61f703151f3f1d0e92c747ef0ecdbaa48c14b361 (patch)
tree3537b64131b90538c5df621e848c272621fac78d /gcc/tree.c
parent6bba1e5ade2ca726492e8952209ca9b1b3c4738c (diff)
* tree.c (build_int_cst_type): Take sign of the value into account
when deciding whether sign extend the value. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@94633 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree.c')
-rw-r--r--gcc/tree.c47
1 files changed, 35 insertions, 12 deletions
diff --git a/gcc/tree.c b/gcc/tree.c
index 39309ffbfe5..6afc17f1f46 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -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