[PATCH] support static nested constructors in bitfields (1/2)

Olivier Hainque hainque@adacore.com
Mon Apr 27 10:36:00 GMT 2009


Hello,

This is a resubmission of a patch first suggested at

  http://gcc.gnu.org/ml/gcc-patches/2008-07/msg01802.html

The patch still applies. Just re-tested on x86_64-suse-linux, no new
regression. I'll be posting the followup part with tests etc shortly.

Thanks in advance,

Olivier

	2009-04-27  Olivier Hainque  <hainque@adacore.com>

	* varasm.c (oc_local_state): New structure, output_constructor
	local state to support communication with helpers.
	(output_constructor_array_range): New output_constructor helper,
	extracted code for an array range element.
	(output_constructor_regular_field): New output_constructor helper,
	extracted code for an element that is not a bitfield.
	(output_constructor_bitfield): New output_constructor helper,
	extracted code for a bitfield element.
	(output_constructor): Rework to use helpers.



-------------- next part --------------
*** gcc/varasm.c.ori	Tue Jun 10 17:59:09 2008
--- gcc/varasm.c	Tue Jun 10 18:00:49 2008
*************** array_size_for_constructor (tree val)
*** 4550,4555 ****
--- 4550,4837 ----
    return tree_low_cst (i, 1);
  }
  
