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]

[tree-ssa] fix opt/13798


The problem shown by this case is similar to that addressed recently in
the C++ front end wrt static initializers.  It really really sucks to
generate 40,000 assignment statements in order to initialize a large array.

This duplicates some logic that expr.c uses in the tree->rtl converter
to decide to drop such large constructors into readonly memory.  We then
memcpy from the readonly memory to the variable.

One change from the expr.c logic is that, if the variable itself is
marked readonly, then the variable is promoted to be static.  This 
eliminates the need for a memcpy at all.  I can't find any downside
to this promotion, so it is done unconditionally, no matter the size
of the constructor.

This does highlight a flaw in the cgraph code in that it cannot remove
unused local static variables.  Primarily because it doesn't even see
these variables until after it has decided all variables must be emitted.
I'm not sure how to address this, exactly.

Tested on alpha-linux.


r~


        PR opt/13798
        * expr.c (is_zeros_p): Remove.  Change all callers to use
        initializer_zerop.
        (categorize_ctor_elements_1, categorize_ctor_elements): New.
        (count_type_elements): New.
        (mostly_zeros_p): Use them.
        * gimplify.c (tmp_var_id_num): Split out from create_tmp_var_raw.
        (create_tmp_var_name): Likewise.
        (gimplify_init_constructor): Drop constructors to readonly memory
        as indicated by categorize_ctor_elements and can_move_by_pieces.
        * tree.c (initializer_zerop): Handle VECTOR_CST.  Don't check
        AGGREGATE_TYPE_P for CONSTRUCTOR.
        * tree.h (categorize_ctor_elements): Declare.
        (count_type_elements): Declare.
        * Makefile.in (gimplify.o): Update dependencies.
        (GTFILES): Add gimplify.c.

Index: Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.903.2.171
diff -c -p -d -b -r1.903.2.171 Makefile.in
*** Makefile.in	23 Jan 2004 08:49:27 -0000	1.903.2.171
--- Makefile.in	28 Jan 2004 09:06:23 -0000
*************** c-simplify.o : c-simplify.c $(CONFIG_H) 
*** 1603,1609 ****
  gimplify.o : gimplify.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \
     diagnostic.h $(TREE_SIMPLE_H) tree-inline.h varray.h langhooks.h \
     langhooks-def.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h except.h \
!    flags.h $(RTL_H) function.h
  gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \
     diagnostic.h $(TREE_SIMPLE_H) tree-inline.h varray.h langhooks.h \
     langhooks-def.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h except.h \
--- 1603,1609 ----
  gimplify.o : gimplify.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \
     diagnostic.h $(TREE_SIMPLE_H) tree-inline.h varray.h langhooks.h \
     langhooks-def.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h except.h \
!    flags.h $(RTL_H) function.h $(EXPR_H) output.h $(GGC_H) gt-gimplify.h
  gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \
     diagnostic.h $(TREE_SIMPLE_H) tree-inline.h varray.h langhooks.h \
     langhooks-def.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h except.h \
*************** GTFILES = $(srcdir)/input.h $(srcdir)/co
*** 2202,2208 ****
    $(srcdir)/tree-ssanames.c $(srcdir)/tree-eh.c \
    $(srcdir)/tree-phinodes.c $(srcdir)/tree-cfg.c \
    $(srcdir)/tree-ssa.c $(srcdir)/tree-dfa.c $(srcdir)/tree-ssa-ccp.c \
!   $(srcdir)/tree-iterator.c \
    $(srcdir)/tree-alias-type.h $(srcdir)/tree-alias-common.h \
    $(srcdir)/tree-alias-type.c $(srcdir)/tree-alias-common.c \
    $(srcdir)/tree-ssa-operands.h $(srcdir)/tree-ssa-operands.c \
--- 2202,2208 ----
    $(srcdir)/tree-ssanames.c $(srcdir)/tree-eh.c \
    $(srcdir)/tree-phinodes.c $(srcdir)/tree-cfg.c \
    $(srcdir)/tree-ssa.c $(srcdir)/tree-dfa.c $(srcdir)/tree-ssa-ccp.c \
