aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@libertysurf.fr>2007-12-13 22:49:09 +0100
committerEric Botcazou <ebotcazou@gcc.gnu.org>2007-12-13 21:49:09 +0000
commit7b7e6ecdb03f08b99c4738473482b4f749af1de0 (patch)
tree1a2db453ef003669b76c5fe7b06ef0c746c75775
parente49f4f07da9c797eb0efadb36161b36cdc7fef47 (diff)
downloadgcc-7b7e6ecdb03f08b99c4738473482b4f749af1de0.zip
gcc-7b7e6ecdb03f08b99c4738473482b4f749af1de0.tar.gz
gcc-7b7e6ecdb03f08b99c4738473482b4f749af1de0.tar.bz2
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
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/gimplify.c12
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/complex-5.c55
-rw-r--r--gcc/testsuite/gcc.dg/uninit-13.c4
-rw-r--r--gcc/tree-complex.c11
-rw-r--r--gcc/tree-flow.h1
-rw-r--r--gcc/tree-gimple.c12
-rw-r--r--gcc/tree-ssa-pre.c19
-rw-r--r--gcc/tree-ssa.c34
10 files changed, 133 insertions, 36 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 916f851..f187e61 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 54d5c46..a58738e 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 5a69876..59fd225 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 0000000..41c4ba0
--- /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 168939a..631e8de 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 693c8c9..a1964ee 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 4424922..6ab91a1 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 abd35f7..d1e47f6 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 c947e0f..69dbfb2 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 eeb7680..6c06df0 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