This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[Committed] PR26561: Distinguish -Inf overflow in fold_div_compare
- From: Roger Sayle <roger at eyesopen dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 9 Mar 2006 07:46:45 -0700 (MST)
- Subject: [Committed] PR26561: Distinguish -Inf overflow in fold_div_compare
My recent reordering of transformations for comparison operators in
fold_binary exposed some latent bugs in fold_div_compare. Unfortunately,
although my previous fix in this code resolved the exposed failure of
gcc.c-torture/execute/divcmp-3.c it didn't completely resolve the issue
and caused the failure of c34004a and two other tests in the Ada
testsuite.
The real problem with this set of optimizations was correctly analyzed
by Eric Botcazou who determined that we need to distinguish positive
and negative overflow where the code currently checks TREE_OVERFLOW.
Hence in X/C1 < C2, we attempt to transform this into X < C1*C2, but
if we overflow we optimize this to true. This is correct for overflow
to +Inf, but we should optimize this to false, if we overflow (underflow?)
towards -Inf.
The fix below is to introduce a neg_overflow flag that we set
appropriately based upon the signs of C1 and C2 if the comparison
and division use signed types.
The following patch has been tested on i686-pc-linux-gnu with a full
"make bootstrap", all default languages including Ada, and regression
tested with a top-level "make -k check" with no new failures and the
resolution of three ACATs failures.
Many thanks to Eric. Committed to mainline as revision 111862.
2006-03-09 Roger Sayle <roger@eyesopen.com>
Eric Botcazou <ebotcazou@libertysurf.fr>
PR middle-end/26561
* fold-const.c (fold_div_compare): When optimizing X/C1 op C2 as
X op C3, consider whether C3 overflows towards +Inf or -Inf.
* gcc.c-torture/execute/divcmp-5.c: New test case.
Index: fold-const.c
===================================================================
*** fold-const.c (revision 111839)
--- fold-const.c (working copy)
*************** fold_div_compare (enum tree_code code, t
*** 6014,6019 ****
--- 6014,6020 ----
tree arg01 = TREE_OPERAND (arg0, 1);
unsigned HOST_WIDE_INT lpart;
HOST_WIDE_INT hpart;
+ bool neg_overflow;
int overflow;
/* We have to do this the hard way to detect unsigned overflow.
*************** fold_div_compare (enum tree_code code, t
*** 6024,6029 ****
--- 6025,6031 ----
TREE_INT_CST_HIGH (arg1), &lpart, &hpart);
prod = build_int_cst_wide (TREE_TYPE (arg00), lpart, hpart);
prod = force_fit_type (prod, -1, overflow, false);
+ neg_overflow = false;
if (TYPE_UNSIGNED (TREE_TYPE (arg0)))
{
*************** fold_div_compare (enum tree_code code, t
*** 6046,6051 ****
--- 6048,6054 ----
switch (tree_int_cst_sgn (arg1))
{
case -1:
+ neg_overflow = true;
lo = int_const_binop (MINUS_EXPR, prod, tmp, 0);
hi = prod;
break;
*************** fold_div_compare (enum tree_code code, t
*** 6083,6089 ****
break;
case 1:
! lo = int_const_binop (PLUS_EXPR, prod, tmp, 0);
hi = prod;
break;
--- 6086,6093 ----
break;
case 1:
! neg_overflow = true;
! lo = int_const_binop (PLUS_EXPR, prod, tmp, 0);
hi = prod;
break;
*************** fold_div_compare (enum tree_code code, t
*** 6114,6135 ****
case LT_EXPR:
if (TREE_OVERFLOW (lo))
! return omit_one_operand (type, integer_one_node, arg00);
return fold_build2 (LT_EXPR, type, arg00, lo);
case LE_EXPR:
if (TREE_OVERFLOW (hi))
! return omit_one_operand (type, integer_one_node, arg00);
return fold_build2 (LE_EXPR, type, arg00, hi);
case GT_EXPR:
if (TREE_OVERFLOW (hi))
! return omit_one_operand (type, integer_zero_node, arg00);
return fold_build2 (GT_EXPR, type, arg00, hi);
case GE_EXPR:
if (TREE_OVERFLOW (lo))
! return omit_one_operand (type, integer_zero_node, arg00);
return fold_build2 (GE_EXPR, type, arg00, lo);
default:
--- 6118,6151 ----
case LT_EXPR:
if (TREE_OVERFLOW (lo))
! {
! tmp = neg_overflow ? integer_zero_node : integer_one_node;
! return omit_one_operand (type, tmp, arg00);
! }
return fold_build2 (LT_EXPR, type, arg00, lo);
case LE_EXPR:
if (TREE_OVERFLOW (hi))
! {
! tmp = neg_overflow ? integer_zero_node : integer_one_node;
! return omit_one_operand (type, tmp, arg00);
! }
return fold_build2 (LE_EXPR, type, arg00, hi);
case GT_EXPR:
if (TREE_OVERFLOW (hi))
! {
! tmp = neg_overflow ? integer_one_node : integer_zero_node;
! return omit_one_operand (type, tmp, arg00);
! }
return fold_build2 (GT_EXPR, type, arg00, hi);
case GE_EXPR:
if (TREE_OVERFLOW (lo))
! {
! tmp = neg_overflow ? integer_one_node : integer_zero_node;
! return omit_one_operand (type, tmp, arg00);
! }
return fold_build2 (GE_EXPR, type, arg00, lo);
default:
/* PR middle-end/26561 */
extern void abort(void);
int always_one_1 (int a)
{
if (a/100 >= -999999999)
return 1;
else
return 0;
}
int always_one_2 (int a)
{
if (a/100 < -999999999)
return 0;
else
return 1;
}
int main(void)
{
if (always_one_1 (0) != 1)
abort ();
if (always_one_2 (0) != 1)
abort ();
return 0;
}
Roger
--