Fixes to array constructors

Richard Kenner kenner@vlsi1.ultra.nyu.edu
Tue Aug 29 19:04:00 GMT 2000


It's possible in the tree (but probably can only happen for Ada) for
the bounds of the array that is the type of the constructor to be a variable.
In the dynamic case (expr.c), this just means it must be handled in the
case way as if an index were variable.  For the static case (varasm.c),
it means that the lower bound should not be consulted unless it is needed,
which is only if an index is specified.  I also did some general cleanup
and improvement of the code in this area.

Tue Aug 29 22:09:59 2000  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>

	* expr.c (store_constructor): Allow variable bounds of array type.
	(expand_expr): Don't blow up if type is ERROR_MARK.
	* varasm.c (output_constructor): Don't access lower bound of array
	type unless need it if index is supplied (so it can be a variable
	if no index is supplied).
	Use tree_low_cst; use HOST_WIDE_INT for sizes; change BITPOS to POS.
	Other minor cleanups.

*** expr.c	2000/08/29 16:23:19	1.255
--- expr.c	2000/08/30 01:54:33
*************** store_constructor (exp, target, align, c
*** 4398,4405 ****
        int need_to_clear;
        tree domain = TYPE_DOMAIN (type);
-       HOST_WIDE_INT minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain));
-       HOST_WIDE_INT maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain));
        tree elttype = TREE_TYPE (type);
  
        /* If the constructor has fewer elements than the array,
           clear the whole array first.  Similarly if this is
--- 4398,4414 ----
        int need_to_clear;
        tree domain = TYPE_DOMAIN (type);
        tree elttype = TREE_TYPE (type);
+       int const_bounds_p = (host_integerp (TYPE_MIN_VALUE (domain), 0)
+ 			    && host_integerp (TYPE_MAX_VALUE (domain), 0));
+       HOST_WIDE_INT minelt;
+       HOST_WIDE_INT maxelt;
  
+       /* If we have constant bounds for the range of the type, get them.  */
+       if (const_bounds_p)
+ 	{
+ 	  minelt = tree_low_cst (TYPE_MIN_VALUE (domain), 0);
+ 	  maxelt = tree_low_cst (TYPE_MAX_VALUE (domain), 0);
+ 	}
+ 
        /* If the constructor has fewer elements than the array,
           clear the whole array first.  Similarly if this is
*************** store_constructor (exp, target, align, c
*** 4410,4419 ****
  	{
  	  HOST_WIDE_INT count = 0, zero_count = 0;
! 	  need_to_clear = 0;
  	  /* This loop is a more accurate version of the loop in
  	     mostly_zeros_p (it handles RANGE_EXPR in an index).
  	     It is also needed to check for missing elements.  */
  	  for (elt = CONSTRUCTOR_ELTS (exp);
! 	       elt != NULL_TREE;
  	       elt = TREE_CHAIN (elt))
  	    {
--- 4419,4429 ----
  	{
  	  HOST_WIDE_INT count = 0, zero_count = 0;
! 	  need_to_clear = ! const_bounds_p;
! 
  	  /* This loop is a more accurate version of the loop in
  	     mostly_zeros_p (it handles RANGE_EXPR in an index).
  	     It is also needed to check for missing elements.  */
  	  for (elt = CONSTRUCTOR_ELTS (exp);
! 	       elt != NULL_TREE && ! need_to_clear;
  	       elt = TREE_CHAIN (elt))
  	    {
*************** store_constructor (exp, target, align, c
*** 4438,4451 ****
  	      else
  		this_node_count = 1;
  	      count += this_node_count;
  	      if (mostly_zeros_p (TREE_VALUE (elt)))
  		zero_count += this_node_count;
  	    }
  	  /* Clear the entire array first if there are any missing elements,
  	     or if the incidence of zero elements is >= 75%.  */
! 	  if (count < maxelt - minelt + 1
! 	      || 4 * zero_count >= 3 * count)
  	    need_to_clear = 1;
  	}
        if (need_to_clear && size > 0)
  	{
--- 4448,4464 ----
  	      else
  		this_node_count = 1;
+ 
  	      count += this_node_count;
  	      if (mostly_zeros_p (TREE_VALUE (elt)))
  		zero_count += this_node_count;
  	    }
+ 
  	  /* Clear the entire array first if there are any missing elements,
  	     or if the incidence of zero elements is >= 75%.  */
! 	  if (! need_to_clear
! 	      && (count < maxelt - minelt + 1 || 4 * zero_count >= 3 * count))
  	    need_to_clear = 1;
  	}
+ 
        if (need_to_clear && size > 0)
  	{
*************** store_constructor (exp, target, align, c
*** 4496,4500 ****
  
  	      /* If the range is constant and "small", unroll the loop.  */
! 	      if (host_integerp (lo_index, 0)
  		  && host_integerp (hi_index, 0)
  		  && (lo = tree_low_cst (lo_index, 0),
--- 4509,4514 ----
  
  	      /* If the range is constant and "small", unroll the loop.  */
! 	      if (const_bounds_p
! 		  && host_integerp (lo_index, 0)
  		  && host_integerp (hi_index, 0)
  		  && (lo = tree_low_cst (lo_index, 0),
*************** expand_expr (exp, target, tmode, modifie
*** 5763,5767 ****
  
    /* Handle ERROR_MARK before anybody tries to access its type.  */
!   if (TREE_CODE (exp) == ERROR_MARK)
      {
        op0 = CONST0_RTX (tmode);
--- 5777,5781 ----
  
    /* Handle ERROR_MARK before anybody tries to access its type.  */
!   if (TREE_CODE (exp) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK)
      {
        op0 = CONST0_RTX (tmode);
*** varasm.c	2000/08/29 21:39:45	1.130
--- varasm.c	2000/08/30 01:54:44
*************** output_constructor (exp, size)
*** 4362,4370 ****
       int size;
  {
    register tree link, field = 0;
!   HOST_WIDE_INT min_index = 0;
    /* Number of bytes output or skipped so far.
       In other words, current position within the constructor.  */
!   int total_bytes = 0;
    /* Non-zero means BYTE contains part of a byte, to be output.  */
    int byte_buffer_in_use = 0;
--- 4362,4371 ----
       int size;
  {
+   tree type = TREE_TYPE (exp);
    register tree link, field = 0;
!   tree min_index = 0;
    /* Number of bytes output or skipped so far.
       In other words, current position within the constructor.  */
!   HOST_WIDE_INT total_bytes = 0;
    /* Non-zero means BYTE contains part of a byte, to be output.  */
    int byte_buffer_in_use = 0;
*************** output_constructor (exp, size)
*** 4374,4384 ****
      abort ();
  
!   if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
!     field = TYPE_FIELDS (TREE_TYPE (exp));
  
!   if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE
!       && TYPE_DOMAIN (TREE_TYPE (exp)) != 0)
!     min_index
!       = TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (exp))));
  
    /* As LINK goes through the elements of the constant,
--- 4375,4384 ----
      abort ();
  
!   if (TREE_CODE (type) == RECORD_TYPE)
!     field = TYPE_FIELDS (type);
  
!   if (TREE_CODE (type) == ARRAY_TYPE
!       && TYPE_DOMAIN (type) != 0)
!     min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
  
    /* As LINK goes through the elements of the constant,
*************** output_constructor (exp, size)
*** 4399,4413 ****
        tree index = 0;
  
!       /* the element in a union constructor specifies the proper field.  */
  
!       if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
! 	  || TREE_CODE (TREE_TYPE (exp)) == UNION_TYPE)
! 	{
! 	  /* if available, use the type given by link */
! 	  if (TREE_PURPOSE (link) != 0)
! 	    field = TREE_PURPOSE (link);
! 	}
! 
!       if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
  	index = TREE_PURPOSE (link);
  
--- 4399,4410 ----
        tree index = 0;
  
!       /* The element in a union constructor specifies the proper field
! 	 or index.  */
!       if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE
! 	   || TREE_CODE (type) == QUAL_UNION_TYPE)
! 	  && TREE_PURPOSE (link) != 0)
! 	field = TREE_PURPOSE (link);
  
!       else if (TREE_CODE (type) == ARRAY_TYPE)
  	index = TREE_PURPOSE (link);
  
*************** output_constructor (exp, size)
*** 4419,4426 ****
  	{
  	  register int fieldsize
! 	    = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp)));
! 	  HOST_WIDE_INT lo_index = TREE_INT_CST_LOW (TREE_OPERAND (index, 0));
! 	  HOST_WIDE_INT hi_index = TREE_INT_CST_LOW (TREE_OPERAND (index, 1));
  	  HOST_WIDE_INT index;
  	  for (index = lo_index; index <= hi_index; index++)
  	    {
--- 4416,4424 ----
  	{
  	  register int fieldsize
! 	    = int_size_in_bytes (TREE_TYPE (type));
! 	  HOST_WIDE_INT lo_index = tree_low_cst (TREE_OPERAND (index, 0), 0);
! 	  HOST_WIDE_INT hi_index = tree_low_cst (TREE_OPERAND (index, 1), 0);
  	  HOST_WIDE_INT index;
+ 
  	  for (index = lo_index; index <= hi_index; index++)
  	    {
*************** output_constructor (exp, size)
*** 4442,4451 ****
  	  /* Since this structure is static,
  	     we know the positions are constant.  */
! 	  HOST_WIDE_INT bitpos = field ? int_byte_position (field) : 0;
  
  	  if (index != 0)
! 	    bitpos
! 	      = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (val)), 1)
! 		* (tree_low_cst (index, 0) - min_index));
  
  	  /* Output any buffered-up bit-fields preceding this element.  */
--- 4440,4448 ----
  	  /* Since this structure is static,
  	     we know the positions are constant.  */
! 	  HOST_WIDE_INT pos = field ? int_byte_position (field) : 0;
  
  	  if (index != 0)
! 	    pos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (val)), 1)
! 		   * (tree_low_cst (index, 0) - tree_low_cst (min_index, 0)));
  
  	  /* Output any buffered-up bit-fields preceding this element.  */
