Commit 7b7e6ecd by Eric Botcazou Committed by Eric Botcazou

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
parent e49f4f07
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> 2007-12-13 Andrew Pinski <pinskia@gmail.com>
David Daney <ddaney@avtrex.com> David Daney <ddaney@avtrex.com>
...@@ -3728,7 +3728,15 @@ tree_to_gimple_tuple (tree *tp) ...@@ -3728,7 +3728,15 @@ tree_to_gimple_tuple (tree *tp)
/* Promote partial stores to COMPLEX variables to total stores. *EXPR_P is /* 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 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 static enum gimplify_status
gimplify_modify_expr_complex_part (tree *expr_p, tree *pre_p, bool want_value) gimplify_modify_expr_complex_part (tree *expr_p, tree *pre_p, bool want_value)
...@@ -6462,7 +6470,7 @@ gimplify_function_tree (tree fndecl) ...@@ -6462,7 +6470,7 @@ gimplify_function_tree (tree fndecl)
ret = DECL_RESULT (fndecl); ret = DECL_RESULT (fndecl);
if ((TREE_CODE (TREE_TYPE (ret)) == COMPLEX_TYPE 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)) && !needs_to_live_in_memory (ret))
DECL_GIMPLE_REG_P (ret) = 1; DECL_GIMPLE_REG_P (ret) = 1;
......
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> 2007-12-13 Olga Golovanevsky <olga@il.ibm.com>
* gcc.dg/struct/struct-reorg.exp: Replace * gcc.dg/struct/struct-reorg.exp: Replace
/* 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);
}
...@@ -5,6 +5,6 @@ typedef _Complex float C; ...@@ -5,6 +5,6 @@ typedef _Complex float C;
C foo() C foo()
{ {
C f; C f;
__imag__ f = 0; __imag__ f = 0; /* { dg-warning "is used" "unconditional" } */
return f; /* { dg-warning "" "uninit" { xfail *-*-* } } */ return f;
} }
...@@ -246,6 +246,17 @@ init_dont_simulate_again (void) ...@@ -246,6 +246,17 @@ init_dont_simulate_again (void)
saw_a_complex_op = true; saw_a_complex_op = true;
break; 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: default:
break; break;
} }
......
...@@ -884,6 +884,7 @@ extern void verify_ssa (bool); ...@@ -884,6 +884,7 @@ extern void verify_ssa (bool);
extern void delete_tree_ssa (void); extern void delete_tree_ssa (void);
extern void walk_use_def_chains (tree, walk_use_def_chains_fn, void *, bool); extern void walk_use_def_chains (tree, walk_use_def_chains_fn, void *, bool);
extern bool stmt_references_memory_p (tree); extern bool stmt_references_memory_p (tree);
extern bool ssa_undefined_value_p (tree);
/* In tree-into-ssa.c */ /* In tree-into-ssa.c */
void update_ssa (unsigned); void update_ssa (unsigned);
......
...@@ -285,7 +285,13 @@ is_gimple_id (tree t) ...@@ -285,7 +285,13 @@ is_gimple_id (tree t)
bool bool
is_gimple_reg_type (tree type) 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. */ /* Return true if T is a non-aggregate register variable. */
...@@ -328,8 +334,8 @@ is_gimple_reg (tree t) ...@@ -328,8 +334,8 @@ is_gimple_reg (tree t)
if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t)) if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t))
return false; return false;
/* Complex values must have been put into ssa form. That is, no /* Complex and vector values must have been put into SSA-like form.
assignments to the individual components. */ That is, no assignments to the individual components. */
if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
|| TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE) || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
return DECL_GIMPLE_REG_P (t); return DECL_GIMPLE_REG_P (t);
......
...@@ -383,7 +383,6 @@ static void bitmap_set_copy (bitmap_set_t, bitmap_set_t); ...@@ -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 bool bitmap_set_contains_value (bitmap_set_t, tree);
static void bitmap_insert_into_set (bitmap_set_t, tree); static void bitmap_insert_into_set (bitmap_set_t, tree);
static bitmap_set_t bitmap_set_new (void); 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 create_expression_by_pieces (basic_block, tree, tree);
static tree find_or_generate_expression (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, ...@@ -1328,7 +1327,7 @@ phi_translate_1 (tree expr, bitmap_set_t set1, bitmap_set_t set2,
if (is_gimple_min_invariant (def)) if (is_gimple_min_invariant (def))
return def; return def;
if (is_undefined_value (def)) if (TREE_CODE (def) == SSA_NAME && ssa_undefined_value_p (def))
return NULL; return NULL;
val = get_value_handle (def); val = get_value_handle (def);
...@@ -2889,18 +2888,6 @@ insert (void) ...@@ -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 /* Add OP to EXP_GEN (block), and possibly to the maximal set if it is
not defined by a phi node. not defined by a phi node.
PHI nodes can't go in the maximal sets because they are not in 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) ...@@ -2912,7 +2899,7 @@ add_to_exp_gen (basic_block block, tree op)
{ {
if (!in_fre) 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; return;
bitmap_value_insert_into_set (EXP_GEN (block), op); bitmap_value_insert_into_set (EXP_GEN (block), op);
if (TREE_CODE (op) != SSA_NAME if (TREE_CODE (op) != SSA_NAME
...@@ -3415,7 +3402,7 @@ make_values_for_stmt (tree stmt, basic_block block) ...@@ -3415,7 +3402,7 @@ make_values_for_stmt (tree stmt, basic_block block)
AVAIL_OUT (block)); AVAIL_OUT (block));
} }
/* None of the rest of these can be PRE'd. */ /* 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); add_to_exp_gen (block, rhs);
return true; return true;
} }
......
...@@ -1228,9 +1228,28 @@ walk_use_def_chains (tree var, walk_use_def_chains_fn fn, void *data, ...@@ -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. /* 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 uses are unconditionally uninitialized, and we can be certain that
such a use is a mistake. This pass is run before most optimizations, such a use is a mistake. This pass is run before most optimizations,
so that we catch as many as we can. so that we catch as many as we can.
...@@ -1250,22 +1269,11 @@ static void ...@@ -1250,22 +1269,11 @@ static void
warn_uninit (tree t, const char *gmsgid, void *data) warn_uninit (tree t, const char *gmsgid, void *data)
{ {
tree var = SSA_NAME_VAR (t); tree var = SSA_NAME_VAR (t);
tree def = SSA_NAME_DEF_STMT (t);
tree context = (tree) data; tree context = (tree) data;
location_t *locus; location_t *locus;
expanded_location xloc, floc; expanded_location xloc, floc;
/* Default uses (indicated by an empty definition statement), if (!ssa_undefined_value_p (t))
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))
return; return;
/* TREE_NO_WARNING either means we already warned, or the front end /* TREE_NO_WARNING either means we already warned, or the front end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment