aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
authorRichard Kenner <kenner@gcc.gnu.org>1994-03-25 16:12:56 -0500
committerRichard Kenner <kenner@gcc.gnu.org>1994-03-25 16:12:56 -0500
commit3122945e76681be8036d7a818310f2c21775d96c (patch)
treec032a4ada6c674eb4ac98127471c3796a8a25ab1 /gcc/fold-const.c
parent0273f32645e1c69ccc7a61a5364683dcf4546c62 (diff)
downloadgcc-3122945e76681be8036d7a818310f2c21775d96c.zip
gcc-3122945e76681be8036d7a818310f2c21775d96c.tar.gz
gcc-3122945e76681be8036d7a818310f2c21775d96c.tar.bz2
(fold, case *_DIV_EXPR): Correct result when product of constants
overflows. From-SVN: r6900
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r--gcc/fold-const.c44
1 files changed, 29 insertions, 15 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 59da9ac..e2f5fc4 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -4008,30 +4008,44 @@ fold (expr)
tem = const_binop (MULT_EXPR, TREE_OPERAND (arg0, 1), arg1, 0);
/* If it overflows, the result is +/- 1 or zero, depending on
- the signs of the two constants and the division operation. */
+ the signs of the constants and remaining operand and on which
+ division operation is being performed. */
+
if (TREE_OVERFLOW (tem))
{
+ /* 1 if C1 * C2 is negative (i.e., C1 and C2 have
+ different signs). */
+ int c_neg = ((tree_int_cst_sgn (arg1) < 0)
+ == (tree_int_cst_sgn (TREE_OPERAND (arg0, 1)) < 0));
+
switch (code)
{
case EXACT_DIV_EXPR:
+ /* If this overflowed, it couldn't have been exact. */
+ abort ();
+
case TRUNC_DIV_EXPR:
- tem = integer_zero_node;
- break;
+ return omit_one_operand (type, integer_zero_node,
+ TREE_OPERAND (arg0, 0));
+
case FLOOR_DIV_EXPR:
- /* -1 if signs disagree, else 0. */
- tem = (((tree_int_cst_sgn (TREE_OPERAND (arg0, 1)) < 0)
- != (tree_int_cst_sgn (arg1) < 0))
- ? build_int_2 (-1, -1) : integer_zero_node);
- break;
+ /* -1 or zero, depending on signs of remaining
+ operand and constants. */
+ tem = build (c_neg ? GE_EXPR : LE_EXPR, integer_type_node,
+ TREE_OPERAND (arg0, 0),
+ convert (type, integer_zero_node));
+ return fold (build (NEGATE_EXPR, type,
+ convert (type, fold (tem))));
+
case CEIL_DIV_EXPR:
- /* 1 if signs agree, else 0. */
- tem = (((tree_int_cst_sgn (TREE_OPERAND (arg0, 1)) < 0)
- == (tree_int_cst_sgn (arg1) < 0))
- ? integer_one_node : integer_zero_node);
- break;
+ /* Zero or 1, depending on signs of remaining
+ operand and constants. */
+ tem = build (c_neg ? LE_EXPR : GE_EXPR, integer_type_node,
+ TREE_OPERAND (arg0, 0),
+ convert (type, integer_zero_node));
+
+ return convert (type, fold (tem));
}
-
- return omit_one_operand (type, tem, TREE_OPERAND (arg0, 0));
}
else
/* If no overflow, divide by C1*C2. */