!   $(srcdir)/tree-iterator.c $(srcdir)/gimplify.c \
    $(srcdir)/tree-alias-type.h $(srcdir)/tree-alias-common.h \
    $(srcdir)/tree-alias-type.c $(srcdir)/tree-alias-common.c \
    $(srcdir)/tree-ssa-operands.h $(srcdir)/tree-ssa-operands.c \
*************** gt-dbxout.h gt-c-common.h gt-c-decl.h gt
*** 2224,2230 ****
  gt-c-pragma.h gtype-c.h gt-input.h gt-cfglayout.h \
  gt-tree-alias-common.h gt-tree-mudflap.h \
  gt-tree-ssa.h gt-tree-dfa.h gt-tree-ssa-ccp.h gt-tree-eh.h \
! gt-tree-ssanames.h gt-tree-iterator.h \
  gt-tree-phinodes.h gt-tree-cfg.h \
  gt-stringpool.h gt-langhooks.h : s-gtype ; @true
  
--- 2224,2230 ----
  gt-c-pragma.h gtype-c.h gt-input.h gt-cfglayout.h \
  gt-tree-alias-common.h gt-tree-mudflap.h \
  gt-tree-ssa.h gt-tree-dfa.h gt-tree-ssa-ccp.h gt-tree-eh.h \
! gt-tree-ssanames.h gt-tree-iterator.h gt-gimplify.h \
  gt-tree-phinodes.h gt-tree-cfg.h \
  gt-stringpool.h gt-langhooks.h : s-gtype ; @true
  
Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.467.2.72
diff -c -p -d -b -r1.467.2.72 expr.c
*** expr.c	6 Jan 2004 22:52:04 -0000	1.467.2.72
--- expr.c	28 Jan 2004 09:06:24 -0000
*************** static rtx clear_storage_via_libcall (rt
*** 152,158 ****
  static tree clear_storage_libcall_fn (int);
  static rtx compress_float_constant (rtx, rtx);
  static rtx get_subtarget (rtx);
- static int is_zeros_p (tree);
  static void store_constructor_field (rtx, unsigned HOST_WIDE_INT,
  				     HOST_WIDE_INT, enum machine_mode,
  				     tree, tree, int, int);
--- 152,157 ----
*************** store_expr (tree exp, rtx target, int wa
*** 4360,4409 ****
      return target;
  }
  
! /* Return 1 if EXP just contains zeros.  FIXME merge with initializer_zerop.  */
  
! static int
! is_zeros_p (tree exp)
  {
!   tree elt;
  
!   switch (TREE_CODE (exp))
      {
!     case CONVERT_EXPR:
!     case NOP_EXPR:
!     case NON_LVALUE_EXPR:
!     case VIEW_CONVERT_EXPR:
!       return is_zeros_p (TREE_OPERAND (exp, 0));
  
!     case INTEGER_CST:
!       return integer_zerop (exp);
  
!     case COMPLEX_CST:
!       return
! 	is_zeros_p (TREE_REALPART (exp)) && is_zeros_p (TREE_IMAGPART (exp));
  
!     case REAL_CST:
!       return REAL_VALUES_IDENTICAL (TREE_REAL_CST (exp), dconst0);
  
      case VECTOR_CST:
!       for (elt = TREE_VECTOR_CST_ELTS (exp); elt;
! 	   elt = TREE_CHAIN (elt))
! 	if (!is_zeros_p (TREE_VALUE (elt)))
! 	  return 0;
  
!       return 1;
  
!     case CONSTRUCTOR:
!       if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
! 	return CONSTRUCTOR_ELTS (exp) == NULL_TREE;
!       for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
! 	if (! is_zeros_p (TREE_VALUE (elt)))
  	  return 0;
  
        return 1;
  
      default:
!       return 0;
      }
  }
  
--- 4359,4524 ----
      return target;
  }
  