+ /* Datastructures and helpers for output_constructor.  */
+ 
+ /* Local output_constructor state to support interaction with helpers.  */
+ 
+ typedef struct {
+ 
+   /* Received arguments.  */
+   tree exp;                     /* constructor expression.  */
+   unsigned HOST_WIDE_INT size;  /* # bytes to output - pad if necessary.  */
+   unsigned int align;           /* known initial alignment.  */
+ 
+   /* Constructor expression data.  */
+   tree type;       /* expression type.  */
+   tree field;      /* current field decl in a record.  */
+   tree min_index;  /* lower bound if specified for an array.  */
+ 
+   /* Output processing state per se.  */
+   HOST_WIDE_INT total_bytes;  /* # bytes output so far / current position.  */
+   int byte_buffer_in_use;     /* whether byte ...  */
+   int byte;                   /* ... contains part of a bitfield byte yet to
+ 			         be output.  */
+ 
+   /* Current element.  */
+   tree val;    /* current element value.  */
+   tree index;  /* current element index.  */
+ 
+ } oc_local_state;
+ 
+ static void output_constructor_array_range (oc_local_state *);
+ static void output_constructor_regular_field (oc_local_state *);
+ static void output_constructor_bitfield (oc_local_state *);
+ 
+ /* Helper for output_constructor.  Output a RANGE_EXPR element.  */
+ 
+ static void
+ output_constructor_array_range (oc_local_state *local)
+ {
+   unsigned HOST_WIDE_INT fieldsize
+     = int_size_in_bytes (TREE_TYPE (local->type));
+ 
+   HOST_WIDE_INT lo_index
+     = tree_low_cst (TREE_OPERAND (local->index, 0), 0);
+   HOST_WIDE_INT hi_index
+     = tree_low_cst (TREE_OPERAND (local->index, 1), 0);
+   HOST_WIDE_INT index;
+ 
+   unsigned int align2
+     = min_align (local->align, fieldsize * BITS_PER_UNIT);
+   
+   for (index = lo_index; index <= hi_index; index++)
+     {
+       /* Output the element's initial value.  */
+       if (local->val == 0)
+ 	assemble_zeros (fieldsize);
+       else
+ 	output_constant (local->val, fieldsize, align2);
+       
+       /* Count its size.  */
+       local->total_bytes += fieldsize;
+     }
+ }
+ 
+ /* Helper for output_constructor.  Output a field element that is not
+    bitfield.  */
+ 
+ static void
+ output_constructor_regular_field (oc_local_state *local)
+ {
+   /* Field size and position.  Since this structure is static, we know the
+      positions are constant.  */
+   unsigned HOST_WIDE_INT fieldsize;
+   HOST_WIDE_INT pos = local->field ? int_byte_position (local->field) : 0;
+ 
+   unsigned int align2;
+ 
+   if (local->index != 0)
+     pos = (tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (local->val)), 1)
+ 	   * ((tree_low_cst (local->index, 0) 
+ 	       - tree_low_cst (local->min_index, 0))));
+   
+   /* Output any buffered-up bit-fields preceding this element.  */
+   if (local->byte_buffer_in_use)
+     {
+       assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1);
+       local->total_bytes++;
+       local->byte_buffer_in_use = 0;
+     }
+   
+   /* Advance to offset of this element.
+      Note no alignment needed in an array, since that is guaranteed
+      if each element has the proper size.  */
+   if ((local->field != 0 || local->index != 0) && pos != local->total_bytes)
+     {
+       gcc_assert (pos >= local->total_bytes);
+       assemble_zeros (pos - local->total_bytes);
+       local->total_bytes = pos;
+     }
+   
+   /* Find the alignment of this element.  */
+   align2 = min_align (local->align, BITS_PER_UNIT * pos);
+ 
+   /* Determine size this element should occupy.  */
+   if (local->field)
+     {
+       fieldsize = 0;
+       
+       /* If this is an array with an unspecified upper bound,
+ 	 the initializer determines the size.  */
+       /* ??? This ought to only checked if DECL_SIZE_UNIT is NULL,
+ 	 but we cannot do this until the deprecated support for
+ 	 initializing zero-length array members is removed.  */
+       if (TREE_CODE (TREE_TYPE (local->field)) == ARRAY_TYPE
+ 	  && TYPE_DOMAIN (TREE_TYPE (local->field))
+ 	  && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (local->field))))
+ 	{
+ 	  fieldsize = array_size_for_constructor (local->val);
+ 	  /* Given a non-empty initialization, this field had
+ 	     better be last.  */
+ 	  gcc_assert (!fieldsize || !TREE_CHAIN (local->field));
+ 	}
+       else if (DECL_SIZE_UNIT (local->field))
+ 	{
+ 	  /* ??? This can't be right.  If the decl size overflows
+ 	     a host integer we will silently emit no data.  */
+ 	  if (host_integerp (DECL_SIZE_UNIT (local->field), 1))
+ 	    fieldsize = tree_low_cst (DECL_SIZE_UNIT (local->field), 1);
+ 	}
+     }
+   else
+     fieldsize = int_size_in_bytes (TREE_TYPE (local->type));
+   
+   /* Output the element's initial value.  */
+   if (local->val == 0)
+     assemble_zeros (fieldsize);
+   else
+     output_constant (local->val, fieldsize, align2);
+ 
+   /* Count its size.  */
+   local->total_bytes += fieldsize;
+ }
+ 
+ /* Helper for output_constructor.  Output a bitfield element.  */
+ 
+ static void
+ output_constructor_bitfield (oc_local_state *local)
+ {
+   /* Offset in bits from the beginning of the structure to the next bit of
+      this element to be processed.  */
+   HOST_WIDE_INT next_offset = int_bit_position (local->field);
+ 
+   /* Offset of the first bit past the end of this element.  */
+   HOST_WIDE_INT end_offset
+     = (next_offset + tree_low_cst (DECL_SIZE (local->field), 1));
+   
+   if (local->val != 0 && TREE_CODE (local->val) != INTEGER_CST)
+     error ("invalid initial value for member %qs",
+ 	   IDENTIFIER_POINTER (DECL_NAME (local->field)));
+ 
+   if (local->val == 0)
+     local->val = integer_zero_node;
+   
+   /* If this field does not start in this (or, next) byte,
+      skip some bytes.  */
+   if (next_offset / BITS_PER_UNIT != local->total_bytes)
+     {
+       /* Output remnant of any bit field in previous bytes.  */
+       if (local->byte_buffer_in_use)
+ 	{
+ 	  assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1);
+ 	  local->total_bytes++;
+ 	  local->byte_buffer_in_use = 0;
+ 	}
+       
+       /* If still not at proper byte, advance to there.  */
+       if (next_offset / BITS_PER_UNIT != local->total_bytes)
+ 	{
+ 	  gcc_assert (next_offset / BITS_PER_UNIT >= local->total_bytes);
+ 	  assemble_zeros (next_offset / BITS_PER_UNIT - local->total_bytes);
+ 	  local->total_bytes = next_offset / BITS_PER_UNIT;
+ 	}
+     }
+   
+   if (! local->byte_buffer_in_use)
+     local->byte = 0;
+   
+   /* We must split the element into pieces that fall within
+      separate bytes, and combine each byte with previous or
+      following bit-fields.  */
+   
+   while (next_offset < end_offset)
+     {
+       int this_time;
+       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
+ 	 within this element when necessary.  */
+       while (next_byte != local->total_bytes)
+ 	{
+ 	  assemble_integer (GEN_INT (local->byte), 1, BITS_PER_UNIT, 1);
+ 	  local->total_bytes++;
+ 	  local->byte = 0;
+ 	}
+       
+       /* Number of bits we can process at once
+ 	 (all part of the same byte).  */
+       this_time = MIN (end_offset - next_offset,
+ 		       BITS_PER_UNIT - next_bit);
+       if (BYTES_BIG_ENDIAN)
+ 	{
+ 	  /* On big-endian machine, take the most significant bits
+ 	     first (of the bits that are significant)
+ 	     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
+ 	     only select bits from the LOW or HIGH part
+ 	     not from both.  */
+ 	  if (shift < HOST_BITS_PER_WIDE_INT
+ 	      && shift + this_time > HOST_BITS_PER_WIDE_INT)
+ 	    {
+ 	      this_time = shift + this_time - HOST_BITS_PER_WIDE_INT;
+ 	      shift = HOST_BITS_PER_WIDE_INT;
+ 	    }
+ 	  
+ 	  /* Now get the bits from the appropriate constant word.  */
+ 	  if (shift < HOST_BITS_PER_WIDE_INT)
+ 	    value = TREE_INT_CST_LOW (local->val);
+ 	  else
+ 	    {
+ 	      gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
+ 	      value = TREE_INT_CST_HIGH (local->val);
+ 	      shift -= HOST_BITS_PER_WIDE_INT;
+ 	    }
+ 	  
+ 	  /* Get the result. This works only when:
+ 	     1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
+ 	  local->byte |= (((value >> shift)
+ 			   & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
+ 			  << (BITS_PER_UNIT - this_time - next_bit));
+ 	}
+       else
+ 	{
+ 	  /* On little-endian machines,
+ 	     take first the least significant bits of the value
+ 	     and pack them starting at the least significant
+ 	     bits of the bytes.  */
+ 	  shift = next_offset - int_bit_position (local->field);
+ 	  
+ 	  /* Don't try to take a bunch of bits that cross
+ 	     the word boundary in the INTEGER_CST. We can
+ 	     only select bits from the LOW or HIGH part
+ 	     not from both.  */
+ 	  if (shift < HOST_BITS_PER_WIDE_INT
+ 	      && shift + this_time > HOST_BITS_PER_WIDE_INT)
+ 	    this_time = (HOST_BITS_PER_WIDE_INT - shift);
+ 	  
+ 	  /* Now get the bits from the appropriate constant word.  */
+ 	  if (shift < HOST_BITS_PER_WIDE_INT)
+ 	    value = TREE_INT_CST_LOW (local->val);
+ 	  else
+ 	    {
+ 	      gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
+ 	      value = TREE_INT_CST_HIGH (local->val);
+ 	      shift -= HOST_BITS_PER_WIDE_INT;
+ 	    }
+ 	  
+ 	  /* Get the result. This works only when:
+ 	     1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
+ 	  local->byte |= (((value >> shift)
+ 			   & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
+ 			  << next_bit);
+ 	}
+       
+       next_offset += this_time;
+       local->byte_buffer_in_use = 1;
+     }
+ }
+ 
  /* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants).
     Generate at least SIZE bytes, padding if necessary.  */
  
*************** static void
*** 4557,4865 ****
  output_constructor (tree exp, unsigned HOST_WIDE_INT size,
  		    unsigned int align)
  {
-   tree type = TREE_TYPE (exp);
-   tree 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;
-   /* Nonzero means BYTE contains part of a byte, to be output.  */
-   int byte_buffer_in_use = 0;
-   int byte = 0;
    unsigned HOST_WIDE_INT cnt;
    constructor_elt *ce;
  
!   gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
  
!   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,
!      FIELD goes through the structure fields, if the constant is a structure.
!      if the constant is a union, then we override this,
!      by getting the field from the TREE_LIST element.
       But the constant could also be an array.  Then FIELD is zero.
  
       There is always a maximum of one element in the chain LINK for unions
       (even if the initializer in a source program incorrectly contains
       more one).  */
    for (cnt = 0;
         VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), cnt, ce);
!        cnt++, field = field ? TREE_CHAIN (field) : 0)
      {
!       tree val = ce->value;
!       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)
  	  && ce->index != 0)
