gcc/
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 13 Jul 2011 11:16:36 +0000 (11:16 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 13 Jul 2011 11:16:36 +0000 (11:16 +0000)
* 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  <cltang@codesourcery.com>

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

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@176228 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/typeck2.c
gcc/expr.c
gcc/gimplify.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/arm/pr48183.c [new file with mode: 0644]
gcc/tree.h

index 0ece8d2..db54952 100644 (file)
@@ -1,3 +1,25 @@
+2011-07-13  Richard Sandiford  <richard.sandiford@linaro.org>
+
+       * 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.
+
 2011-07-13  Richard Guenther  <rguenther@suse.de>
 
        * tree-vrp.c (simplify_conversion_using_ranges): Make sure
index 9e55de8..cfe3bab 100644 (file)
@@ -1,3 +1,10 @@
+2011-07-13  Richard Sandiford  <richard.sandiford@linaro.org>
+
+       * 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.
+
 2011-07-12   Diego Novillo  <dnovillo@google.com>
 
        * name-lookup.h (cp_binding_level): Rename from cxx_scope.
index 023fab3..ac4f383 100644 (file)
@@ -481,18 +481,20 @@ cxx_incomplete_type_error (const_tree value, const_tree type)
 
 \f
 /* 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_split_elts = 0;
 
   switch (TREE_CODE (type))
     {
@@ -504,7 +506,6 @@ split_nonconstant_init_1 (tree dest, tree *initp)
     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, tree *initp)
                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_split_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, tree *initp)
              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_split_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, tree *initp)
          code = build2 (MODIFY_EXPR, type, dest, cons);
          code = build_stmt (input_location, EXPR_STMT, code);
          add_stmt (code);
+         num_split_elts += CONSTRUCTOR_NELTS (init);
        }
       break;
 
@@ -592,6 +583,8 @@ split_nonconstant_init_1 (tree dest, tree *initp)
 
   /* 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_split_elts, inner_type);
 }
 
 /* A subroutine of store_init_value.  Splits non-constant static
@@ -607,7 +600,8 @@ split_nonconstant_init (tree dest, tree init)
   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 77039e8..ed921aa 100644 (file)
@@ -4846,16 +4846,136 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal)
   return NULL_RTX;
 }
 \f
+/* 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 ctor, HOST_WIDE_INT *p_nz_elts,
   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 ctor, HOST_WIDE_INT *p_nz_elts,
            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 ctor, HOST_WIDE_INT *p_nz_elts,
          {
            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 ctor, HOST_WIDE_INT *p_nz_elts,
        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 ctor, HOST_WIDE_INT *p_nz_elts,
            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 ctor, HOST_WIDE_INT *p_nz_elts,
              {
                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 ctor, HOST_WIDE_INT *p_nz_elts,
      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;
-      }
-
-    case UNION_TYPE:
-    case QUAL_UNION_TYPE:
-      return -1;
-
-    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;
+      if (num_elts == 0)
+       return false;
 
-    case ERROR_MARK:
-      return 0;
+      gcc_assert (num_elts == 1 && last_type);
 
-    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 @@ static int
 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 @@ static int
 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 5a928be..1d0b907 100644 (file)
@@ -3731,9 +3731,8 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_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, gimple_seq *pre_p, gimple_seq *post_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, gimple_seq *pre_p, gimple_seq *post_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 58b5931..4febcdf 100644 (file)
@@ -1,3 +1,7 @@
+2011-07-13  Chung-Lin Tang  <cltang@codesourcery.com>
+
+       * gcc.target/arm/pr48183.c: New test.
+
 2011-07-13  Richard Guenther  <rguenther@suse.de>
 
        * gcc.dg/torture/20110713-1.c: New testcase.
diff --git a/gcc/testsuite/gcc.target/arm/pr48183.c b/gcc/testsuite/gcc.target/arm/pr48183.c
new file mode 100644 (file)
index 0000000..f021825
--- /dev/null
@@ -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);
+    }
+}
index 571a71f..fe76f8f 100644 (file)
@@ -4804,21 +4804,10 @@ extern bool initializer_zerop (const_tree);
 
 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.  */