! /* Examine CTOR.  Discover how many scalar fields are set to non-zero
!    values and place it in *P_NZ_ELTS.  Discover how many scalar fields
!    are set to non-constant values and place it in  *P_NC_ELTS.  */
  
! static void
! categorize_ctor_elements_1 (tree ctor, HOST_WIDE_INT *p_nz_elts,
! 			    HOST_WIDE_INT *p_nc_elts)
  {
!   HOST_WIDE_INT nz_elts, nc_elts;
!   tree list;
  
!   nz_elts = 0;
!   nc_elts = 0;
!   
!   for (list = CONSTRUCTOR_ELTS (ctor); list; list = TREE_CHAIN (list))
      {
!       tree value = TREE_VALUE (list);
!       tree purpose = TREE_PURPOSE (list);
!       HOST_WIDE_INT mult;
  
!       mult = 1;
!       if (TREE_CODE (purpose) == RANGE_EXPR)
! 	{
! 	  tree lo_index = TREE_OPERAND (purpose, 0);
! 	  tree hi_index = TREE_OPERAND (purpose, 1);
  
! 	  if (host_integerp (lo_index, 1) && host_integerp (hi_index, 1))
! 	    mult = (tree_low_cst (hi_index, 1)
! 		    - tree_low_cst (lo_index, 1) + 1);
! 	}
  
!       switch (TREE_CODE (value))
! 	{
! 	case CONSTRUCTOR:
! 	  {
! 	    HOST_WIDE_INT nz = 0, nc = 0;
! 	    categorize_ctor_elements_1 (value, &nz, &nc);
! 	    nz_elts += mult * nz;
! 	    nc_elts += mult * nc;
! 	  }
! 	  break;
  
+ 	case INTEGER_CST:
+ 	case REAL_CST:
+ 	  if (!initializer_zerop (value))
+ 	    nz_elts += mult;
+ 	  break;
+ 	case COMPLEX_CST:
+ 	  if (!initializer_zerop (TREE_REALPART (value)))
+ 	    nz_elts += mult;
+ 	  if (!initializer_zerop (TREE_IMAGPART (value)))
+ 	    nz_elts += mult;
+ 	  break;
  	case VECTOR_CST:
! 	  {
! 	    tree v;
! 	    for (v = TREE_VECTOR_CST_ELTS (value); v; v = TREE_CHAIN (v))
! 	      if (!initializer_zerop (TREE_VALUE (v)))
! 	        nz_elts += mult;
! 	  }
! 	  break;
  
! 	default:
! 	  nz_elts += mult;
! 	  if (!initializer_constant_valid_p (value, TREE_TYPE (value)))
! 	    nc_elts += mult;
! 	  break;
! 	}
!     }
  
!   *p_nz_elts += nz_elts;
!   *p_nc_elts += nc_elts;
! }
! 
! void
! categorize_ctor_elements (tree ctor, HOST_WIDE_INT *p_nz_elts,
! 			  HOST_WIDE_INT *p_nc_elts)
! {
!   *p_nz_elts = 0;
!   *p_nc_elts = 0;
!   categorize_ctor_elements_1 (ctor, p_nz_elts, p_nc_elts);
! }
! 
! /* Count the number of scalars in TYPE.  Return -1 on overflow or
!    variable-sized.  */
! 
! HOST_WIDE_INT
! count_type_elements (tree type)
! {
!   const HOST_WIDE_INT max = ~((HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1));
!   switch (TREE_CODE (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);
! 	    HOST_WIDE_INT m = count_type_elements (TREE_TYPE (type));
! 	    if (n == 0)
  	      return 0;
+ 	    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 = TREE_CHAIN (f))
+ 	  if (TREE_CODE (f) == FIELD_DECL)
+ 	    {
+ 	      t = count_type_elements (TREE_TYPE (f));
+ 	      if (t < 0)
+ 		return -1;
+ 	      n += t;
+ 	    }
+ 
+ 	return n;
+       }
+ 
+     case UNION_TYPE:
+     case QUAL_UNION_TYPE:
+       {
+ 	/* Ho hum.  How in the world do we guess here?  Clearly it isn't
+ 	   right to count the fields.  Guess based on the number of words.  */
+         HOST_WIDE_INT n = int_size_in_bytes (type);
+ 	if (n < 0)
+ 	  return -1;
+ 	return n / UNITS_PER_WORD;
+       }
+ 
+     case COMPLEX_TYPE:
+       return 2;
+ 
+     case VECTOR_TYPE:
+       /* ??? This is broke.  We should encode the vector width in the tree.  */
+       return GET_MODE_NUNITS (TYPE_MODE (type));
+ 
+     case INTEGER_TYPE:
+     case REAL_TYPE:
+     case ENUMERAL_TYPE:
+     case BOOLEAN_TYPE:
+     case CHAR_TYPE:
+     case POINTER_TYPE:
+     case OFFSET_TYPE:
+     case REFERENCE_TYPE:
        return 1;
  
