summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>2006-10-28 18:03:21 +0000
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>2006-10-28 18:03:21 +0000
commit26e1261a7d5763cee4e7280239cd64e0ad6b3cdb (patch)
treecc83b84ce7c4da661546d58027790862ce4092db /gcc
parentef2f1a1042205241206d078c68f75bcfe1170e15 (diff)
downloadgcc-26e1261a7d5763cee4e7280239cd64e0ad6b3cdb.tar.gz
2006-10-28 Richard Guenther <rguenther@suse.de>
PR middle-end/26899 * fold-const.c (maybe_canonicalize_comparison_1): Helper for maybe_canonicalize_comparison. (maybe_canonicalize_comparison): New function for canonicalizing comparison trees. (fold_comparison): Call it to canonicalize comparisons with constants involved. * gcc.dg/tree-ssa/pr26899.c: New testcase. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@118106 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/fold-const.c124
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr26899.c10
4 files changed, 149 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e64b3f487de..fe590bf2ac2 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,15 @@
2006-10-28 Richard Guenther <rguenther@suse.de>
+ PR middle-end/26899
+ * fold-const.c (maybe_canonicalize_comparison_1): Helper
+ for maybe_canonicalize_comparison.
+ (maybe_canonicalize_comparison): New function for canonicalizing
+ comparison trees.
+ (fold_comparison): Call it to canonicalize comparisons with
+ constants involved.
+
+2006-10-28 Richard Guenther <rguenther@suse.de>
+
PR target/28806
* builtins.c (expand_builtin_int_roundingfn_2): Expand
BUILT_IN_LROUND and BUILT_IN_LLROUND from here.
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 571a7e84612..32e64c99e1f 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -7749,6 +7749,126 @@ fold_minmax (enum tree_code code, tree type, tree op0, tree op1)
return NULL_TREE;
}
+/* Helper that tries to canonicalize the comparison ARG0 CODE ARG1
+ by changing CODE to reduce the magnitude of constants involved in
+ ARG0 of the comparison.
+ Returns a canonicalized comparison tree if a simplification was
+ possible, otherwise returns NULL_TREE. */
+
+static tree
+maybe_canonicalize_comparison_1 (enum tree_code code, tree type,
+ tree arg0, tree arg1)
+{
+ enum tree_code code0 = TREE_CODE (arg0);
+ tree t, cst0 = NULL_TREE;
+ int sgn0;
+ bool swap = false;
+
+ /* Match A +- CST code arg1 and CST code arg1. */
+ if (!(((code0 == MINUS_EXPR
+ || code0 == PLUS_EXPR)
+ && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
+ || code0 == INTEGER_CST))
+ return NULL_TREE;
+
+ /* Identify the constant in arg0 and its sign. */
+ if (code0 == INTEGER_CST)
+ cst0 = arg0;
+ else
+ cst0 = TREE_OPERAND (arg0, 1);
+ sgn0 = tree_int_cst_sgn (cst0);
+
+ /* Overflowed constants and zero will cause problems. */
+ if (integer_zerop (cst0)
+ || TREE_OVERFLOW (cst0))
+ return NULL_TREE;
+
+ /* See if we can reduce the mangitude of the constant in
+ arg0 by changing the comparison code. */
+ if (code0 == INTEGER_CST)
+ {
+ /* CST <= arg1 -> CST-1 < arg1. */
+ if (code == LE_EXPR && sgn0 == 1)
+ code = LT_EXPR;
+ /* -CST < arg1 -> -CST-1 <= arg1. */
+ else if (code == LT_EXPR && sgn0 == -1)
+ code = LE_EXPR;
+ /* CST > arg1 -> CST-1 >= arg1. */
+ else if (code == GT_EXPR && sgn0 == 1)
+ code = GE_EXPR;
+ /* -CST >= arg1 -> -CST-1 > arg1. */
+ else if (code == GE_EXPR && sgn0 == -1)
+ code = GT_EXPR;
+ else
+ return NULL_TREE;
+ /* arg1 code' CST' might be more canonical. */
+ swap = true;
+ }
+ else
+ {
+ /* 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;
+ }
+
+ /* Now build the constant reduced in magnitude. */
+ t = int_const_binop (sgn0 == -1 ? PLUS_EXPR : MINUS_EXPR,
+ cst0, build_int_cst (TREE_TYPE (cst0), 1), 0);
+ if (code0 != INTEGER_CST)
+ t = fold_build2 (code0, TREE_TYPE (arg0), TREE_OPERAND (arg0, 0), t);
+
+ /* If swapping might yield to a more canonical form, do so. */
+ if (swap)
+ return fold_build2 (swap_tree_comparison (code), type, arg1, t);
+ else
+ return fold_build2 (code, type, t, arg1);
+}
+
+/* Canonicalize the comparison ARG0 CODE ARG1 with type TYPE with undefined
+ overflow further. Try to decrease the magnitude of constants involved
+ by changing LE_EXPR and GE_EXPR to LT_EXPR and GT_EXPR or vice versa
+ and put sole constants at the second argument position.
+ Returns the canonicalized tree if changed, otherwise NULL_TREE. */
+
+static tree
+maybe_canonicalize_comparison (enum tree_code code, tree type,
+ tree arg0, tree arg1)
+{
+ tree t;
+
+ /* In principle pointers also have undefined overflow behavior,
+ but that causes problems elsewhere. */
+ if ((flag_wrapv || flag_trapv)
+ || (TYPE_UNSIGNED (TREE_TYPE (arg0))
+ && !POINTER_TYPE_P (TREE_TYPE (arg0))))
+ return NULL_TREE;
+
+ /* Try canonicalization by simplifying arg0. */
+ t = maybe_canonicalize_comparison_1 (code, type, arg0, arg1);
+ if (t)
+ return t;
+
+ /* Try canonicalization by simplifying arg1 using the swapped
+ comparsion. */
+ code = swap_tree_comparison (code);
+ return maybe_canonicalize_comparison_1 (code, type, arg1, arg0);
+}
+
/* Subroutine of fold_binary. This routine performs all of the
transformations that are common to the equality/inequality
operators (EQ_EXPR and NE_EXPR) and the ordering operators
@@ -7877,6 +7997,10 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1)
variable2);
}
+ tem = maybe_canonicalize_comparison (code, type, arg0, arg1);
+ if (tem)
+ return tem;
+
if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
{
tree targ0 = strip_float_extensions (arg0);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 8f5a43528bf..e2096ba55ae 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,10 @@
2006-10-28 Richard Guenther <rguenther@suse.de>
+ PR middle-end/26899
+ * gcc.dg/tree-ssa/pr26899.c: New testcase.
+
+2006-10-28 Richard Guenther <rguenther@suse.de>
+
PR target/28806
* gcc.target/i386/math-torture/lround.c: New testcase.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr26899.c b/gcc/testsuite/gcc.dg/tree-ssa/pr26899.c
new file mode 100644
index 00000000000..5e19f56d94d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr26899.c
@@ -0,0 +1,10 @@
+/* { dg-options "-fdump-tree-gimple" } */
+
+int foo (int i, int j)
+{
+ return (i < j + 1) || (j > i - 1);
+}
+
+/* { dg-final { scan-tree-dump "j >= i" "gimple" } } */
+/* { dg-final { cleanup-tree-dump "gimple" } } */
+