aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/convert.c18
-rw-r--r--gcc/fold-const.c19
3 files changed, 35 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 197ac51..30640c7 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2002-06-14 Eric Botcazou <ebotcazou@multimania.com>
+
+ * convert.c (convert_to_integer) [LSHIFT_EXPR]: Don't pass
+ the truncation down when the target type is signed.
+ [trunc1]: Use unsigned arithmetic for LSHIFT_EXPR.
+ * fold-const.c (extract_muldiv) [NOP_EXPR]: Don't pass through
+ the conversion if the target type is a smaller type.
+
2002-06-14 Richard Henderson <rth@redhat.com>
* fold-const.c (fold) [compare ops]: Move X>=C / X<C transfomation
diff --git a/gcc/convert.c b/gcc/convert.c
index 970b05c..e90ce4c 100644
--- a/gcc/convert.c
+++ b/gcc/convert.c
@@ -229,9 +229,11 @@ convert_to_integer (type, expr)
case LSHIFT_EXPR:
/* We can pass truncation down through left shifting
- when the shift count is a nonnegative constant. */
+ when the shift count is a nonnegative constant and
+ the target type is unsigned. */
if (TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST
&& tree_int_cst_sgn (TREE_OPERAND (expr, 1)) >= 0
+ && TREE_UNSIGNED (type)
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
{
/* If shift count is less than the width of the truncated type,
@@ -313,12 +315,22 @@ convert_to_integer (type, expr)
/* Don't do unsigned arithmetic where signed was wanted,
or vice versa.
Exception: if both of the original operands were
- unsigned then can safely do the work as unsigned.
+ unsigned then we can safely do the work as unsigned.
+ Exception: shift operations take their type solely
+ from the first argument.
+ Exception: the LSHIFT_EXPR case above requires that
+ we perform this operation unsigned lest we produce
+ signed-overflow undefinedness.
And we may need to do it as unsigned
if we truncate to the original size. */
if (TREE_UNSIGNED (TREE_TYPE (expr))
|| (TREE_UNSIGNED (TREE_TYPE (arg0))
- && TREE_UNSIGNED (TREE_TYPE (arg1))))
+ && (TREE_UNSIGNED (TREE_TYPE (arg1))
+ || ex_form == LSHIFT_EXPR
+ || ex_form == RSHIFT_EXPR
+ || ex_form == LROTATE_EXPR
+ || ex_form == RROTATE_EXPR))
+ || ex_form == LSHIFT_EXPR)
typex = (*lang_hooks.types.unsigned_type) (typex);
else
typex = (*lang_hooks.types.signed_type) (typex);
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 31bcddb..5c04d78 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -3969,17 +3969,22 @@ extract_muldiv (t, c, code, wide_type)
break;
case CONVERT_EXPR: case NON_LVALUE_EXPR: case NOP_EXPR:
- /* If op0 is an expression, and is unsigned, and the type is
- smaller than ctype, then we cannot widen the expression. */
+ /* If op0 is an expression ... */
if ((TREE_CODE_CLASS (TREE_CODE (op0)) == '<'
|| TREE_CODE_CLASS (TREE_CODE (op0)) == '1'
|| TREE_CODE_CLASS (TREE_CODE (op0)) == '2'
|| TREE_CODE_CLASS (TREE_CODE (op0)) == 'e')
- && TREE_UNSIGNED (TREE_TYPE (op0))
- && ! (TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE
- && TYPE_IS_SIZETYPE (TREE_TYPE (op0)))
- && (GET_MODE_SIZE (TYPE_MODE (ctype))
- > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))))
+ /* ... and is unsigned, and its type is smaller than ctype,
+ then we cannot pass through as widening. */
+ && ((TREE_UNSIGNED (TREE_TYPE (op0))
+ && ! (TREE_CODE (TREE_TYPE (op0)) == INTEGER_TYPE
+ && TYPE_IS_SIZETYPE (TREE_TYPE (op0)))
+ && (GET_MODE_SIZE (TYPE_MODE (ctype))
+ > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))))
+ /* ... or its type is larger than ctype,
+ then we cannot pass through this truncation. */
+ || (GET_MODE_SIZE (TYPE_MODE (ctype))
+ < GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0))))))
break;
/* Pass the constant down and see if we can make a simplification. If