+     case VOID_TYPE:
+     case METHOD_TYPE:
+     case FILE_TYPE:
+     case SET_TYPE:
+     case FUNCTION_TYPE:
+     case LANG_TYPE:
      default:
!       abort ();
      }
  }
  
*************** int
*** 4413,4442 ****
  mostly_zeros_p (tree exp)
  {
    if (TREE_CODE (exp) == CONSTRUCTOR)
      {
!       int elts = 0, zeros = 0;
!       tree elt = CONSTRUCTOR_ELTS (exp);
!       if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
! 	{
  	  /* If there are no ranges of true bits, it is all zero.  */
! 	  return elt == NULL_TREE;
! 	}
!       for (; elt; elt = TREE_CHAIN (elt))
! 	{
! 	  /* We do not handle the case where the index is a RANGE_EXPR,
! 	     so the statistic will be somewhat inaccurate.
! 	     We do make a more accurate count in store_constructor itself,
! 	     so since this function is only used for nested array elements,
! 	     this should be close enough.  */
! 	  if (mostly_zeros_p (TREE_VALUE (elt)))
! 	    zeros++;
! 	  elts++;
! 	}
  
!       return 4 * zeros >= 3 * elts;
      }
  
!   return is_zeros_p (exp);
  }
  
  /* Helper function for store_constructor.
--- 4528,4548 ----
  mostly_zeros_p (tree exp)
  {
    if (TREE_CODE (exp) == CONSTRUCTOR)
+     
      {
!       HOST_WIDE_INT nz_elts, nc_elts, elts;
! 
        /* If there are no ranges of true bits, it is all zero.  */
!       if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
! 	return CONSTRUCTOR_ELTS (exp) == NULL_TREE;
  
!       categorize_ctor_elements (exp, &nz_elts, &nc_elts);
!       elts = count_type_elements (TREE_TYPE (exp));
! 
!       return nz_elts < elts / 4;
      }
  
