summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2012-12-06 14:37:09 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2012-12-06 14:37:09 +0000
commit7e9f37dcf7f0e45f051b518acc14a3c1e143233b (patch)
tree69d8a57a66b0f88599b49c7300a7e116451e88ce
parent747f0d2a917dbbd49282158a6e8b331a1364b1d1 (diff)
downloadppe42-gcc-7e9f37dcf7f0e45f051b518acc14a3c1e143233b.tar.gz
ppe42-gcc-7e9f37dcf7f0e45f051b518acc14a3c1e143233b.zip
PR c++/55137
* fold-const.c (fold_binary_loc) <associate>: Don't introduce TREE_OVERFLOW through reassociation. If type doesn't have defined overflow, but one or both of the operands do, use the wrapping type for reassociation and only convert to type at the end. * g++.dg/opt/pr55137.C: New test. * gcc.c-torture/execute/pr55137.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@194250 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/fold-const.c68
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/opt/pr55137.C4
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr55137.c30
5 files changed, 91 insertions, 25 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6b63bc23738..348a6f6a0bb 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2012-12-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/55137
+ * fold-const.c (fold_binary_loc) <associate>: Don't introduce
+ TREE_OVERFLOW through reassociation. If type doesn't have defined
+ overflow, but one or both of the operands do, use the wrapping type
+ for reassociation and only convert to type at the end.
+
2012-12-06 Richard Biener <rguenther@suse.de>
* gimple-fold.c (fold_stmt_1): Remove code handling folding
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 071fb8c15ab..0a8b90a5d09 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -10348,6 +10348,7 @@ fold_binary_loc (location_t loc,
{
tree var0, con0, lit0, minus_lit0;
tree var1, con1, lit1, minus_lit1;
+ tree atype = type;
bool ok = true;
/* Split both trees into variables, constants, and literals. Then
@@ -10363,11 +10364,25 @@ fold_binary_loc (location_t loc,
if (code == MINUS_EXPR)
code = PLUS_EXPR;
- /* With undefined overflow we can only associate constants with one
- variable, and constants whose association doesn't overflow. */
+ /* With undefined overflow prefer doing association in a type
+ which wraps on overflow, if that is one of the operand types. */
if ((POINTER_TYPE_P (type) && POINTER_TYPE_OVERFLOW_UNDEFINED)
|| (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_WRAPS (type)))
{
+ if (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+ && TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0)))
+ atype = TREE_TYPE (arg0);
+ else if (INTEGRAL_TYPE_P (TREE_TYPE (arg1))
+ && TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg1)))
+ atype = TREE_TYPE (arg1);
+ gcc_assert (TYPE_PRECISION (atype) == TYPE_PRECISION (type));
+ }
+
+ /* With undefined overflow we can only associate constants with one
+ variable, and constants whose association doesn't overflow. */
+ if ((POINTER_TYPE_P (atype) && POINTER_TYPE_OVERFLOW_UNDEFINED)
+ || (INTEGRAL_TYPE_P (atype) && !TYPE_OVERFLOW_WRAPS (atype)))
+ {
if (var0 && var1)
{
tree tmp0 = var0;
@@ -10378,14 +10393,14 @@ fold_binary_loc (location_t loc,
if (CONVERT_EXPR_P (tmp0)
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (tmp0, 0)))
&& (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (tmp0, 0)))
- <= TYPE_PRECISION (type)))
+ <= TYPE_PRECISION (atype)))
tmp0 = TREE_OPERAND (tmp0, 0);
if (TREE_CODE (tmp1) == NEGATE_EXPR)
tmp1 = TREE_OPERAND (tmp1, 0);
if (CONVERT_EXPR_P (tmp1)
&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (tmp1, 0)))
&& (TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (tmp1, 0)))
- <= TYPE_PRECISION (type)))
+ <= TYPE_PRECISION (atype)))
tmp1 = TREE_OPERAND (tmp1, 0);
/* The only case we can still associate with two variables
is if they are the same, modulo negation and bit-pattern
@@ -10393,16 +10408,6 @@ fold_binary_loc (location_t loc,
if (!operand_equal_p (tmp0, tmp1, 0))
ok = false;
}
-
- if (ok && lit0 && lit1)
- {
- tree tmp0 = fold_convert (type, lit0);
- tree tmp1 = fold_convert (type, lit1);
-
- if (!TREE_OVERFLOW (tmp0) && !TREE_OVERFLOW (tmp1)
- && TREE_OVERFLOW (fold_build2 (code, type, tmp0, tmp1)))
- ok = false;
- }
}
/* Only do something if we found more than two objects. Otherwise,
@@ -10413,10 +10418,16 @@ fold_binary_loc (location_t loc,
+ (lit0 != 0) + (lit1 != 0)
+ (minus_lit0 != 0) + (minus_lit1 != 0))))
{
- var0 = associate_trees (loc, var0, var1, code, type);
- con0 = associate_trees (loc, con0, con1, code, type);
- lit0 = associate_trees (loc, lit0, lit1, code, type);
- minus_lit0 = associate_trees (loc, minus_lit0, minus_lit1, code, type);
+ bool any_overflows = false;
+ if (lit0) any_overflows |= TREE_OVERFLOW (lit0);
+ if (lit1) any_overflows |= TREE_OVERFLOW (lit1);
+ if (minus_lit0) any_overflows |= TREE_OVERFLOW (minus_lit0);
+ if (minus_lit1) any_overflows |= TREE_OVERFLOW (minus_lit1);
+ var0 = associate_trees (loc, var0, var1, code, atype);
+ con0 = associate_trees (loc, con0, con1, code, atype);
+ lit0 = associate_trees (loc, lit0, lit1, code, atype);
+ minus_lit0 = associate_trees (loc, minus_lit0, minus_lit1,
+ code, atype);
/* Preserve the MINUS_EXPR if the negative part of the literal is
greater than the positive part. Otherwise, the multiplicative
@@ -10430,38 +10441,45 @@ fold_binary_loc (location_t loc,
&& tree_int_cst_lt (lit0, minus_lit0))
{
minus_lit0 = associate_trees (loc, minus_lit0, lit0,
- MINUS_EXPR, type);
+ MINUS_EXPR, atype);
lit0 = 0;
}
else
{
lit0 = associate_trees (loc, lit0, minus_lit0,
- MINUS_EXPR, type);
+ MINUS_EXPR, atype);
minus_lit0 = 0;
}
}
+
+ /* Don't introduce overflows through reassociation. */
+ if (!any_overflows
+ && ((lit0 && TREE_OVERFLOW (lit0))
+ || (minus_lit0 && TREE_OVERFLOW (minus_lit0))))
+ return NULL_TREE;
+
if (minus_lit0)
{
if (con0 == 0)
return
fold_convert_loc (loc, type,
associate_trees (loc, var0, minus_lit0,
- MINUS_EXPR, type));
+ MINUS_EXPR, atype));
else
{
con0 = associate_trees (loc, con0, minus_lit0,
- MINUS_EXPR, type);
+ MINUS_EXPR, atype);
return
fold_convert_loc (loc, type,
associate_trees (loc, var0, con0,
- PLUS_EXPR, type));
+ PLUS_EXPR, atype));
}
}
- con0 = associate_trees (loc, con0, lit0, code, type);
+ con0 = associate_trees (loc, con0, lit0, code, atype);
return
fold_convert_loc (loc, type, associate_trees (loc, var0, con0,
- code, type));
+ code, atype));
}
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f89fe3c5026..ce14c922f04 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2012-12-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/55137
+ * g++.dg/opt/pr55137.C: New test.
+ * gcc.c-torture/execute/pr55137.c: New test.
+
2012-12-06 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
* lib/target-supports.exp (check_effective_target_arm_v8_neon_ok):
diff --git a/gcc/testsuite/g++.dg/opt/pr55137.C b/gcc/testsuite/g++.dg/opt/pr55137.C
new file mode 100644
index 00000000000..73f8092af27
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr55137.C
@@ -0,0 +1,4 @@
+// PR c++/55137
+// { dg-do compile }
+
+enum E { F = -1 + (int) (sizeof (int) - 1) };
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr55137.c b/gcc/testsuite/gcc.c-torture/execute/pr55137.c
new file mode 100644
index 00000000000..80bc973f7f8
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr55137.c
@@ -0,0 +1,30 @@
+/* PR c++/55137 */
+
+extern void abort (void);
+
+int
+foo (unsigned int x)
+{
+ return ((int) (x + 1U) + 1) < (int) x;
+}
+
+int
+bar (unsigned int x)
+{
+ return (int) (x + 1U) + 1;
+}
+
+int
+baz (unsigned int x)
+{
+ return x + 1U;
+}
+
+int
+main ()
+{
+ if (foo (__INT_MAX__) != (bar (__INT_MAX__) < __INT_MAX__)
+ || foo (__INT_MAX__) != ((int) baz (__INT_MAX__) + 1 < __INT_MAX__))
+ abort ();
+ return 0;
+}
OpenPOWER on IntegriCloud