! 	field = ce->index;
  
!       else if (TREE_CODE (type) == ARRAY_TYPE)
! 	index = ce->index;
  
  #ifdef ASM_COMMENT_START
!       if (field && flag_verbose_asm)
  	fprintf (asm_out_file, "%s %s:\n",
  		 ASM_COMMENT_START,
! 		 DECL_NAME (field)
! 		 ? IDENTIFIER_POINTER (DECL_NAME (field))
  		 : "<anonymous>");
  #endif
  
        /* Eliminate the marker that makes a cast not be an lvalue.  */
!       if (val != 0)
! 	STRIP_NOPS (val);
  
!       if (index && TREE_CODE (index) == RANGE_EXPR)
! 	{
! 	  unsigned HOST_WIDE_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;
! 	  unsigned int align2 = min_align (align, fieldsize * BITS_PER_UNIT);
! 
! 	  for (index = lo_index; index <= hi_index; index++)
! 	    {
! 	      /* Output the element's initial value.  */
! 	      if (val == 0)
! 		assemble_zeros (fieldsize);
! 	      else
! 		output_constant (val, fieldsize, align2);
! 
! 	      /* Count its size.  */
! 	      total_bytes += fieldsize;
! 	    }
! 	}
!       else if (field == 0 || !DECL_BIT_FIELD (field))
! 	{
! 	  /* An element that is not a bit-field.  */
! 
! 	  unsigned HOST_WIDE_INT fieldsize;
! 	  /* Since this structure is static,
! 	     we know the positions are constant.  */
! 	  HOST_WIDE_INT pos = field ? int_byte_position (field) : 0;
! 	  unsigned int align2;
! 
! 	  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.  */
! 	  if (byte_buffer_in_use)
! 	    {
! 	      assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
! 	      total_bytes++;
! 	      byte_buffer_in_use = 0;
! 	    }
! 
! 	  /* Advance to offset of this element.
! 	     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)
! 	    {
! 	      gcc_assert (pos >= total_bytes);
! 	      assemble_zeros (pos - total_bytes);
! 	      total_bytes = pos;
! 	    }
! 
! 	  /* Find the alignment of this element.  */
! 	  align2 = min_align (align, BITS_PER_UNIT * pos);
  
! 	  /* Determine size this element should occupy.  */
! 	  if (field)
! 	    {
! 	      fieldsize = 0;
! 
! 	      /* If this is an array with an unspecified upper bound,
! 		 the initializer determines the size.  */
! 	      /* ??? This ought to only checked if DECL_SIZE_UNIT is NULL,
! 		 but we cannot do this until the deprecated support for
! 		 initializing zero-length array members is removed.  */
! 	      if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
! 		  && TYPE_DOMAIN (TREE_TYPE (field))
! 		  && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
! 		{
! 		  fieldsize = array_size_for_constructor (val);
! 		  /* Given a non-empty initialization, this field had
! 		     better be last.  */
! 		  gcc_assert (!fieldsize || !TREE_CHAIN (field));
! 		}
! 	      else if (DECL_SIZE_UNIT (field))
! 		{
! 		  /* ??? This can't be right.  If the decl size overflows
! 		     a host integer we will silently emit no data.  */
! 		  if (host_integerp (DECL_SIZE_UNIT (field), 1))
! 		    fieldsize = tree_low_cst (DECL_SIZE_UNIT (field), 1);
! 		}
! 	    }
! 	  else
! 	    fieldsize = int_size_in_bytes (TREE_TYPE (type));
  
! 	  /* Output the element's initial value.  */
! 	  if (val == 0)
! 	    assemble_zeros (fieldsize);
! 	  else
! 	    output_constant (val, fieldsize, align2);
  
! 	  /* Count its size.  */
! 	  total_bytes += fieldsize;
! 	}
!       else if (val != 0 && TREE_CODE (val) != INTEGER_CST)
! 	error ("invalid initial value for member %qs",
! 	       IDENTIFIER_POINTER (DECL_NAME (field)));
        else
