diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 916f85160f4960670d3bbf433fb35826f98f6cce..f187e61d11fa8293cc805a1e27a6c898ed2ad369 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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> diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 54d5c46ec3ec1fea5ab5f5c2dd0c23de0d4f3fe6..a58738e34ef08f1a9849c63baf2359b574419fcf 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -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; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5a698766c827cce7fc5016f91fb2b3989a12f996..59fd225289c3a5569d6781f52d2c1e0eb23a51c7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 diff --git a/gcc/testsuite/gcc.dg/complex-5.c b/gcc/testsuite/gcc.dg/complex-5.c new file mode 100644 index 0000000000000000000000000000000000000000..41c4ba0b909771d96ca312e21f69eed0dc343fd4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/complex-5.c @@ -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); +} diff --git a/gcc/testsuite/gcc.dg/uninit-13.c b/gcc/testsuite/gcc.dg/uninit-13.c index 168939ab8573889b3c40eeb2c6c63080840e286a..631e8de3ada6d6f49db5df96e3bfe976c3bcdc96 100644 --- a/gcc/testsuite/gcc.dg/uninit-13.c +++ b/gcc/testsuite/gcc.dg/uninit-13.c @@ -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; } diff --git a/gcc/tree-complex.c b/gcc/tree-complex.c index 693c8c99347b388591b878828949e6c334554ca7..a1964ee6813a90544e120b6ea63479b66ac7ce5a 100644 --- a/gcc/tree-complex.c +++ b/gcc/tree-complex.c @@ -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; } diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 4424922613c667533827ef1dd324becccaf81f25..6ab91a1793fe36cfaeaac961c855ee122149aa62 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -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); diff --git a/gcc/tree-gimple.c b/gcc/tree-gimple.c index abd35f7957bc62cddd6cb4462537cdd84e51ee85..d1e47f65edab38c19c56f9799fc6d19524954bdd 100644 --- a/gcc/tree-gimple.c +++ b/gcc/tree-gimple.c @@ -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); diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index c947e0f45d1ad31320d32442e96e413e0a4f14cd..69dbfb2b9a3beca9bd35bb36bb13295d68e5fc1e 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -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; } diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index eeb76806f8df0ce61d356be30743a95ca924d32a..6c06df094b175c70d61e33a26f525e526ceb5958 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -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