!   return initializer_zerop (exp);
  }
  
  /* Helper function for store_constructor.
*************** store_constructor (tree exp, rtx target,
*** 4576,4582 ****
  	  if (field == 0)
  	    continue;
  
! 	  if (cleared && is_zeros_p (value))
  	    continue;
  
  	  if (host_integerp (DECL_SIZE (field), 1))
--- 4682,4688 ----
  	  if (field == 0)
  	    continue;
  
! 	  if (cleared && initializer_zerop (value))
  	    continue;
  
  	  if (host_integerp (DECL_SIZE (field), 1))
*************** store_constructor (tree exp, rtx target,
*** 4811,4817 ****
  	  tree index = TREE_PURPOSE (elt);
  	  rtx xtarget = target;
  
! 	  if (cleared && is_zeros_p (value))
  	    continue;
  
  	  unsignedp = TREE_UNSIGNED (elttype);
--- 4917,4923 ----
  	  tree index = TREE_PURPOSE (elt);
  	  rtx xtarget = target;
  
! 	  if (cleared && initializer_zerop (value))
  	    continue;
  
  	  unsignedp = TREE_UNSIGNED (elttype);
*************** expand_expr_1 (tree exp, rtx target, enu
*** 6899,6907 ****
  			&& (! MOVE_BY_PIECES_P
  			    (tree_low_cst (TYPE_SIZE_UNIT (type), 1),
  			     TYPE_ALIGN (type)))
! 			&& ((TREE_CODE (type) == VECTOR_TYPE
! 			     && !is_zeros_p (exp))
! 			    || ! mostly_zeros_p (exp)))))
  	       || ((modifier == EXPAND_INITIALIZER
  		    || modifier == EXPAND_CONST_ADDRESS)
  		   && TREE_CONSTANT (exp)))
--- 7005,7011 ----
  			&& (! MOVE_BY_PIECES_P
  			    (tree_low_cst (TYPE_SIZE_UNIT (type), 1),
  			     TYPE_ALIGN (type)))
! 			&& ! mostly_zeros_p (exp))))
  	       || ((modifier == EXPAND_INITIALIZER
  		    || modifier == EXPAND_CONST_ADDRESS)
  		   && TREE_CONSTANT (exp)))
*************** const_vector_from_tree (tree exp)
*** 10110,10116 ****
  
    mode = TYPE_MODE (TREE_TYPE (exp));
  
!   if (is_zeros_p (exp))
      return CONST0_RTX (mode);
  
    units = GET_MODE_NUNITS (mode);
--- 10214,10220 ----
  
    mode = TYPE_MODE (TREE_TYPE (exp));
  
!   if (initializer_zerop (exp))
      return CONST0_RTX (mode);
  
    units = GET_MODE_NUNITS (mode);
Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Attic/gimplify.c,v
retrieving revision 1.1.2.137
diff -c -p -d -b -r1.1.2.137 gimplify.c
*** gimplify.c	27 Jan 2004 22:49:08 -0000	1.1.2.137
--- gimplify.c	28 Jan 2004 09:06:24 -0000
*************** Software Foundation, 59 Temple Place - S
*** 42,47 ****
--- 42,50 ----
  #include "flags.h"
  #include "real.h"
  #include "function.h"
+ #include "output.h"
+ #include "expr.h"
+ #include "ggc.h"
  
  static struct gimplify_ctx
  {
*************** create_artificial_label (void)
*** 282,313 ****
    return lab;
  }
  
! /* Create a new temporary variable declaration of type TYPE.
!    Does NOT push it into the current binding.  */
  
! tree
! create_tmp_var_raw (tree type, const char *prefix)
  {
-   static unsigned int id_num = 1;
    char *tmp_name;
-   char *preftmp = NULL;
-   tree tmp_var;
-   tree new_type;
  
    if (prefix)
      {
!       preftmp = ASTRDUP (prefix);
        remove_suffix (preftmp, strlen (preftmp));
        prefix = preftmp;
      }
  
!   ASM_FORMAT_PRIVATE_NAME (tmp_name, (prefix ? prefix : "T"), id_num++);
  
    /* Make the type of the variable writable.  */
    new_type = build_type_variant (type, 0, 0);
    TYPE_ATTRIBUTES (new_type) = TYPE_ATTRIBUTES (type);
  
!   tmp_var = build_decl (VAR_DECL, get_identifier (tmp_name), type);
  
    /* The variable was declared by the compiler.  */
    DECL_ARTIFICIAL (tmp_var) = 1;
--- 285,325 ----
    return lab;
  }
  
! /* Create a new temporary name with PREFIX.  Returns an indentifier.  */
  