*************** output_constructor (exp, size)
*** 4460,4488 ****
  	     Note no alignment needed in an array, since that is guaranteed
  	     if each element has the proper size.  */
! 	  if ((field != 0 || index != 0) && bitpos != total_bytes)
  	    {
! 	      assemble_zeros (bitpos - total_bytes);
! 	      total_bytes = bitpos;
  	    }
-           else if (field != 0 && DECL_PACKED (field))
-             {
-                /* Some assemblers automaticallly align a datum according to
-                   its size if no align directive is specified.  The datum,
-                   however, may be declared with 'packed' attribute, so we
-                   have to disable such a feature.  */
  
!                ASM_OUTPUT_ALIGN (asm_out_file, 0);
!             }
  
  	  /* Determine size this element should occupy.  */
  	  if (field)
! 	    {
! 	      if (TREE_CODE (DECL_SIZE_UNIT (field)) != INTEGER_CST)
! 		abort ();
! 
! 	      fieldsize = TREE_INT_CST_LOW (DECL_SIZE_UNIT (field));
! 	    }
  	  else
! 	    fieldsize = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp)));
  
  	  /* Output the element's initial value.  */
--- 4457,4478 ----
  	     Note no alignment needed in an array, since that is guaranteed
  	     if each element has the proper size.  */
