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]

fix middle-end/19515


The solution is about what I mentioned in the PR.  At each step, see
if we've got an incompletely initialized union, and if so, force the
entire object to be zeroed.  Not spectacularly efficient, but continues
to avoid the quadratic match-up-the-initializer-with-the-structure
problem, which we should still solve at some point.  But not now.


r~


        * expr.c (categorize_ctor_elements): New argument p_must_clear.
        (categorize_ctor_elements_1): Likewise.  Detect a union that isn't
        fully initialized.
        (mostly_zeros_p): Update for new categorize_ctor_elements argument.
        * gimplify.c (gimplify_init_constructor): Likewise.  Only shove
        objects into static storage if they have more than one non-zero value.
        * tree.h (categorize_ctor_elements): Update decl.

Index: gcc/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.772
diff -u -p -d -r1.772 expr.c
--- gcc/expr.c	23 Jan 2005 15:05:28 -0000	1.772
+++ gcc/expr.c	26 Jan 2005 15:17:11 -0000
@@ -4272,12 +4272,15 @@ store_expr (tree exp, rtx target, int ca
    * how many scalar fields are set to non-constant values,
      and place it in  *P_NC_ELTS; and
    * how many scalar fields in total are in CTOR,
-     and place it in *P_ELT_COUNT.  */
+     and place it in *P_ELT_COUNT.
+   * if a type is a union, and the initializer from the constructor
+     is not the largest element in the union, then set *p_must_clear.  */
 
 static void
 categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
 			    HOST_WIDE_INT *p_nc_elts,
-			    HOST_WIDE_INT *p_elt_count)
+			    HOST_WIDE_INT *p_elt_count,
+			    bool *p_must_clear)
 {
   HOST_WIDE_INT nz_elts, nc_elts, elt_count;
   tree list;
@@ -4307,11 +4310,11 @@ categorize_ctor_elements_1 (tree ctor, H
 	{
 	case CONSTRUCTOR:
 	  {
-	    HOST_WIDE_INT nz = 0, nc = 0, count = 0;
-	    categorize_ctor_elements_1 (value, &nz, &nc, &count);
+	    HOST_WIDE_INT nz = 0, nc = 0, ic = 0;
+	    categorize_ctor_elements_1 (value, &nz, &nc, &ic, p_must_clear);
 	    nz_elts += mult * nz;
 	    nc_elts += mult * nc;
-	    elt_count += mult * count;
+	    elt_count += mult * ic;
 	  }
 	  break;
 
@@ -4356,6 +4359,36 @@ categorize_ctor_elements_1 (tree ctor, H
 	}
     }
 
+  if (!*p_must_clear
+      && (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE
+	  || TREE_CODE (TREE_TYPE (ctor)) == QUAL_UNION_TYPE))
+    {
+      tree init_sub_type;
+
+      /* We don't expect more than one element of the union to be
+	 initialized.  Not sure what we should do otherwise... */
+      list = CONSTRUCTOR_ELTS (ctor);
+      gcc_assert (TREE_CHAIN (list) == NULL);
+
+      init_sub_type = TREE_TYPE (TREE_VALUE (list));
+
+      /* ??? We could look at each element of the union, and find the
+	 largest element.  Which would avoid comparing the size of the
+	 initialized element against any tail padding in the union.
+	 Doesn't seem worth the effort...  */
+      if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (ctor)), 
+			    TYPE_SIZE (init_sub_type)) == 1)
+	{
+	  /* And now we have to find out if the element itself is fully
+	     constructed.  E.g. for union { struct { int a, b; } s; } u
+	     = { .s = { .a = 1 } }.  */
+	  if (elt_count != count_type_elements (init_sub_type))
+	    *p_must_clear = true;
+	}
+      else
+	*p_must_clear = true;
+    }
+
   *p_nz_elts += nz_elts;
   *p_nc_elts += nc_elts;
   *p_elt_count += elt_count;
