PR 48183 is caused by the fact that we don't really support integers
(or least integer constants) wider than 2*HOST_BITS_PER_WIDE_INT:

   http://gcc.gnu.org/ml/gcc-patches/2011-03/msg01220.html

However, such constants shouldn't be needed in normal use.
They came from an unnecessary zero-initialisation of a union such as:

   union { a f1; b f2; } u = { init_f1 };

where f1 and f2 are the full width of the union.  The zero-initialisation
gets optimised away for "real" insns, but persists in debug insns:

   http://gcc.gnu.org/ml/gcc-patches/2011-03/msg01585.html

This patch takes up Richard's idea here:

   http://gcc.gnu.org/ml/gcc-patches/2011-03/msg01987.html

categorize_ctor_elements currently tries to work out how many scalars a
constructor initialises (IE) and how many of those scalars are zero (ZE).
Callers can then call count_type_elements to find out how many scalars (TE)
ought to be initialised if the constructor is "complete" (i.e. if it
explicitly initialises every meaningful byte, rather than relying on
default zero-initialisation).  The constructor is complete if TE == ZE,
except as noted in [A] below.

However, count_type_elements can't return the required TE for unions,
because it would need to know which of the union's fields was initialised
by the constructor (if any).  This choice of field is reflected in IE and
ZE, so would need to be reflected in TE as well.

count_type_elements therefore punts on unions.  However, the caller
can't easily tell whether it punts because of that, because of overflow,
of because of variable-sized types.

[A] One particular case of interest is when a union constructor initialises
a field that is shorter than the union.  In this case, the rest of the
union must be zeroed in order to ensure that the other fields have
predictable values.  categorize_ctor_elements has a special out-parameter
to reccord this situation.

This leads to quite a complicated interface.  The patch tries to
simplify it by making categorize_ctor_elements keep track of whether
a constructor is complete.  This also has the minor advantage of
avoiding double recursion: first through the constructor,
then through its type tree.

After this change, ZE and IE are only needed when deciding how best to
implement "complete" initialisers (such as whether to do a bulk zero
initialisation anyway, and just write the nonzero elements individually).
For cases where a "leaf" constructor element is itself an aggregate with
a union, we can therefore estimate the number of scalars in the union,
and hopefully make the heuristic a bit more accurate than the current 1:

            HOST_WIDE_INT tc = count_type_elements (TREE_TYPE (value), true);
            if (tc < 1)
              tc = 1;

cp/typeck2.c also wants to check whether the variable parts of a
constructor are complete.  The patch uses the approach to completeness
there.  This should make it a bit more general than the current code,
which only deals with non-nested constructors.

Tested on x86_64-linux-gnu (all languages, including Ada), and on
arm-linux-gnueabi.  OK to install?

Richard


gcc/
        * tree.h (categorize_ctor_elements): Remove comment.  Fix long line.
        (count_type_elements): Delete.
        (complete_ctor_at_level_p): Declare.
        * expr.c (flexible_array_member_p): New function, split out from...
        (count_type_elements): ...here.  Make static.  Replace allow_flexarr
        parameter with for_ctor_p.  When for_ctor_p is true, return the
        number of elements that should appear in the top-level constructor,
        otherwise return an estimate of the number of scalars.
        (categorize_ctor_elements): Replace p_must_clear with p_complete.
        (categorize_ctor_elements_1): Likewise.  Use complete_ctor_at_level_p.
        (complete_ctor_at_level_p): New function, borrowing union logic
        from old categorize_ctor_elements_1.
        (mostly_zeros_p): Return true if the constructor is not complete.
        (all_zeros_p): Update call to categorize_ctor_elements.
        * gimplify.c (gimplify_init_constructor): Update call to
        categorize_ctor_elements.  Don't call count_type_elements.
        Unconditionally prevent clearing for variable-sized types,
        otherwise rely on categorize_ctor_elements to detect
        incomplete initializers.

gcc/cp/
        * typeck2.c (split_nonconstant_init_1): Pass the initializer directly,
        rather than a pointer to it.  Return true if the whole of the value
        was initialized by the generated statements.  Use
        complete_ctor_at_level_p instead of count_type_elements.