! 	  if ((field != 0 || index != 0) && pos != total_bytes)
  	    {
! 	      assemble_zeros (pos - total_bytes);
! 	      total_bytes = pos;
  	    }
  
!           else if (field != 0 && DECL_PACKED (field))
! 	    /* Some assemblers automaticallly align a datum according to its
! 	       size if no align directive is specified.  The datum, however,
! 	       may be declared with 'packed' attribute, so we have to disable
! 	       such a feature.  */
! 	    ASM_OUTPUT_ALIGN (asm_out_file, 0);
  
  	  /* Determine size this element should occupy.  */
  	  if (field)
! 	    fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
  	  else
! 	    fieldsize = int_size_in_bytes (TREE_TYPE (type));
  
  	  /* Output the element's initial value.  */
*************** output_constructor (exp, size)
*** 4545,4550 ****
  	      int shift;
  	      HOST_WIDE_INT value;
! 	      int next_byte = next_offset / BITS_PER_UNIT;
! 	      int next_bit = next_offset % BITS_PER_UNIT;
  
  	      /* Advance from byte to byte
--- 4535,4540 ----
  	      int shift;
  	      HOST_WIDE_INT value;
! 	      HOST_WIDE_INT next_byte = next_offset / BITS_PER_UNIT;
! 	      HOST_WIDE_INT next_bit = next_offset % BITS_PER_UNIT;
  
  	      /* Advance from byte to byte
*************** output_constructor (exp, size)
*** 4567,4570 ****
--- 4557,4561 ----
  		     and put them into bytes from the most significant end.  */
  		  shift = end_offset - next_offset - this_time;
+ 
  		  /* Don't try to take a bunch of bits that cross
  		     the word boundary in the INTEGER_CST. We can
*************** output_constructor (exp, size)
*** 4580,4586 ****
  		  /* Now get the bits from the appropriate constant word.  */
  		  if (shift < HOST_BITS_PER_WIDE_INT)
! 		    {
! 		      value = TREE_INT_CST_LOW (val);
! 		    }
  		  else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
  		    {
--- 4571,4575 ----
  		  /* Now get the bits from the appropriate constant word.  */
  		  if (shift < HOST_BITS_PER_WIDE_INT)
! 		    value = TREE_INT_CST_LOW (val);
  		  else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
  		    {
*************** output_constructor (exp, size)
*** 4590,4593 ****
--- 4579,4583 ----
  		  else
  		    abort ();
+ 
  		  /* Get the result. This works only when:
  		     1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
*************** output_constructor (exp, size)
*** 4629,4632 ****
--- 4619,4623 ----
  			   << next_bit);
  		}
+ 
  	      next_offset += this_time;
  	      byte_buffer_in_use = 1;
*************** output_constructor (exp, size)
*** 4634,4637 ****
--- 4625,4629 ----
  	}
      }
+ 
    if (byte_buffer_in_use)
      {
*************** output_constructor (exp, size)
*** 4639,4642 ****
--- 4631,4635 ----
        total_bytes++;
      }
+ 
    if (total_bytes < size)
      assemble_zeros (size - total_bytes);


More information about the Gcc-patches mailing list