diff options
author | Richard Kenner <kenner@gcc.gnu.org> | 1994-03-25 16:12:56 -0500 |
---|---|---|
committer | Richard Kenner <kenner@gcc.gnu.org> | 1994-03-25 16:12:56 -0500 |
commit | 3122945e76681be8036d7a818310f2c21775d96c (patch) | |
tree | c032a4ada6c674eb4ac98127471c3796a8a25ab1 /gcc/fold-const.c | |
parent | 0273f32645e1c69ccc7a61a5364683dcf4546c62 (diff) | |
download | gcc-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.c | 44 |
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. */ |