! 	{
! 	  /* Element that is a bit-field.  */
! 
! 	  HOST_WIDE_INT next_offset = int_bit_position (field);
! 	  HOST_WIDE_INT end_offset
! 	    = (next_offset + tree_low_cst (DECL_SIZE (field), 1));
! 
! 	  if (val == 0)
! 	    val = integer_zero_node;
! 
! 	  /* If this field does not start in this (or, next) byte,
! 	     skip some bytes.  */
! 	  if (next_offset / BITS_PER_UNIT != total_bytes)
! 	    {
! 	      /* Output remnant of any bit field in previous bytes.  */
! 	      if (byte_buffer_in_use)
! 		{
! 		  assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
! 		  total_bytes++;
! 		  byte_buffer_in_use = 0;
! 		}
! 
! 	      /* If still not at proper byte, advance to there.  */
! 	      if (next_offset / BITS_PER_UNIT != total_bytes)
! 		{
! 		  gcc_assert (next_offset / BITS_PER_UNIT >= total_bytes);
! 		  assemble_zeros (next_offset / BITS_PER_UNIT - total_bytes);
! 		  total_bytes = next_offset / BITS_PER_UNIT;
! 		}
! 	    }
! 
! 	  if (! byte_buffer_in_use)
! 	    byte = 0;
! 
! 	  /* We must split the element into pieces that fall within
! 	     separate bytes, and combine each byte with previous or
! 	     following bit-fields.  */
! 
! 	  /* next_offset is the offset n fbits from the beginning of
! 	     the structure to the next bit of this element to be processed.
! 	     end_offset is the offset of the first bit past the end of
! 	     this element.  */
! 	  while (next_offset < end_offset)
! 	    {
! 	      int this_time;
! 	      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
! 		 within this element when necessary.  */
! 	      while (next_byte != total_bytes)
! 		{
! 		  assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
! 		  total_bytes++;
! 		  byte = 0;
! 		}
! 
! 	      /* Number of bits we can process at once
! 		 (all part of the same byte).  */
! 	      this_time = MIN (end_offset - next_offset,
! 			       BITS_PER_UNIT - next_bit);
! 	      if (BYTES_BIG_ENDIAN)
! 		{
! 		  /* On big-endian machine, take the most significant bits
! 		     first (of the bits that are significant)
! 		     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
! 		     only select bits from the LOW or HIGH part
! 		     not from both.  */
! 		  if (shift < HOST_BITS_PER_WIDE_INT
! 		      && shift + this_time > HOST_BITS_PER_WIDE_INT)
! 		    {
! 		      this_time = shift + this_time - HOST_BITS_PER_WIDE_INT;
! 		      shift = HOST_BITS_PER_WIDE_INT;
! 		    }
! 
! 		  /* Now get the bits from the appropriate constant word.  */
! 		  if (shift < HOST_BITS_PER_WIDE_INT)
! 		    value = TREE_INT_CST_LOW (val);
! 		  else
! 		    {
! 		      gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
! 		      value = TREE_INT_CST_HIGH (val);
! 		      shift -= HOST_BITS_PER_WIDE_INT;
! 		    }
! 
! 		  /* Get the result. This works only when:
! 		     1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
! 		  byte |= (((value >> shift)
! 			    & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
! 			   << (BITS_PER_UNIT - this_time - next_bit));
! 		}
! 	      else
! 		{
! 		  /* On little-endian machines,
! 		     take first the least significant bits of the value
! 		     and pack them starting at the least significant
! 		     bits of the bytes.  */
! 		  shift = next_offset - int_bit_position (field);
! 
! 		  /* Don't try to take a bunch of bits that cross
! 		     the word boundary in the INTEGER_CST. We can
! 		     only select bits from the LOW or HIGH part
! 		     not from both.  */
! 		  if (shift < HOST_BITS_PER_WIDE_INT
! 		      && shift + this_time > HOST_BITS_PER_WIDE_INT)
! 		    this_time = (HOST_BITS_PER_WIDE_INT - shift);
! 
! 		  /* Now get the bits from the appropriate constant word.  */
! 		  if (shift < HOST_BITS_PER_WIDE_INT)
! 		    value = TREE_INT_CST_LOW (val);
! 		  else
! 		    {
! 		      gcc_assert (shift < 2 * HOST_BITS_PER_WIDE_INT);
! 		      value = TREE_INT_CST_HIGH (val);
! 		      shift -= HOST_BITS_PER_WIDE_INT;
! 		    }
! 
! 		  /* Get the result. This works only when:
! 		     1 <= this_time <= HOST_BITS_PER_WIDE_INT.  */
! 		  byte |= (((value >> shift)
! 			    & (((HOST_WIDE_INT) 2 << (this_time - 1)) - 1))
! 			   << next_bit);
! 		}
! 
! 	      next_offset += this_time;
! 	      byte_buffer_in_use = 1;
! 	    }
! 	}
      }
  
