This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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);
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]