re PR c++/55137 (Unexpected static structure initialization)

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.

From-SVN: r194250
This commit is contained in:
Jakub Jelinek 2012-12-06 15:37:09 +01:00 committed by Jakub Jelinek
parent d8169a0d2a
commit 5442fe4818
5 changed files with 91 additions and 25 deletions

View file

@ -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

View file

@ -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,10 +10364,24 @@ 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)
{
@ -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));
}
}

View file

@ -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):

View file

@ -0,0 +1,4 @@
// PR c++/55137
// { dg-do compile }
enum E { F = -1 + (int) (sizeof (int) - 1) };

View file

@ -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;
}