re PR tree-optimization/39804 (internal compiler error: in propagate_necessity, at tree-ssa-dce.c:754)

2009-04-18  Richard Guenther  <rguenther@suse.de>

	PR middle-end/39804
	* tree-ssa-ccp.c (fold_stmt_1): New function factored from ...
	(fold_stmt): ... this and ...
	(fold_stmt_inplace): ... this.
	(fold_stmt_1): Fold references in calls and asms.
	* tree-cfg.c (remove_useless_stmts_cond): Use fold_stmt.

	* gcc.target/i386/pr39804.c: New testcase.

From-SVN: r146314
This commit is contained in:
Richard Guenther 2009-04-18 13:02:00 +00:00 committed by Richard Biener
parent 1eefab17a5
commit 2586ba4bda
5 changed files with 113 additions and 58 deletions

View File

@ -1,3 +1,12 @@
2009-04-18 Richard Guenther <rguenther@suse.de>
PR middle-end/39804
* tree-ssa-ccp.c (fold_stmt_1): New function factored from ...
(fold_stmt): ... this and ...
(fold_stmt_inplace): ... this.
(fold_stmt_1): Fold references in calls and asms.
* tree-cfg.c (remove_useless_stmts_cond): Use fold_stmt.
2009-04-18 Kazu Hirata <kazu@codesourcery.com>
* tree-vrp.c (ssa_name_nonzero_p): Remove.

View File

@ -1,3 +1,8 @@
2009-04-18 Richard Guenther <rguenther@suse.de>
PR middle-end/39804
* gcc.target/i386/pr39804.c: New testcase.
2009-04-18 Eric Botcazou <ebotcazou@adacore.com>
* gcc.target/i386/pr39496.c: Compile with -mtune=i686.

View File

@ -0,0 +1,31 @@
/* { dg-do compile } */
/* { dg-require-effective-target ilp32 } */
/* { dg-options "-O" } */
typedef unsigned char u8;
struct __large_struct { unsigned long buf[100]; };
static inline __attribute__((always_inline)) unsigned long
__copy_from_user_inatomic(void *to, const void *from, unsigned long n)
{
unsigned long ret = 0;
asm volatile("1: mov""b"" %2,%""b""1\n" "2:\n"
".section .fixup,\"ax\"\n"
"3: mov %3,%0\n"
" xor""b"" %""b""1,%""b""1\n"
" jmp 2b\n"
".previous\n"
" .section __ex_table,\"a\"\n"
" " ".balign 4" " " "\n"
" " ".long" " " "1b" "," "3b" "\n"
" .previous\n"
: "=r" (ret), "=q"(*(u8 *)to)
: "m" ((*(struct __large_struct *)(from))), "i" (1), "0" (ret));
return ret;
}
void romchecksum(const unsigned char *rom, unsigned char c)
{
unsigned char sum;
for (sum = 0;
!__copy_from_user_inatomic(&(c), ( typeof(c) *)(rom++), sizeof(c));)
sum += c;
}

View File

@ -1574,7 +1574,8 @@ remove_useless_stmts_cond (gimple_stmt_iterator *gsi, struct rus_data *data)
gimple stmt = gsi_stmt (*gsi);
/* The folded result must still be a conditional statement. */
fold_stmt_inplace (stmt);
fold_stmt (gsi);
gcc_assert (gsi_stmt (*gsi) == stmt);
data->may_branch = true;

View File

