Since it also affects 4.6 branch, can this and r176270 also be ported to gcc4.6?

thanks
Carrot

On Wed, Jul 13, 2011 at 12:34 AM, Richard Sandiford
<richard.sandif...@linaro.org> wrote:
> 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