! static GTY(()) unsigned int tmp_var_id_num;
! 
! static tree
! create_tmp_var_name (const char *prefix)
  {
    char *tmp_name;
  
    if (prefix)
      {
!       char *preftmp = ASTRDUP (prefix);
        remove_suffix (preftmp, strlen (preftmp));
        prefix = preftmp;
      }
  
!   ASM_FORMAT_PRIVATE_NAME (tmp_name, prefix ? prefix : "T", tmp_var_id_num++);
!   return get_identifier (tmp_name);
! }
! 
! 
! /* Create a new temporary variable declaration of type TYPE.
!    Does NOT push it into the current binding.  */
! 
! tree
! create_tmp_var_raw (tree type, const char *prefix)
! {
!   tree tmp_var;
!   tree new_type;
  
    /* Make the type of the variable writable.  */
    new_type = build_type_variant (type, 0, 0);
    TYPE_ATTRIBUTES (new_type) = TYPE_ATTRIBUTES (type);
  
!   tmp_var = build_decl (VAR_DECL, create_tmp_var_name (prefix), type);
  
    /* The variable was declared by the compiler.  */
    DECL_ARTIFICIAL (tmp_var) = 1;
*************** gimplify_init_constructor (tree *expr_p,
*** 1114,1121 ****
    tree type = TREE_TYPE (ctor);
    enum gimplify_status ret;
    tree elt_list;
-   bool cleared;
-   int len, i;
  
    if (TREE_CODE (ctor) != CONSTRUCTOR)
      return GS_UNHANDLED;
--- 1126,1131 ----
*************** gimplify_init_constructor (tree *expr_p,
*** 1129,1138 ****
      case UNION_TYPE:
      case QUAL_UNION_TYPE:
      case ARRAY_TYPE:
        /* Aggregate types must lower constructors to initialization of
  	 individual elements.  The exception is that a CONSTRUCTOR node
  	 with no elements indicates zero-initialization of the whole.  */
- 
        if (elt_list == NULL)
  	{
  	  if (want_value)
--- 1139,1152 ----
      case UNION_TYPE:
      case QUAL_UNION_TYPE:
      case ARRAY_TYPE:
+       {
+ 	HOST_WIDE_INT i, num_elements, num_nonzero_elements;
+ 	HOST_WIDE_INT num_nonconstant_elements;
+ 	bool cleared;
+ 
  	/* Aggregate types must lower constructors to initialization of
  	   individual elements.  The exception is that a CONSTRUCTOR node
  	   with no elements indicates zero-initialization of the whole.  */
  	if (elt_list == NULL)
  	  {
  	    if (want_value)
*************** gimplify_init_constructor (tree *expr_p,
*** 1144,1163 ****
  	    return GS_ALL_DONE;
  	}
  
!       cleared = false;
!       len = list_length (elt_list);
  
!       if (mostly_zeros_p (ctor))
  	cleared = true;
!       else if (TREE_CODE (type) == ARRAY_TYPE)
  	{
  	  tree nelts = array_type_nelts (type);
! 	  if (TREE_CODE (nelts) != INTEGER_CST
! 	      || (unsigned)len != TREE_INT_CST_LOW (nelts)+1)
! 	    cleared = 1;
  	}
        else if (len != fields_length (type))
  	cleared = 1;
  
        if (cleared)
  	{
--- 1158,1255 ----
  	      return GS_ALL_DONE;
  	  }
  
! 	categorize_ctor_elements (ctor, &num_nonzero_elements,
! 				  &num_nonconstant_elements);
! 	num_elements = count_type_elements (TREE_TYPE (ctor));
  
! 	/* 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
! 	    && TREE_READONLY (object)
! 	    && TREE_CODE (object) == VAR_DECL)
! 	  {
! 	    DECL_INITIAL (object) = ctor;
! 	    TREE_STATIC (object) = 1;
! 	    if (!DECL_NAME (object))
! 	      DECL_NAME (object) = create_tmp_var_name ("C");
! 	    *expr_p = build_empty_stmt ();
! 	    break;
! 	  }
! 
! 	/* If there are "lots" of initialized elements, and all of them
! 	   are valid address constants, then the entire initializer can
! 	   be dropped to memory, and then memcpy'd out.  */
! 	if (num_nonconstant_elements == 0)
! 	  {
! 	    HOST_WIDE_INT size = int_size_in_bytes (type);
! 	    unsigned int align;
! 
! 	    /* ??? We can still get unbounded array types, at least
! 	       from the C++ front end.  This seems wrong, but attempt
! 	       to work around it for now.  */
! 	    if (size < 0)
! 	      {
! 		size = int_size_in_bytes (TREE_TYPE (object));
! 		if (size >= 0)
! 		  TREE_TYPE (ctor) = type = TREE_TYPE (object);
! 	      }
! 
! 	    /* Find the maximum alignment we can assume for the object.  */
! 	    /* ??? Make use of DECL_OFFSET_ALIGN.  */
! 	    if (DECL_P (object))
! 	      align = DECL_ALIGN (object);
! 	    else
! 	      align = TYPE_ALIGN (type);
! 
! 	    if (size > 0 && !can_move_by_pieces (size, align))
! 	      {
! 		tree new = create_tmp_var_raw (type, "C");
! 		gimple_add_tmp_var (new);
! 		TREE_STATIC (new) = 1;
! 		TREE_READONLY (new) = 1;
! 		DECL_INITIAL (new) = ctor;
! 		if (align > DECL_ALIGN (new))
! 		  {
! 		    DECL_ALIGN (new) = align;
! 		    DECL_USER_ALIGN (new) = 1;
! 		  }
! 
! 		TREE_OPERAND (*expr_p, 1) = new;
! 		break;
! 	      }
! 	  }
! 
! 	/* If there are "lots" of initialized elements, even discounting
! 	   those that are not address constants (and thus *must* be 
! 	   computed at runtime), then partition the constructor into
! 	   constant and non-constant parts.  Block copy the constant
! 	   parts in, then generate code for the non-constant parts.  */
! 	/* TODO.  There's code in cp/typeck.c to do this.  */
! 
! 	/* If there are "lots" of zeros, then block clear the object first.  */
! 	cleared = false;
! 	if (num_elements - num_nonzero_elements > CLEAR_RATIO
! 	    && num_nonzero_elements < num_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 behaviour in
! 	   large cases or excessive memory use in small cases.  */
! 	else
! 	  {
! 	    HOST_WIDE_INT len = list_length (elt_list);
! 	    if (TREE_CODE (type) == ARRAY_TYPE)
  	      {
  		tree nelts = array_type_nelts (type);
! 		if (!host_integerp (nelts, 1)
! 		    || tree_low_cst (nelts, 1) != len)
! 		  cleared = 1;;
  	      }
  	    else if (len != fields_length (type))
  	      cleared = 1;
+ 	  }
  
  	if (cleared)
  	  {
*************** gimplify_init_constructor (tree *expr_p,
*** 1178,1184 ****
  	  if (TREE_CODE (type) == ARRAY_TYPE)
  	    {
  	      tree t = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object)));
! 	      cref = build (ARRAY_REF, t, object, build_int_2 (i, 0));
  	    }
  	  else
  	    {
--- 1270,1286 ----
  	    if (TREE_CODE (type) == ARRAY_TYPE)
  	      {
  		tree t = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object)));
! 
! 		/* ??? Here's to hoping the front end fills in all of the
! 		   indicies, so we don't have to figure out what's missing
! 		   ourselves.  */
! 		if (!purpose)
! 		  abort ();
! 		/* ??? Need to handle this.  */
! 		if (TREE_CODE (purpose) == RANGE_EXPR)
! 		  abort ();
! 
! 		cref = build (ARRAY_REF, t, object, purpose);
  	      }
  	    else
  	      {
*************** gimplify_init_constructor (tree *expr_p,
*** 1193,1198 ****
--- 1295,1301 ----
  	  }
  
  	*expr_p = build_empty_stmt ();
+       }
        break;
  
      case COMPLEX_TYPE:
*************** gimplify_function_tree (tree fndecl)
*** 3580,3582 ****
--- 3683,3687 ----
  
    current_function_decl = oldfn;
  }
+ 
+ #include "gt-gimplify.h"
Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.263.2.76
diff -c -p -d -b -r1.263.2.76 tree.c
*** tree.c	3 Jan 2004 23:02:02 -0000	1.263.2.76
--- tree.c	28 Jan 2004 09:06:25 -0000
*************** make_vector (enum machine_mode mode, tre
*** 5118,5158 ****
  bool
  initializer_zerop (tree init)
  {
    STRIP_NOPS (init);
  
    switch (TREE_CODE (init))
      {
      case INTEGER_CST:
        return integer_zerop (init);
      case REAL_CST:
        return real_zerop (init)
  	&& ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init));
      case COMPLEX_CST:
        return integer_zerop (init)
  	|| (real_zerop (init)
  	    && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_REALPART (init)))
  	    && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_IMAGPART (init))));
