This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR middle-end/33088
- From: Eric Botcazou <ebotcazou at libertysurf dot fr>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 12 Dec 2007 23:21:48 +0100
- Subject: [PATCH] Fix PR middle-end/33088
As diagnosed by Joseph, this is a problem introduced by RTH's patch
http://gcc.gnu.org/ml/gcc-patches/2005-06/msg00860.html>
which promotes partial stores to the real or imaginary part of a complex
variable to total stores.
This is achieved by generating a load of the other, unmodified part of the
complex variables just before the total store, thus introducing a load of
an undefined value if the variable is uninitialized.
This works, i.e. the uninitialized loads are cleaned up, if the fully-fledged
complex operations lowering pass is run, followed by a DCE pass. The problem
here is that the lowering pass is not run, even at -O or above, because the
associated predicate returns false for the function at hand.
The proposed fix is two-pronged: (1) not promoting the partial stores at -O0,
(2) teaching the predicate to detect the uninitialized loads at -O1 or above.
(1) is achieved by just tweaking is_gimple_reg_type, i.e. DECL_GIMPLE_REG_P is
still being set on the individual variables. This seems to work, but...
Tested on i586-suse-linux, OK for mainline?
2007-12-12 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-12 Eric Botcazou <ebotcazou@libertysurf.fr>
* gcc.dg/uninit-13.c: UnXFAIL.
* gcc.dg/complex-5.c: New testcase.
--
Eric Botcazou
Index: gimplify.c
===================================================================
--- gimplify.c (revision 130775)
+++ gimplify.c (working copy)
@@ -3715,7 +3715,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 clean up the mess. */
static enum gimplify_status
gimplify_modify_expr_complex_part (tree *expr_p, tree *pre_p, bool want_value)
@@ -6449,7 +6457,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;
Index: tree-complex.c
===================================================================
--- tree-complex.c (revision 130775)
+++ tree-complex.c (working copy)
@@ -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 clean up the mess. */
+ 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;
}
Index: tree-flow.h
===================================================================
--- tree-flow.h (revision 130775)
+++ tree-flow.h (working copy)
@@ -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);
Index: tree-gimple.c
===================================================================
--- tree-gimple.c (revision 130775)
+++ tree-gimple.c (working copy)
@@ -280,12 +280,18 @@ is_gimple_id (tree t)
|| TREE_CODE (t) == STRING_CST);
}
-/* Return true if TYPE is a suitable type for a scalar register variable. */
+/* Return true if TYPE is a suitable type for a scalar register variable.
+ 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). */
bool
is_gimple_reg_type (tree type)
{
- return !AGGREGATE_TYPE_P (type);
+ 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);
Index: tree-ssa.c
===================================================================
--- tree-ssa.c (revision 130775)
+++ tree-ssa.c (working copy)
@@ -1228,9 +1228,28 @@ walk_use_def_chains (tree var, walk_use_
}
+/* 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
Index: tree-ssa-pre.c
===================================================================
--- tree-ssa-pre.c (revision 130775)
+++ tree-ssa-pre.c (working copy)
@@ -383,7 +383,6 @@ static void bitmap_set_copy (bitmap_set_
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
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
{
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_b
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;
}
Index: testsuite/gcc.dg/uninit-13.c
===================================================================
--- testsuite/gcc.dg/uninit-13.c (revision 130775)
+++ testsuite/gcc.dg/uninit-13.c (working copy)
@@ -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;
}
/* PR middle-end/33088 */
/* Origin: Joseph S. Myers <jsm28@gcc.gnu.org> */
/* { dg-do run } */
/* [ dg-options "-O -ffloat-store -lm" { target i?86-*-linux* x86_64-*-linux* } } */
#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);
}