gcc/testsuite/
2011-07-12  Chung-Lin Tang  <clt...@codesourcery.com>

        * gcc.target/arm/pr48183.c: New test.

Index: gcc/tree.h
===================================================================
--- gcc/tree.h  2011-07-12 15:30:05.000000000 +0100
+++ gcc/tree.h  2011-07-12 15:32:34.000000000 +0100
@@ -4804,21 +4804,10 @@ extern bool initializer_zerop (const_tre
 
 extern VEC(tree,gc) *ctor_to_vec (tree);
 
-/* Examine CTOR to discover:
-   * how many scalar fields are set to nonzero values,
-     and place it in *P_NZ_ELTS;
-   * how many scalar fields in total are in CTOR,
-     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.
+extern bool categorize_ctor_elements (const_tree, HOST_WIDE_INT *,
+                                     HOST_WIDE_INT *, bool *);
 
-   Return whether or not CTOR is a valid static constant initializer, the same
-   as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0".  */
-
-extern bool categorize_ctor_elements (const_tree, HOST_WIDE_INT *, 
HOST_WIDE_INT *,
-                                     bool *);
-
-extern HOST_WIDE_INT count_type_elements (const_tree, bool);
+extern bool complete_ctor_at_level_p (const_tree, HOST_WIDE_INT, const_tree);
 
 /* integer_zerop (tree x) is nonzero if X is an integer constant of value 0.  
*/
 
Index: gcc/expr.c
===================================================================
--- gcc/expr.c  2011-07-12 15:30:05.000000000 +0100
+++ gcc/expr.c  2011-07-12 15:32:34.000000000 +0100
@@ -4846,16 +4846,136 @@ store_expr (tree exp, rtx target, int ca
   return NULL_RTX;
 }
 
+/* Return true if field F of structure TYPE is a flexible array.  */
+
+static bool
+flexible_array_member_p (const_tree f, const_tree type)
+{
+  const_tree tf;
+
+  tf = TREE_TYPE (f);
+  return (DECL_CHAIN (f) == NULL
+         && TREE_CODE (tf) == ARRAY_TYPE
+         && TYPE_DOMAIN (tf)
+         && TYPE_MIN_VALUE (TYPE_DOMAIN (tf))
+         && integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (tf)))
+         && !TYPE_MAX_VALUE (TYPE_DOMAIN (tf))
+         && int_size_in_bytes (type) >= 0);
+}
+
+/* If FOR_CTOR_P, return the number of top-level elements that a constructor
+   must have in order for it to completely initialize a value of type TYPE.
+   Return -1 if the number isn't known.
+
+   If !FOR_CTOR_P, return an estimate of the number of scalars in TYPE.  */
+
+static HOST_WIDE_INT
+count_type_elements (const_tree type, bool for_ctor_p)
+{
+  switch (TREE_CODE (type))
+    {
+    case ARRAY_TYPE:
+      {
+       tree nelts;
+
+       nelts = array_type_nelts (type);
+       if (nelts && host_integerp (nelts, 1))
+         {
+           unsigned HOST_WIDE_INT n;
+
+           n = tree_low_cst (nelts, 1) + 1;
+           if (n == 0 || for_ctor_p)
+             return n;
+           else
+             return n * count_type_elements (TREE_TYPE (type), false);
+         }
+       return for_ctor_p ? -1 : 1;
+      }
+
+    case RECORD_TYPE:
+      {
+       unsigned HOST_WIDE_INT n;
+       tree f;
+
+       n = 0;
+       for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f))
+         if (TREE_CODE (f) == FIELD_DECL)
+           {
+             if (!for_ctor_p)
+               n += count_type_elements (TREE_TYPE (f), false);
+             else if (!flexible_array_member_p (f, type))
+               /* Don't count flexible arrays, which are not supposed
+                  to be initialized.  */
+               n += 1;
+           }
+
+       return n;
+      }
+
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      {
+       tree f;
+       HOST_WIDE_INT n, m;
+
+       gcc_assert (!for_ctor_p);
+       /* Estimate the number of scalars in each field and pick the
+          maximum.  Other estimates would do instead; the idea is simply
+          to make sure that the estimate is not sensitive to the ordering
+          of the fields.  */
+       n = 1;
+       for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f))
+         if (TREE_CODE (f) == FIELD_DECL)
+           {
+             m = count_type_elements (TREE_TYPE (f), false);
+             /* If the field doesn't span the whole union, add an extra
+                scalar for the rest.  */
+             if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (f)),
+                                   TYPE_SIZE (type)) != 1)
+               m++;
+             if (n < m)
+               n = m;
+           }
+       return n;
+      }
+
+    case COMPLEX_TYPE:
+      return 2;
+
+    case VECTOR_TYPE:
+      return TYPE_VECTOR_SUBPARTS (type);
+
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+    case FIXED_POINT_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+    case POINTER_TYPE:
+    case OFFSET_TYPE:
+    case REFERENCE_TYPE:
+      return 1;
+
+    case ERROR_MARK:
+      return 0;
+
+    case VOID_TYPE:
+    case METHOD_TYPE:
+    case FUNCTION_TYPE:
+    case LANG_TYPE:
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Helper for categorize_ctor_elements.  Identical interface.  */
 
 static bool
 categorize_ctor_elements_1 (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
-                           HOST_WIDE_INT *p_elt_count,
-                           bool *p_must_clear)
+                           HOST_WIDE_INT *p_init_elts, bool *p_complete)
 {
   unsigned HOST_WIDE_INT idx;
-  HOST_WIDE_INT nz_elts, elt_count;
-  tree value, purpose;
+  HOST_WIDE_INT nz_elts, init_elts, num_fields;
+  tree value, purpose, elt_type;
 
   /* Whether CTOR is a valid constant initializer, in accordance with what
      initializer_constant_valid_p does.  If inferred from the constructor
@@ -4864,7 +4984,9 @@ categorize_ctor_elements_1 (const_tree c
   bool const_p = const_from_elts_p ? true : TREE_STATIC (ctor);
 
   nz_elts = 0;
-  elt_count = 0;
+  init_elts = 0;
+  num_fields = 0;
+  elt_type = NULL_TREE;
 
   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value)
     {
@@ -4879,6 +5001,8 @@ categorize_ctor_elements_1 (const_tree c
            mult = (tree_low_cst (hi_index, 1)
                    - tree_low_cst (lo_index, 1) + 1);
        }
+      num_fields += mult;
+      elt_type = TREE_TYPE (value);
 
       switch (TREE_CODE (value))
        {
@@ -4886,11 +5010,11 @@ categorize_ctor_elements_1 (const_tree c
          {
            HOST_WIDE_INT nz = 0, ic = 0;
 
-           bool const_elt_p
-             = categorize_ctor_elements_1 (value, &nz, &ic, p_must_clear);
+           bool const_elt_p = categorize_ctor_elements_1 (value, &nz, &ic,
+                                                          p_complete);
 
            nz_elts += mult * nz;
-           elt_count += mult * ic;
+           init_elts += mult * ic;
 
            if (const_from_elts_p && const_p)
              const_p = const_elt_p;
@@ -4902,12 +5026,12 @@ categorize_ctor_elements_1 (const_tree c
        case FIXED_CST:
          if (!initializer_zerop (value))
            nz_elts += mult;
-         elt_count += mult;
+         init_elts += mult;
          break;
 
        case STRING_CST:
          nz_elts += mult * TREE_STRING_LENGTH (value);
-         elt_count += mult * TREE_STRING_LENGTH (value);
+         init_elts += mult * TREE_STRING_LENGTH (value);
          break;
 
        case COMPLEX_CST:
@@ -4915,7 +5039,7 @@ categorize_ctor_elements_1 (const_tree c
            nz_elts += mult;
          if (!initializer_zerop (TREE_IMAGPART (value)))
            nz_elts += mult;
-         elt_count += mult;
+         init_elts += mult;
          break;
 
        case VECTOR_CST:
@@ -4925,65 +5049,31 @@ categorize_ctor_elements_1 (const_tree c
              {
                if (!initializer_zerop (TREE_VALUE (v)))
                  nz_elts += mult;
-               elt_count += mult;
+               init_elts += mult;
              }
          }
          break;
 
        default:
          {
-           HOST_WIDE_INT tc = count_type_elements (TREE_TYPE (value), true);
-           if (tc < 1)
-             tc = 1;
+           HOST_WIDE_INT tc = count_type_elements (elt_type, false);
            nz_elts += mult * tc;
-           elt_count += mult * tc;
+           init_elts += mult * tc;
 
            if (const_from_elts_p && const_p)
-             const_p = initializer_constant_valid_p (value, TREE_TYPE (value))
+             const_p = initializer_constant_valid_p (value, elt_type)
                        != NULL_TREE;
          }
          break;
        }
     }
 
-  if (!*p_must_clear
-      && (TREE_CODE (TREE_TYPE (ctor)) == UNION_TYPE
-         || TREE_CODE (TREE_TYPE (ctor)) == QUAL_UNION_TYPE))
-    {
-      tree init_sub_type;
-      bool clear_this = true;
-
-      if (!VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)))
-       {
-         /* We don't expect more than one element of the union to be
-            initialized.  Not sure what we should do otherwise... */
-          gcc_assert (VEC_length (constructor_elt, CONSTRUCTOR_ELTS (ctor))
-                     == 1);
-
-          init_sub_type = TREE_TYPE (VEC_index (constructor_elt,
-                                               CONSTRUCTOR_ELTS (ctor),
-                                               0)->value);
-
-         /* ??? 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, false))
-               clear_this = false;
-           }
-       }
-
-      *p_must_clear = clear_this;
-    }
+  if (*p_complete && !complete_ctor_at_level_p (TREE_TYPE (ctor),
+                                               num_fields, elt_type))
+    *p_complete = false;
 
   *p_nz_elts += nz_elts;
-  *p_elt_count += elt_count;
+  *p_init_elts += init_elts;
 
   return const_p;
 }
@@ -4993,111 +5083,50 @@ categorize_ctor_elements_1 (const_tree c
      and place it in *P_NZ_ELTS;
    * how many scalar fields in total are in CTOR,
      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.
+   * whether the constructor is complete -- in the sense that every
+     meaningful byte is explicitly given a value --
+     and place it in *P_COMPLETE.
 
    Return whether or not CTOR is a valid static constant initializer, the same
    as "initializer_constant_valid_p (CTOR, TREE_TYPE (CTOR)) != 0".  */
 
 bool
 categorize_ctor_elements (const_tree ctor, HOST_WIDE_INT *p_nz_elts,
-                         HOST_WIDE_INT *p_elt_count,
-                         bool *p_must_clear)
+                         HOST_WIDE_INT *p_init_elts, bool *p_complete)
 {
   *p_nz_elts = 0;
-  *p_elt_count = 0;
-  *p_must_clear = false;
+  *p_init_elts = 0;
+  *p_complete = true;
 
-  return
-    categorize_ctor_elements_1 (ctor, p_nz_elts, p_elt_count, p_must_clear);
+  return categorize_ctor_elements_1 (ctor, p_nz_elts, p_init_elts, p_complete);
 }
 