!     case CONSTRUCTOR:
!       {
! 	/* Set is empty if it has no elements.  */
!         if ((TREE_CODE (TREE_TYPE (init)) == SET_TYPE)
!              && CONSTRUCTOR_ELTS (init))
  	  return false;
  
! 	if (AGGREGATE_TYPE_P (TREE_TYPE (init)))
! 	  {
! 	    tree aggr_init = CONSTRUCTOR_ELTS (init);
  
! 	    while (aggr_init)
! 	      {
! 		if (! initializer_zerop (TREE_VALUE (aggr_init)))
  		  return false;
! 		aggr_init = TREE_CHAIN (aggr_init);
! 	      }
! 	    return true;
! 	  }
  	return false;
!       }
      default:
        return false;
      }
--- 5118,5165 ----
  bool
  initializer_zerop (tree init)
  {
+   tree elt;
+ 
    STRIP_NOPS (init);
  
    switch (TREE_CODE (init))
      {
      case INTEGER_CST:
        return integer_zerop (init);
+ 
      case REAL_CST:
+       /* ??? Note that this is not correct for C4X float formats.  There,
+ 	 a bit pattern of all zeros is 1.0; 0.0 is encoded with the most
+ 	 negative exponent.  */
        return real_zerop (init)
  	&& ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init));
