From 7b7e6ecdb03f08b99c4738473482b4f749af1de0 Mon Sep 17 00:00:00 2001 From: Eric Botcazou <ebotcazou@libertysurf.fr> Date: Thu, 13 Dec 2007 22:49:09 +0100 Subject: [PATCH] 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 --- gcc/ChangeLog | 16 ++++++++++ gcc/gimplify.c | 12 +++++-- gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/gcc.dg/complex-5.c | 55 ++++++++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/uninit-13.c | 4 +-- gcc/tree-complex.c | 11 +++++++ gcc/tree-flow.h | 1 + gcc/tree-gimple.c | 12 +++++-- gcc/tree-ssa-pre.c | 19 ++--------- gcc/tree-ssa.c | 34 ++++++++++++-------- 10 files changed, 133 insertions(+), 36 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/complex-5.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 916f85160f49..f187e61d11fa 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 54d5c46ec3ec..a58738e34ef0 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 5a698766c827..59fd225289c3 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 000000000000..41c4ba0b9097 --- /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 168939ab8573..631e8de3ada6 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 693c8c99347b..a1964ee6813a 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 4424922613c6..6ab91a1793fe 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 abd35f7957bc..d1e47f65edab 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 c947e0f45d1a..69dbfb2b9a3b 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 eeb76806f8df..6c06df094b17 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 -- GitLab