-/* Count the number of scalars in TYPE.  Return -1 on overflow or
-   variable-sized.  If ALLOW_FLEXARR is true, don't count flexible
-   array member at the end of the structure.  */
+/* TYPE is initialized by a constructor with NUM_ELTS elements, the last
+   of which had type LAST_TYPE.  Each element was itself a complete
+   initializer, in the sense that every meaningful byte was explicitly
+   given a value.  Return true if the same is true for the constructor
+   as a whole.  */
 
-HOST_WIDE_INT
-count_type_elements (const_tree type, bool allow_flexarr)
+bool
+complete_ctor_at_level_p (const_tree type, HOST_WIDE_INT num_elts,
+                         const_tree last_type)
 {
-  const HOST_WIDE_INT max = ~((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1));
-  switch (TREE_CODE (type))
+  if (TREE_CODE (type) == UNION_TYPE
+      || TREE_CODE (type) == QUAL_UNION_TYPE)
     {
-    case ARRAY_TYPE:
-      {
-       tree telts = array_type_nelts (type);
-       if (telts && host_integerp (telts, 1))
-         {
-           HOST_WIDE_INT n = tree_low_cst (telts, 1) + 1;
-           HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type), false);
-           if (n == 0)
-             return 0;
-           else if (max / n > m)
-             return n * m;
-         }
-       return -1;
-      }
-
-    case RECORD_TYPE:
-      {
-       HOST_WIDE_INT n = 0, t;
-       tree f;
-
-       for (f = TYPE_FIELDS (type); f ; f = DECL_CHAIN (f))
-         if (TREE_CODE (f) == FIELD_DECL)
-           {
-             t = count_type_elements (TREE_TYPE (f), false);
-             if (t < 0)
-               {
-                 /* Check for structures with flexible array member.  */
-                 tree tf = TREE_TYPE (f);
-                 if (allow_flexarr
-                     && DECL_CHAIN (f) == NULL
-                     && TREE_CODE (tf) == ARRAY_TYPE
-                     && TYPE_DOMAIN (tf)
-                     && TYPE_MIN_VALUE (TYPE_DOMAIN (tf))
-                     && integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (tf)))
-                     && !TYPE_MAX_VALUE (TYPE_DOMAIN (tf))
-                     && int_size_in_bytes (type) >= 0)
-                   break;
-
-                 return -1;
-               }
-             n += t;
-           }
-
-       return n;
-      }
+      if (num_elts == 0)
+       return false;
 