+ 
      case COMPLEX_CST:
        return integer_zerop (init)
  	|| (real_zerop (init)
  	    && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_REALPART (init)))
  	    && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_IMAGPART (init))));
! 
!     case VECTOR_CST:
!       for (elt = TREE_VECTOR_CST_ELTS (init); elt; elt = TREE_CHAIN (elt))
! 	if (!initializer_zerop (TREE_VALUE (elt)))
  	  return false;
+       return true;
  
!     case CONSTRUCTOR:
!       elt = CONSTRUCTOR_ELTS (init);
!       if (elt == NULL_TREE)
! 	return true;
  
!       /* A set is empty only if it has no elements.  */
!       if (TREE_CODE (TREE_TYPE (init)) == SET_TYPE)
  	return false;
! 
!       for (; elt ; elt = TREE_CHAIN (elt))
! 	if (! initializer_zerop (TREE_VALUE (elt)))
  	  return false;
!       return true;
! 
      default:
        return false;
      }
Index: tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.342.2.162
diff -c -p -d -b -r1.342.2.162 tree.h
*** tree.h	19 Jan 2004 23:21:42 -0000	1.342.2.162
--- tree.h	28 Jan 2004 09:06:25 -0000
*************** extern int fields_length (tree);
*** 2978,2983 ****
--- 2978,2985 ----
  
  extern bool initializer_zerop (tree);
  
+ extern void categorize_ctor_elements (tree, HOST_WIDE_INT *, HOST_WIDE_INT *);
+ extern HOST_WIDE_INT count_type_elements (tree);
  extern int mostly_zeros_p (tree);
  
  /* add_var_to_bind_expr (bind_expr, var) binds var to bind_expr.  */


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