@@ -4364,12 +4397,15 @@ categorize_ctor_elements_1 (tree ctor, H
 void
 categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts,
 			  HOST_WIDE_INT *p_nc_elts,
-			  HOST_WIDE_INT *p_elt_count)
+			  HOST_WIDE_INT *p_elt_count,
+			  bool *p_must_clear)
 {
   *p_nz_elts = 0;
   *p_nc_elts = 0;
   *p_elt_count = 0;
-  categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts, p_elt_count);
+  *p_must_clear = false;
+  categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts, p_elt_count,
+			      p_must_clear);
 }
 
 /* Count the number of scalars in TYPE.  Return -1 on overflow or
@@ -4459,8 +4495,12 @@ mostly_zeros_p (tree exp)
 
     {
       HOST_WIDE_INT nz_elts, nc_elts, count, elts;
+      bool must_clear;
+
+      categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count, &must_clear);
+      if (must_clear)
+	return 1;
 
-      categorize_ctor_elements (exp, &nz_elts, &nc_elts, &count);
       elts = count_type_elements (TREE_TYPE (exp));
 
       return nz_elts < elts / 4;
Index: gcc/gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.106
diff -u -p -d -r2.106 gimplify.c
--- gcc/gimplify.c	23 Jan 2005 15:05:30 -0000	2.106
+++ gcc/gimplify.c	26 Jan 2005 15:17:12 -0000
@@ -2599,11 +2599,12 @@ gimplify_init_constructor (tree *expr_p,
 
 	categorize_ctor_elements (ctor, &num_nonzero_elements,
 				  &num_nonconstant_elements,
-				  &num_ctor_elements);
+				  &num_ctor_elements, &cleared);
 
 	/* If a const aggregate variable is being initialized, then it
 	   should never be a lose to promote the variable to be static.  */
 	if (num_nonconstant_elements == 0
+	    && num_nonzero_elements > 1
 	    && TREE_READONLY (object)
 	    && TREE_CODE (object) == VAR_DECL)
 	  {
@@ -2685,7 +2686,6 @@ gimplify_init_constructor (tree *expr_p,
 	num_type_elements = count_type_elements (TREE_TYPE (ctor));
 
 	/* If there are "lots" of zeros, then block clear the object first.  */
-	cleared = false;
 	if (num_type_elements - num_nonzero_elements > CLEAR_RATIO
 	    && num_nonzero_elements < num_type_elements/4)
 	  cleared = true;
Index: gcc/tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.680
diff -u -p -d -r1.680 tree.h
--- gcc/tree.h	26 Jan 2005 15:08:50 -0000	1.680
+++ gcc/tree.h	26 Jan 2005 15:17:13 -0000
@@ -3235,8 +3235,8 @@ extern int fields_length (tree);
 
 extern bool initializer_zerop (tree);
 
-extern void categorize_ctor_elements (tree, HOST_WIDE_INT *,
-				      HOST_WIDE_INT *, HOST_WIDE_INT *);
+extern void categorize_ctor_elements (tree, HOST_WIDE_INT *, HOST_WIDE_INT *,
+				      HOST_WIDE_INT *, bool *);
 extern HOST_WIDE_INT count_type_elements (tree);
 
 /* add_var_to_bind_expr (bind_expr, var) binds var to bind_expr.  */
Index: gcc/testsuite/gcc.c-torture/execute/pr19515.c
===================================================================
RCS file: gcc/testsuite/gcc.c-torture/execute/pr19515.c
diff -N gcc/testsuite/gcc.c-torture/execute/pr19515.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/gcc.c-torture/execute/pr19515.c	26 Jan 2005 15:17:13 -0000
@@ -0,0 +1,17 @@
+/* PR 19515 */
+
+typedef union {
+      char a2[8];
+}aun;
+
+void abort (void);
+
+int main(void)
+{
+  aun a = {{0}};
+
+  if (a.a2[2] != 0)
+    abort ();
+  return 0;
+}
+


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