-    case UNION_TYPE:
-    case QUAL_UNION_TYPE:
-      return -1;
-
-    case COMPLEX_TYPE:
-      return 2;
-
-    case VECTOR_TYPE:
-      return TYPE_VECTOR_SUBPARTS (type);
+      gcc_assert (num_elts == 1 && last_type);
 
-    case INTEGER_TYPE:
-    case REAL_TYPE:
-    case FIXED_POINT_TYPE:
-    case ENUMERAL_TYPE:
-    case BOOLEAN_TYPE:
-    case POINTER_TYPE:
-    case OFFSET_TYPE:
-    case REFERENCE_TYPE:
-      return 1;
-
-    case ERROR_MARK:
-      return 0;
-
-    case VOID_TYPE:
-    case METHOD_TYPE:
-    case FUNCTION_TYPE:
-    case LANG_TYPE:
-    default:
-      gcc_unreachable ();
+      /* ??? 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...  */
+      return simple_cst_equal (TYPE_SIZE (type), TYPE_SIZE (last_type)) == 1;
     }
+
+  return count_type_elements (type, true) == num_elts;
 }
 
 /* Return 1 if EXP contains mostly (3/4)  zeros.  */
@@ -5106,18 +5135,12 @@ count_type_elements (const_tree type, bo
 mostly_zeros_p (const_tree exp)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR)
