This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH][no-undefined-overflow] More comparison handling
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Fri, 6 Mar 2009 17:07:02 +0100 (CET)
- Subject: [PATCH][no-undefined-overflow] More comparison handling
This transitiones A +- CST code arg1 canonicalization and
X +- C1 CMP Y +- C2 folding.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to the
branch.
Richard.
2009-03-06 Richard Guenther <rguenther@suse.de>
* fold-const.c (maybe_canonicalize_comparison_1): Canonicalize
A +- CST code arg1 if A +- CST does not overflow.
(fold_comparison): Transform X +- C1 CMP Y +- C2 to
X CMP Y +- C2 +- C1 if X +- C1 does not overflow and C2 +- C1
is less in magnitude than C2.
Index: no-undefined-overflow/gcc/fold-const.c
===================================================================
*** no-undefined-overflow.orig/gcc/fold-const.c 2009-03-06 16:04:48.000000000 +0100
--- no-undefined-overflow/gcc/fold-const.c 2009-03-06 16:33:04.000000000 +0100
*************** maybe_canonicalize_comparison_1 (enum tr
*** 8685,8697 ****
bool swap = false;
/* Match A +- CST code arg1 and CST code arg1. We can change the
! first form only if overflow is undefined. */
! if (!((TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))
! /* In principle pointers also have undefined overflow behavior,
but that causes problems elsewhere. */
! && !POINTER_TYPE_P (TREE_TYPE (arg0))
! && (code0 == MINUS_EXPR
! || code0 == PLUS_EXPR)
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
|| code0 == INTEGER_CST))
return NULL_TREE;
--- 8685,8695 ----
bool swap = false;
/* Match A +- CST code arg1 and CST code arg1. We can change the
! first form only if the operation does not wrap. */
! if (!((/* In principle pointer arithmetic also can be non-wrapping,
but that causes problems elsewhere. */
! (code0 == MINUSNV_EXPR
! || code0 == PLUSNV_EXPR)
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
|| code0 == INTEGER_CST))
return NULL_TREE;
*************** maybe_canonicalize_comparison_1 (enum tr
*** 8733,8755 ****
{
/* A - CST < arg1 -> A - CST-1 <= arg1. */
if (code == LT_EXPR
! && code0 == ((sgn0 == -1) ? PLUS_EXPR : MINUS_EXPR))
code = LE_EXPR;
/* A + CST > arg1 -> A + CST-1 >= arg1. */
else if (code == GT_EXPR
! && code0 == ((sgn0 == -1) ? MINUS_EXPR : PLUS_EXPR))
code = GE_EXPR;
/* A + CST <= arg1 -> A + CST-1 < arg1. */
else if (code == LE_EXPR
! && code0 == ((sgn0 == -1) ? MINUS_EXPR : PLUS_EXPR))
code = LT_EXPR;
/* A - CST >= arg1 -> A - CST-1 > arg1. */
else if (code == GE_EXPR
! && code0 == ((sgn0 == -1) ? PLUS_EXPR : MINUS_EXPR))
code = GT_EXPR;
else
return NULL_TREE;
! *strict_overflow_p = true;
}
/* Now build the constant reduced in magnitude. But not if that
--- 8731,8754 ----
{
/* A - CST < arg1 -> A - CST-1 <= arg1. */
if (code == LT_EXPR
! && code0 == ((sgn0 == -1) ? PLUSNV_EXPR : MINUSNV_EXPR))
code = LE_EXPR;
/* A + CST > arg1 -> A + CST-1 >= arg1. */
else if (code == GT_EXPR
! && code0 == ((sgn0 == -1) ? MINUSNV_EXPR : PLUSNV_EXPR))
code = GE_EXPR;
/* A + CST <= arg1 -> A + CST-1 < arg1. */
else if (code == LE_EXPR
! && code0 == ((sgn0 == -1) ? MINUSNV_EXPR : PLUSNV_EXPR))
code = LT_EXPR;
/* A - CST >= arg1 -> A - CST-1 > arg1. */
else if (code == GE_EXPR
! && code0 == ((sgn0 == -1) ? PLUSNV_EXPR : MINUSNV_EXPR))
code = GT_EXPR;
else
return NULL_TREE;
! if (!TREE_NO_WARNING (arg0))
! *strict_overflow_p = true;
}
/* Now build the constant reduced in magnitude. But not if that
*************** maybe_canonicalize_comparison_1 (enum tr
*** 8767,8772 ****
--- 8766,8773 ----
t = int_const_binop (sgn0 == -1 ? PLUS_EXPR : MINUS_EXPR,
cst0, build_int_cst (TREE_TYPE (cst0), 1), 0);
+ /* If A - CST didn't overflow so does A - (CST - 1). So it is safe
+ to keep the *NV_EXPR variants. */
if (code0 != INTEGER_CST)
t = fold_build2 (code0, TREE_TYPE (arg0), TREE_OPERAND (arg0, 0), t);
*************** fold_comparison (enum tree_code code, tr
*** 9112,9163 ****
}
/* Transform comparisons of the form X +- C1 CMP Y +- C2 to
! X CMP Y +- C2 +- C1 for signed X, Y. This is valid if
! the resulting offset is smaller in absolute value than the
original one. */
! if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))
! && (TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
! && (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
! && !TREE_OVERFLOW (TREE_OPERAND (arg0, 1)))
! && (TREE_CODE (arg1) == PLUS_EXPR || TREE_CODE (arg1) == MINUS_EXPR)
! && (TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
! && !TREE_OVERFLOW (TREE_OPERAND (arg1, 1))))
{
tree const1 = TREE_OPERAND (arg0, 1);
tree const2 = TREE_OPERAND (arg1, 1);
tree variable1 = TREE_OPERAND (arg0, 0);
tree variable2 = TREE_OPERAND (arg1, 0);
tree cst;
const char * const warnmsg = G_("assuming signed overflow does not "
"occur when combining constants around "
"a comparison");
/* Put the constant on the side where it doesn't overflow and is
! of lower absolute value than before. */
! cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1)
! ? MINUS_EXPR : PLUS_EXPR,
! const2, const1, 0);
! if (!TREE_OVERFLOW (cst)
! && tree_int_cst_compare (const2, cst) == tree_int_cst_sgn (const2))
{
! fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON);
! return fold_build2 (code, type,
! variable1,
! fold_build2 (TREE_CODE (arg1), TREE_TYPE (arg1),
! variable2, cst));
}
! cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1)
! ? MINUS_EXPR : PLUS_EXPR,
! const1, const2, 0);
! if (!TREE_OVERFLOW (cst)
! && tree_int_cst_compare (const1, cst) == tree_int_cst_sgn (const1))
{
! fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON);
! return fold_build2 (code, type,
! fold_build2 (TREE_CODE (arg0), TREE_TYPE (arg0),
! variable1, cst),
! variable2);
}
}
--- 9113,9183 ----
}
/* Transform comparisons of the form X +- C1 CMP Y +- C2 to
! X CMP Y +- C2 +- C1 if X +- C1 does not overflow.. This is then
! valid if the resulting offset is smaller in absolute value than the
original one. */
! if ((((TREE_CODE (arg0) == PLUSNV_EXPR || TREE_CODE (arg0) == MINUSNV_EXPR)
! && (PLUS_EXPR_P (arg1) || MINUS_EXPR_P (arg1)))
! || ((TREE_CODE (arg1) == PLUSNV_EXPR || TREE_CODE (arg1) == MINUSNV_EXPR)
! && (PLUS_EXPR_P (arg0) || MINUS_EXPR_P (arg0))))
! && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
! && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST)
{
tree const1 = TREE_OPERAND (arg0, 1);
tree const2 = TREE_OPERAND (arg1, 1);
tree variable1 = TREE_OPERAND (arg0, 0);
tree variable2 = TREE_OPERAND (arg1, 0);
tree cst;
+ unsigned HOST_WIDE_INT low;
+ HOST_WIDE_INT hi;
+ int overflow;
const char * const warnmsg = G_("assuming signed overflow does not "
"occur when combining constants around "
"a comparison");
/* Put the constant on the side where it doesn't overflow and is
! of lower absolute value than before if the operation on
! the other side doesn't overflow. */
! if (TREE_CODE (arg0) == PLUSNV_EXPR || TREE_CODE (arg0) == MINUSNV_EXPR)
{
! overflow = int_const_binop_1 ((strip_nv (TREE_CODE (arg0))
! == strip_nv (TREE_CODE (arg1)))
! ? MINUS_EXPR : PLUS_EXPR,
! const2, const1, &low, &hi);
! overflow |= fit_double_type (low, hi, &low, &hi, TREE_TYPE (arg1));
! cst = build_int_cst_wide (TREE_TYPE (arg1), low, hi);
! if (!overflow
! && tree_int_cst_compare (const2, cst) == tree_int_cst_sgn (const2))
! {
! if (!TREE_NO_WARNING (arg0))
! fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON);
! return fold_build2 (code, type,
! variable1,
! fold_build2 (strip_nv (TREE_CODE (arg1)),
! TREE_TYPE (arg1),
! variable2, cst));
! }
}
! if (TREE_CODE (arg1) == PLUSNV_EXPR || TREE_CODE (arg1) == MINUSNV_EXPR)
{
! overflow = int_const_binop_1 ((strip_nv (TREE_CODE (arg0))
! == strip_nv (TREE_CODE (arg1)))
! ? MINUS_EXPR : PLUS_EXPR,
! const1, const2, &low, &hi);
! overflow |= fit_double_type (low, hi, &low, &hi, TREE_TYPE (arg0));
! cst = build_int_cst_wide (TREE_TYPE (arg0), low, hi);
! if (!overflow
! && tree_int_cst_compare (const1, cst) == tree_int_cst_sgn (const1))
! {
! if (!TREE_NO_WARNING (arg1))
! fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON);
! return fold_build2 (code, type,
! fold_build2 (strip_nv (TREE_CODE (arg0)),
! TREE_TYPE (arg0),
! variable1, cst),
! variable2);
! }
}
}