re PR middle-end/33088 (spurious exceptions with -ffloat-store)

PR middle-end/33088
	* gimplify.c (gimplify_modify_expr_complex_part): Add note to comment.
	* tree-complex.c (init_dont_simulate_again): Return true if there are
	uninitialized loads generated by gimplify_modify_expr_complex_part.
	* tree-gimple.c (is_gimple_reg_type): Return false for complex types
	if not optimizing.
	* tree-ssa.c (ssa_undefined_value_p): New predicate extracted from...
	(warn_uninit): ...here.  Use ssa_undefined_value_p.
	* tree-ssa-pre.c (is_undefined_value): Delete.
	(phi_translate_1): Use ssa_undefined_value_p.
	(add_to_exp_gen): Likewise.
	(make_values_for_stmt): Likewise.
	* tree-flow.h (ssa_undefined_value_p): Declare.

From-SVN: r130917
This commit is contained in:
Eric Botcazou 2007-12-13 22:49:09 +01:00 committed by Eric Botcazou
parent e49f4f07da
commit 7b7e6ecdb0
10 changed files with 133 additions and 36 deletions

View File

@ -1,3 +1,19 @@
2007-12-13 Eric Botcazou <ebotcazou@libertysurf.fr>
PR middle-end/33088
* gimplify.c (gimplify_modify_expr_complex_part): Add note to comment.
* tree-complex.c (init_dont_simulate_again): Return true if there are
uninitialized loads generated by gimplify_modify_expr_complex_part.
* tree-gimple.c (is_gimple_reg_type): Return false for complex types
if not optimizing.
* tree-ssa.c (ssa_undefined_value_p): New predicate extracted from...
(warn_uninit): ...here. Use ssa_undefined_value_p.
* tree-ssa-pre.c (is_undefined_value): Delete.
(phi_translate_1): Use ssa_undefined_value_p.
(add_to_exp_gen): Likewise.
(make_values_for_stmt): Likewise.
* tree-flow.h (ssa_undefined_value_p): Declare.
2007-12-13 Andrew Pinski <pinskia@gmail.com>
David Daney <ddaney@avtrex.com>

View File

@ -3728,7 +3728,15 @@ tree_to_gimple_tuple (tree *tp)
/* Promote partial stores to COMPLEX variables to total stores. *EXPR_P is
a MODIFY_EXPR with a lhs of a REAL/IMAGPART_EXPR of a variable with
DECL_GIMPLE_REG_P set. */
DECL_GIMPLE_REG_P set.
IMPORTANT NOTE: This promotion is performed by introducing a load of the
other, unmodified part of the complex object just before the total store.
As a consequence, if the object is still uninitialized, an undefined value
will be loaded into a register, which may result in a spurious exception
if the register is floating-point and the value happens to be a signaling
NaN for example. Then the fully-fledged complex operations lowering pass
followed by a DCE pass are necessary in order to fix things up. */
static enum gimplify_status
gimplify_modify_expr_complex_part (tree *expr_p, tree *pre_p, bool want_value)
@ -6462,7 +6470,7 @@ gimplify_function_tree (tree fndecl)
ret = DECL_RESULT (fndecl);
if ((TREE_CODE (TREE_TYPE (ret)) == COMPLEX_TYPE
|| TREE_CODE (TREE_TYPE (ret)) == VECTOR_TYPE)
|| TREE_CODE (TREE_TYPE (ret)) == VECTOR_TYPE)
&& !needs_to_live_in_memory (ret))
DECL_GIMPLE_REG_P (ret) = 1;

View File

@ -1,3 +1,8 @@
2007-12-13 Eric Botcazou <ebotcazou@libertysurf.fr>
* gcc.dg/uninit-13.c: UnXFAIL.
* gcc.dg/complex-5.c: New testcase.
2007-12-13 Olga Golovanevsky <olga@il.ibm.com>
* gcc.dg/struct/struct-reorg.exp: Replace

View File

@ -0,0 +1,55 @@
/* PR middle-end/33088 */
/* Origin: Joseph S. Myers <jsm28@gcc.gnu.org> */
/* { dg-do run { target i?86-*-linux* x86_64-*-linux* } } */
/* { dg-options "-std=c99 -O -ffloat-store -lm" } */
#include <fenv.h>
#include <stdlib.h>
volatile int x[1024];
void __attribute__((noinline))
fill_stack (void)
{
volatile int y[1024];
int i;
for (i = 0; i < 1024; i++)
y[i] = 0x7ff00000;
for (i = 0; i < 1024; i++)
x[i] = y[i];
}
volatile _Complex double vc;
void __attribute__((noinline))
use_complex (_Complex double c)
{
vc = c;
}
double t0, t1, t2, t3;
#define USE_COMPLEX(X, R, C) \
do { __real__ X = R; __imag__ X = C; use_complex (X); } while (0)
void __attribute__((noinline))
use_stack (void)
{
_Complex double a, b, c, d;
USE_COMPLEX (a, t0, t1);
USE_COMPLEX (b, t1, t2);
USE_COMPLEX (c, t2, t3);
USE_COMPLEX (d, t3, t0);
}
int
main (void)
{
fill_stack ();
feclearexcept (FE_INVALID);
use_stack ();
if (fetestexcept (FE_INVALID))
abort ();
exit (0);
}

View File

@ -5,6 +5,6 @@ typedef _Complex float C;
C foo()
{
C f;
__imag__ f = 0;
return f; /* { dg-warning "" "uninit" { xfail *-*-* } } */
__imag__ f = 0; /* { dg-warning "is used" "unconditional" } */
return f;
}

View File