-
     {
-      HOST_WIDE_INT nz_elts, count, elts;
-      bool must_clear;
-
-      categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
-      if (must_clear)
-       return 1;
+      HOST_WIDE_INT nz_elts, init_elts;
+      bool complete_p;
 
-      elts = count_type_elements (TREE_TYPE (exp), false);
-
-      return nz_elts < elts / 4;
+      categorize_ctor_elements (exp, &nz_elts, &init_elts, &complete_p);
+      return !complete_p || nz_elts < init_elts / 4;
     }
 
   return initializer_zerop (exp);
@@ -5129,13 +5152,12 @@ mostly_zeros_p (const_tree exp)
 all_zeros_p (const_tree exp)
 {
   if (TREE_CODE (exp) == CONSTRUCTOR)
-
     {
-      HOST_WIDE_INT nz_elts, count;
-      bool must_clear;
+      HOST_WIDE_INT nz_elts, init_elts;
+      bool complete_p;
 
-      categorize_ctor_elements (exp, &nz_elts, &count, &must_clear);
-      return nz_elts == 0;
+      categorize_ctor_elements (exp, &nz_elts, &init_elts, &complete_p);
+      return nz_elts == init_elts;
     }
 
   return initializer_zerop (exp);
Index: gcc/gimplify.c
===================================================================
--- gcc/gimplify.c      2011-07-12 15:30:05.000000000 +0100
+++ gcc/gimplify.c      2011-07-12 15:32:43.000000000 +0100
@@ -3731,9 +3731,8 @@ gimplify_init_constructor (tree *expr_p,
     case ARRAY_TYPE:
       {
        struct gimplify_init_ctor_preeval_data preeval_data;
-       HOST_WIDE_INT num_type_elements, num_ctor_elements;
-       HOST_WIDE_INT num_nonzero_elements;
-       bool cleared, valid_const_initializer;
+       HOST_WIDE_INT num_ctor_elements, num_nonzero_elements;
+       bool cleared, complete_p, valid_const_initializer;
 
        /* Aggregate types must lower constructors to initialization of
           individual elements.  The exception is that a CONSTRUCTOR node
@@ -3750,7 +3749,7 @@ gimplify_init_constructor (tree *expr_p,
           can only do so if it known to be a valid constant initializer.  */
        valid_const_initializer
          = categorize_ctor_elements (ctor, &num_nonzero_elements,
-                                     &num_ctor_elements, &cleared);
+                                     &num_ctor_elements, &complete_p);
 
        /* If a const aggregate variable is being initialized, then it
           should never be a lose to promote the variable to be static.  */
@@ -3788,26 +3787,29 @@ gimplify_init_constructor (tree *expr_p,
           parts in, then generate code for the non-constant parts.  */
        /* TODO.  There's code in cp/typeck.c to do this.  */
 
-       num_type_elements = count_type_elements (type, true);
-
-       /* If count_type_elements could not determine number of type elements
-          for a constant-sized object, assume clearing is needed.
-          Don't do this for variable-sized objects, as store_constructor
-          will ignore the clearing of variable-sized objects.  */
-       if (num_type_elements < 0 && int_size_in_bytes (type) >= 0)
+       if (int_size_in_bytes (TREE_TYPE (ctor)) < 0)
+         /* store_constructor will ignore the clearing of variable-sized
+            objects.  Initializers for such objects must explicitly set
+            every field that needs to be set.  */
+         cleared = false;
+       else if (!complete_p)
+         /* If the constructor isn't complete, clear the whole object
+            beforehand.
+
+            ??? This ought not to be needed.  For any element not present
+            in the initializer, we should simply set them to zero.  Except
+            we'd need to *find* the elements that are not present, and that
+            requires trickery to avoid quadratic compile-time behavior in
+            large cases or excessive memory use in small cases.  */
          cleared = true;
-       /* If there are "lots" of zeros, then block clear the object first.  */
-       else if (num_type_elements - num_nonzero_elements
+       else if (num_ctor_elements - num_nonzero_elements
                 > CLEAR_RATIO (optimize_function_for_speed_p (cfun))
-                && num_nonzero_elements < num_type_elements/4)
-         cleared = true;
-       /* ??? This bit ought not be needed.  For any element not present
-          in the initializer, we should simply set them to zero.  Except
-          we'd need to *find* the elements that are not present, and that
-          requires trickery to avoid quadratic compile-time behavior in
-          large cases or excessive memory use in small cases.  */
-       else if (num_ctor_elements < num_type_elements)
+                && num_nonzero_elements < num_ctor_elements / 4)
+         /* If there are "lots" of zeros, it's more efficient to clear
+            the memory and then set the nonzero elements.  */
          cleared = true;
+       else
+         cleared = false;
 
        /* If there are "lots" of initialized elements, and all of them
           are valid address constants, then the entire initializer can
Index: gcc/cp/typeck2.c
===================================================================
--- gcc/cp/typeck2.c    2011-07-12 15:30:05.000000000 +0100
+++ gcc/cp/typeck2.c    2011-07-12 15:32:34.000000000 +0100
@@ -481,18 +481,20 @@ cxx_incomplete_type_error (const_tree va
 
 
 /* The recursive part of split_nonconstant_init.  DEST is an lvalue
-   expression to which INIT should be assigned.  INIT is a CONSTRUCTOR.  */
+   expression to which INIT should be assigned.  INIT is a CONSTRUCTOR.
+   Return true if the whole of the value was initialized by the
+   generated statements.  */
 
-static void
-split_nonconstant_init_1 (tree dest, tree *initp)
+static bool
+split_nonconstant_init_1 (tree dest, tree init)
 {
   unsigned HOST_WIDE_INT idx;
-  tree init = *initp;
   tree field_index, value;
   tree type = TREE_TYPE (dest);
   tree inner_type = NULL;
   bool array_type_p = false;
-  HOST_WIDE_INT num_type_elements, num_initialized_elements;
+  bool complete_p = true;
+  HOST_WIDE_INT num_elts = 0;
 
   switch (TREE_CODE (type))
     {
@@ -504,7 +506,6 @@ split_nonconstant_init_1 (tree dest, tre
     case RECORD_TYPE:
     case UNION_TYPE:
     case QUAL_UNION_TYPE:
-      num_initialized_elements = 0;
       FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx,
                                field_index, value)
        {
@@ -527,13 +528,14 @@ split_nonconstant_init_1 (tree dest, tre
                sub = build3 (COMPONENT_REF, inner_type, dest, field_index,
                              NULL_TREE);
 
-             split_nonconstant_init_1 (sub, &value);
+             if (!split_nonconstant_init_1 (sub, value))
+               complete_p = false;
+             num_elts++;
            }
          else if (!initializer_constant_valid_p (value, inner_type))
            {
              tree code;
              tree sub;
-             HOST_WIDE_INT inner_elements;
 
              /* FIXME: Ordered removal is O(1) so the whole function is
                 worst-case quadratic. This could be fixed using an aside
@@ -557,21 +559,9 @@ split_nonconstant_init_1 (tree dest, tre
              code = build_stmt (input_location, EXPR_STMT, code);
              add_stmt (code);
 
-             inner_elements = count_type_elements (inner_type, true);
-             if (inner_elements < 0)
-               num_initialized_elements = -1;
-             else if (num_initialized_elements >= 0)
-               num_initialized_elements += inner_elements;
-             continue;
+             num_elts++;
            }
        }
-
-      num_type_elements = count_type_elements (type, true);
-      /* If all elements of the initializer are non-constant and
-        have been split out, we don't need the empty CONSTRUCTOR.  */
-      if (num_type_elements > 0
-         && num_type_elements == num_initialized_elements)
-       *initp = NULL;
       break;
 
     case VECTOR_TYPE:
@@ -583,6 +573,7 @@ split_nonconstant_init_1 (tree dest, tre
          code = build2 (MODIFY_EXPR, type, dest, cons);
          code = build_stmt (input_location, EXPR_STMT, code);
          add_stmt (code);
+         num_elts += CONSTRUCTOR_NELTS (init);
        }
       break;
 
@@ -592,6 +583,8 @@ split_nonconstant_init_1 (tree dest, tre
 
   /* The rest of the initializer is now a constant. */
   TREE_CONSTANT (init) = 1;
+  return complete_p && complete_ctor_at_level_p (TREE_TYPE (init),
+                                                num_elts, inner_type);
 }
 
 /* A subroutine of store_init_value.  Splits non-constant static
@@ -607,7 +600,8 @@ split_nonconstant_init (tree dest, tree 
   if (TREE_CODE (init) == CONSTRUCTOR)
     {
       code = push_stmt_list ();
-      split_nonconstant_init_1 (dest, &init);
+      if (split_nonconstant_init_1 (dest, init))
+       init = NULL_TREE;
       code = pop_stmt_list (code);
       DECL_INITIAL (dest) = init;
       TREE_READONLY (dest) = 0;
Index: gcc/testsuite/gcc.target/arm/pr48183.c
===================================================================
--- /dev/null   2011-07-06 08:45:41.269790986 +0100
+++ gcc/testsuite/gcc.target/arm/pr48183.c      2011-07-12 15:32:34.000000000 
+0100
@@ -0,0 +1,25 @@
+/* testsuite/gcc.target/arm/pr48183.c */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-options "-O -g" } */
+/* { dg-add-options arm_neon } */
+
+#include <arm_neon.h>
+
+void move_16bit_to_32bit (int32_t *dst, const short *src, unsigned n)
+{
+    unsigned i;
+    int16x4x2_t input;
+    int32x4x2_t mid;
+    int32x4x2_t output;
+
+    for (i = 0; i < n/2; i += 8) {
+        input = vld2_s16(src + i);
+        mid.val[0] = vmovl_s16(input.val[0]);
+        mid.val[1] = vmovl_s16(input.val[1]);
+        output.val[0] = vshlq_n_s32(mid.val[0], 8);
+        output.val[1] = vshlq_n_s32(mid.val[1], 8);
+        vst2q_s32((int32_t *)dst + i, output);
+    }
+}

Reply via email to