!   if (byte_buffer_in_use)
      {
!       assemble_integer (GEN_INT (byte), 1, BITS_PER_UNIT, 1);
!       total_bytes++;
      }
  
!   if ((unsigned HOST_WIDE_INT)total_bytes < size)
!     assemble_zeros (size - total_bytes);
  }
  
  /* This TREE_LIST contains any weak symbol declarations waiting
--- 4839,4934 ----
  output_constructor (tree exp, unsigned HOST_WIDE_INT size,
  		    unsigned int align)
  {
    unsigned HOST_WIDE_INT cnt;
    constructor_elt *ce;
  
!   oc_local_state local;
  
!   /* Setup our local state to communicate with helpers.  */
!   local.exp = exp;
!   local.size = size;
!   local.align = align;
! 
!   local.total_bytes = 0;
!   local.byte_buffer_in_use = 0;
!   local.byte = 0;
! 
!   local.type = TREE_TYPE (exp);
! 
!   local.min_index = 0;
!   if (TREE_CODE (local.type) == ARRAY_TYPE
!       && TYPE_DOMAIN (local.type) != 0)
!     local.min_index = TYPE_MIN_VALUE (TYPE_DOMAIN (local.type));
!   
!   gcc_assert (HOST_BITS_PER_WIDE_INT >= BITS_PER_UNIT);
  