@ -246,6 +246,17 @@ init_dont_simulate_again (void)
saw_a_complex_op = true;
break;
case REALPART_EXPR:
case IMAGPART_EXPR:
/* The total store transformation performed during
gimplification creates such uninitialized loads
and we need to lower the statement to be able
to fix things up. */
if (TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME
&& ssa_undefined_value_p (TREE_OPERAND (rhs, 0)))
saw_a_complex_op = true;
break;
default:
break;
}

View File

@ -884,6 +884,7 @@ extern void verify_ssa (bool);
extern void delete_tree_ssa (void);
extern void walk_use_def_chains (tree, walk_use_def_chains_fn, void *, bool);
extern bool stmt_references_memory_p (tree);
extern bool ssa_undefined_value_p (tree);
/* In tree-into-ssa.c */
void update_ssa (unsigned);

View File

@ -285,7 +285,13 @@ is_gimple_id (tree t)
bool
is_gimple_reg_type (tree type)
{
return !AGGREGATE_TYPE_P (type);
/* In addition to aggregate types, we also exclude complex types if not
optimizing because they can be subject to partial stores in GNU C by
means of the __real__ and __imag__ operators and we cannot promote
them to total stores (see gimplify_modify_expr_complex_part). */
return !(AGGREGATE_TYPE_P (type)
|| (TREE_CODE (type) == COMPLEX_TYPE && !optimize));
}
/* Return true if T is a non-aggregate register variable. */
@ -328,8 +334,8 @@ is_gimple_reg (tree t)
if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
return false;
/* Complex values must have been put into ssa form. That is, no
assignments to the individual components. */
/* Complex and vector values must have been put into SSA-like form.
That is, no assignments to the individual components. */
if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
|| TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
return DECL_GIMPLE_REG_P (t);

View File

@ -383,7 +383,6 @@ static void bitmap_set_copy (bitmap_set_t, bitmap_set_t);
static bool bitmap_set_contains_value (bitmap_set_t, tree);
static void bitmap_insert_into_set (bitmap_set_t, tree);
static bitmap_set_t bitmap_set_new (void);
static bool is_undefined_value (tree);
static tree create_expression_by_pieces (basic_block, tree, tree);
static tree find_or_generate_expression (basic_block, tree, tree);
@ -1328,7 +1327,7 @@ phi_translate_1 (tree expr, bitmap_set_t set1, bitmap_set_t set2,
if (is_gimple_min_invariant (def))
return def;
if (is_undefined_value (def))
if (TREE_CODE (def) == SSA_NAME && ssa_undefined_value_p (def))
return NULL;
val = get_value_handle (def);
@ -2889,18 +2888,6 @@ insert (void)
}
/* Return true if VAR is an SSA variable with no defining statement in
this procedure, *AND* isn't a live-on-entry parameter. */
static bool
is_undefined_value (tree expr)
{
return (TREE_CODE (expr) == SSA_NAME
&& IS_EMPTY_STMT (SSA_NAME_DEF_STMT (expr))
/* PARM_DECLs and hard registers are always defined. */
&& TREE_CODE (SSA_NAME_VAR (expr)) != PARM_DECL);
}
/* Add OP to EXP_GEN (block), and possibly to the maximal set if it is
not defined by a phi node.
PHI nodes can't go in the maximal sets because they are not in
@ -2912,7 +2899,7 @@ add_to_exp_gen (basic_block block, tree op)
{
if (!in_fre)
{
if (TREE_CODE (op) == SSA_NAME && is_undefined_value (op))
if (TREE_CODE (op) == SSA_NAME && ssa_undefined_value_p (op))
return;
bitmap_value_insert_into_set (EXP_GEN (block), op);
if (TREE_CODE (op) != SSA_NAME
@ -3415,7 +3402,7 @@ make_values_for_stmt (tree stmt, basic_block block)
AVAIL_OUT (block));
}
/* None of the rest of these can be PRE'd. */
if (TREE_CODE (rhs) == SSA_NAME && !is_undefined_value (rhs))
if (TREE_CODE (rhs) == SSA_NAME && !ssa_undefined_value_p (rhs))
add_to_exp_gen (block, rhs);
return true;
}

View File

@ -1228,9 +1228,28 @@ walk_use_def_chains (tree var, walk_use_def_chains_fn fn, void *data,
}
/* Return true if T, an SSA_NAME, has an undefined value. */
bool
ssa_undefined_value_p (tree t)
{
tree var = SSA_NAME_VAR (t);
/* Parameters get their initial value from the function entry. */
if (TREE_CODE (var) == PARM_DECL)
return false;
/* Hard register variables get their initial value from the ether. */
if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var))
return false;
/* The value is undefined iff its definition statement is empty. */
return IS_EMPTY_STMT (SSA_NAME_DEF_STMT (t));
}
/* Emit warnings for uninitialized variables. This is done in two passes.
The first pass notices real uses of SSA names with default definitions.
The first pass notices real uses of SSA names with undefined values.
Such uses are unconditionally uninitialized, and we can be certain that
such a use is a mistake. This pass is run before most optimizations,
so that we catch as many as we can.
@ -1250,22 +1269,11 @@ static void
warn_uninit (tree t, const char *gmsgid, void *data)
{
tree var = SSA_NAME_VAR (t);
tree def = SSA_NAME_DEF_STMT (t);
tree context = (tree) data;
location_t *locus;
expanded_location xloc, floc;
/* Default uses (indicated by an empty definition statement),
are uninitialized. */
if (!IS_EMPTY_STMT (def))
return;
/* Except for PARMs of course, which are always initialized. */
if (TREE_CODE (var) == PARM_DECL)
return;
/* Hard register variables get their initial value from the ether. */
if (TREE_CODE (var) == VAR_DECL && DECL_HARD_REGISTER (var))
if (!ssa_undefined_value_p (t))
return;
/* TREE_NO_WARNING either means we already warned, or the front end