@ -2836,43 +2836,81 @@ fold_gimple_call (gimple_stmt_iterator *gsi)
return false;
}
/* Fold the statement pointed to by GSI. In some cases, this function may
replace the whole statement with a new one. Returns true iff folding
makes any changes.
The statement pointed to by GSI should be in valid gimple form but may
be in unfolded state as resulting from for example constant propagation
which can produce *&x = 0. */
/* Worker for both fold_stmt and fold_stmt_inplace. The INPLACE argument
distinguishes both cases. */
bool
fold_stmt (gimple_stmt_iterator *gsi)
static bool
fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace)
{
bool changed = false;
gimple stmt = gsi_stmt (*gsi);
unsigned i;
/* Fold the main computation performed by the statement. */
switch (gimple_code (stmt))
{
case GIMPLE_ASSIGN:
{
unsigned old_num_ops = gimple_num_ops (stmt);
tree new_rhs = fold_gimple_assign (gsi);
if (new_rhs != NULL_TREE)
if (new_rhs != NULL_TREE
&& (!inplace
|| get_gimple_rhs_num_ops (TREE_CODE (new_rhs)) < old_num_ops))
{
gimple_assign_set_rhs_from_tree (gsi, new_rhs);
changed = true;
}
break;
}
case GIMPLE_COND:
changed |= fold_gimple_cond (stmt);
break;
case GIMPLE_CALL:
/* Fold *& in call arguments. */
for (i = 0; i < gimple_call_num_args (stmt); ++i)
if (REFERENCE_CLASS_P (gimple_call_arg (stmt, i)))
{
tree tmp = maybe_fold_reference (gimple_call_arg (stmt, i), false);
if (tmp)
{
gimple_call_set_arg (stmt, i, tmp);
changed = true;
}
}
/* The entire statement may be replaced in this case. */
changed |= fold_gimple_call (gsi);
if (!inplace)
changed |= fold_gimple_call (gsi);
break;
default:
return changed;
case GIMPLE_ASM:
/* Fold *& in asm operands. */
for (i = 0; i < gimple_asm_noutputs (stmt); ++i)
{
tree link = gimple_asm_output_op (stmt, i);
tree op = TREE_VALUE (link);
if (REFERENCE_CLASS_P (op)
&& (op = maybe_fold_reference (op, true)) != NULL_TREE)
{
TREE_VALUE (link) = op;
changed = true;
}
}
for (i = 0; i < gimple_asm_ninputs (stmt); ++i)
{
tree link = gimple_asm_input_op (stmt, i);
tree op = TREE_VALUE (link);
if (REFERENCE_CLASS_P (op)
&& (op = maybe_fold_reference (op, false)) != NULL_TREE)
{
TREE_VALUE (link) = op;
changed = true;
}
}
break;
default:;
}
stmt = gsi_stmt (*gsi);
@ -2895,6 +2933,19 @@ fold_stmt (gimple_stmt_iterator *gsi)
return changed;
}
/* Fold the statement pointed to by GSI. In some cases, this function may
replace the whole statement with a new one. Returns true iff folding
makes any changes.
The statement pointed to by GSI should be in valid gimple form but may
be in unfolded state as resulting from for example constant propagation
which can produce *&x = 0. */
bool
fold_stmt (gimple_stmt_iterator *gsi)
{
return fold_stmt_1 (gsi, false);
}
/* Perform the minimal folding on statement STMT. Only operations like
*&x created by constant propagation are handled. The statement cannot
be replaced with a new one. Return true if the statement was
@ -2906,51 +2957,9 @@ fold_stmt (gimple_stmt_iterator *gsi)
bool
fold_stmt_inplace (gimple stmt)
{
gimple_stmt_iterator si;
bool changed = false;
/* Fold the main computation performed by the statement. */
switch (gimple_code (stmt))
{
case GIMPLE_ASSIGN:
{
unsigned old_num_ops;
tree new_rhs;
old_num_ops = gimple_num_ops (stmt);
si = gsi_for_stmt (stmt);
new_rhs = fold_gimple_assign (&si);
if (new_rhs != NULL_TREE
&& get_gimple_rhs_num_ops (TREE_CODE (new_rhs)) < old_num_ops)
{
gimple_assign_set_rhs_from_tree (&si, new_rhs);
changed = true;
}
gcc_assert (gsi_stmt (si) == stmt);
break;
}
case GIMPLE_COND:
changed |= fold_gimple_cond (stmt);
break;
default:
break;
}
/* Fold *& on the lhs. */
if (gimple_has_lhs (stmt))
{
tree lhs = gimple_get_lhs (stmt);
if (lhs && REFERENCE_CLASS_P (lhs))
{
tree new_lhs = maybe_fold_reference (lhs, true);
if (new_lhs)
{
gimple_set_lhs (stmt, new_lhs);
changed = true;
}
}
}
gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
bool changed = fold_stmt_1 (&gsi, true);
gcc_assert (gsi_stmt (gsi) == stmt);
return changed;
}