!   /* As CE goes through the elements of the constant, FIELD goes through the
!      structure fields if the constant is a structure.  If the constant is a
!      union, we override this by getting the field from the TREE_LIST element.
       But the constant could also be an array.  Then FIELD is zero.
  
       There is always a maximum of one element in the chain LINK for unions
       (even if the initializer in a source program incorrectly contains
       more one).  */
+ 
+   local.field = 0;
+   if (TREE_CODE (local.type) == RECORD_TYPE)
+     local.field = TYPE_FIELDS (local.type);
+ 
    for (cnt = 0;
         VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (exp), cnt, ce);
!        cnt++, local.field = local.field ? TREE_CHAIN (local.field) : 0)
      {
!       local.val = ce->value;
!       local.index = 0;
  
        /* The element in a union constructor specifies the proper field
  	 or index.  */
!       if ((TREE_CODE (local.type) == RECORD_TYPE
! 	   || TREE_CODE (local.type) == UNION_TYPE
! 	   || TREE_CODE (local.type) == QUAL_UNION_TYPE)
  	  && ce->index != 0)
! 	local.field = ce->index;
  
!       else if (TREE_CODE (local.type) == ARRAY_TYPE)
! 	local.index = ce->index;
  
  #ifdef ASM_COMMENT_START
!       if (local.field && flag_verbose_asm)
  	fprintf (asm_out_file, "%s %s:\n",
  		 ASM_COMMENT_START,
! 		 DECL_NAME (local.field)
! 		 ? IDENTIFIER_POINTER (DECL_NAME (local.field))
  		 : "<anonymous>");
  #endif
  
        /* Eliminate the marker that makes a cast not be an lvalue.  */
!       if (local.val != 0)
! 	STRIP_NOPS (local.val);
  
!       /* Output the current element, using the appropriate helper ...  */
  
!       /* For an array slice.  */
!       if (local.index && TREE_CODE (local.index) == RANGE_EXPR)
! 	output_constructor_array_range (&local);
  
!       /* For a field that is not a bitfield.  */
!       else if (local.field == 0 || !DECL_BIT_FIELD (local.field))
! 	output_constructor_regular_field (&local);
  
!       /* For a bitfield.  */
        else
! 	output_constructor_bitfield (&local);
      }
  
!   if (local.byte_buffer_in_use)
      {
!       assemble_integer (GEN_INT (local.byte), 1, BITS_PER_UNIT, 1);
!       local.total_bytes++;
      }
  
!   if ((unsigned HOST_WIDE_INT)local.total_bytes < size)
!     assemble_zeros (size - local.total_bytes);
  }
  
  /* This TREE_LIST contains any weak symbol declarations waiting


More information about the Gcc-patches mailing list