diff options
Diffstat (limited to 'gcc/stor-layout.c')
| -rw-r--r-- | gcc/stor-layout.c | 113 | 
1 files changed, 92 insertions, 21 deletions
| diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c index 41d316543e7..cffb81c7f62 100644 --- a/gcc/stor-layout.c +++ b/gcc/stor-layout.c @@ -634,9 +634,9 @@ rli_size_so_far (record_layout_info rli)  }  /* FIELD is about to be added to RLI->T.  The alignment (in bits) of -   the next available location is given by KNOWN_ALIGN.  Update the -   variable alignment fields in RLI, and return the alignment to give -   the FIELD.  */ +   the next available location within the record is given by KNOWN_ALIGN. +   Update the variable alignment fields in RLI, and return the alignment +   to give the FIELD.  */  unsigned int  update_alignment_for_field (record_layout_info rli, tree field, @@ -682,6 +682,18 @@ update_alignment_for_field (record_layout_info rli, tree field,  	    type_align = MIN (type_align, maximum_field_alignment);  	  rli->record_align = MAX (rli->record_align, type_align);  	  rli->unpacked_align = MAX (rli->unpacked_align, TYPE_ALIGN (type)); +	  /* If we start a new run, make sure we start it properly aligned.  */ +	  if ((!rli->prev_field +	       || integer_zerop (DECL_SIZE (field)) +	       || integer_zerop (DECL_SIZE (rli->prev_field)) +	       || !host_integerp (DECL_SIZE (rli->prev_field), 0) +	       || !host_integerp (TYPE_SIZE (type), 0) +	       || !simple_cst_equal (TYPE_SIZE (type), +				     TYPE_SIZE (TREE_TYPE (rli->prev_field))) +	       || (rli->remaining_in_alignment +		   < tree_low_cst (DECL_SIZE (field), 0))) +	      && desired_align < type_align) +	    desired_align = type_align;  	}      }  #ifdef PCC_BITFIELD_TYPE_MATTERS @@ -820,7 +832,7 @@ place_field (record_layout_info rli, tree field)      known_align = (tree_low_cst (rli->bitpos, 1)  		   & - tree_low_cst (rli->bitpos, 1));    else if (integer_zerop (rli->offset)) -    known_align = BIGGEST_ALIGNMENT; +    known_align = 0;    else if (host_integerp (rli->offset, 1))      known_align = (BITS_PER_UNIT  		   * (tree_low_cst (rli->offset, 1) @@ -829,6 +841,8 @@ place_field (record_layout_info rli, tree field)      known_align = rli->offset_align;    desired_align = update_alignment_for_field (rli, field, known_align); +  if (known_align == 0) +    known_align = MAX (BIGGEST_ALIGNMENT, rli->record_align);    if (warn_packed && DECL_PACKED (field))      { @@ -1001,18 +1015,30 @@ place_field (record_layout_info rli, tree field)  	      if (rli->remaining_in_alignment < bitsize)  		{ -		  /* out of bits; bump up to next 'word'.  */ -		  rli->offset = DECL_FIELD_OFFSET (rli->prev_field); -		  rli->bitpos -		    = size_binop (PLUS_EXPR, TYPE_SIZE (type), -				  DECL_FIELD_BIT_OFFSET (rli->prev_field)); -		  rli->prev_field = field; -		  rli->remaining_in_alignment -		    = tree_low_cst (TYPE_SIZE (type), 0); +		  /* If PREV_FIELD is packed, and we haven't lumped +		     non-packed bitfields with it, treat this as if PREV_FIELD +		     was not a bitfield.  This avoids anomalies where a packed +		     bitfield with long long base type can take up more +		     space than a same-size bitfield with base type short.  */ +		  if (rli->prev_packed) +		    rli->prev_field = prev_saved = NULL; +		  else +		    { +		      /* out of bits; bump up to next 'word'.  */ +		      rli->offset = DECL_FIELD_OFFSET (rli->prev_field); +		      rli->bitpos +			= size_binop (PLUS_EXPR, TYPE_SIZE (type), +				      DECL_FIELD_BIT_OFFSET (rli->prev_field)); +		      rli->prev_field = field; +		      rli->remaining_in_alignment +			= tree_low_cst (TYPE_SIZE (type), 0) - bitsize; +		    }  		} - -	      rli->remaining_in_alignment -= bitsize; +	      else +		rli->remaining_in_alignment -= bitsize;  	    } +	  else if (rli->prev_packed) +	    rli->prev_field = prev_saved = NULL;  	  else  	    {  	      /* End of a run: if leaving a run of bitfields of the same type @@ -1028,9 +1054,14 @@ place_field (record_layout_info rli, tree field)  		{  		  tree type_size = TYPE_SIZE (TREE_TYPE (rli->prev_field)); -		  rli->bitpos -		    = size_binop (PLUS_EXPR, type_size, -				  DECL_FIELD_BIT_OFFSET (rli->prev_field)); +		  /* If the desired alignment is greater or equal to TYPE_SIZE, +		     we have already adjusted rli->bitpos / rli->offset above. +		   */ +		  if ((unsigned HOST_WIDE_INT) tree_low_cst (type_size, 0) +		      > desired_align) +		    rli->bitpos +		      = size_binop (PLUS_EXPR, type_size, +				    DECL_FIELD_BIT_OFFSET (rli->prev_field));  		}  	      else  		/* We "use up" size zero fields; the code below should behave @@ -1044,6 +1075,7 @@ place_field (record_layout_info rli, tree field)  		rli->prev_field = NULL;  	    } +	  rli->prev_packed = 0;  	  normalize_rli (rli);          } @@ -1116,20 +1148,59 @@ place_field (record_layout_info rli, tree field)      actual_align = (tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)  		    & - tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1));    else if (integer_zerop (DECL_FIELD_OFFSET (field))) -    actual_align = BIGGEST_ALIGNMENT; +    actual_align = MAX (BIGGEST_ALIGNMENT, rli->record_align);    else if (host_integerp (DECL_FIELD_OFFSET (field), 1))      actual_align = (BITS_PER_UNIT  		   * (tree_low_cst (DECL_FIELD_OFFSET (field), 1)  		      & - tree_low_cst (DECL_FIELD_OFFSET (field), 1)));    else      actual_align = DECL_OFFSET_ALIGN (field); +  /* ACTUAL_ALIGN is still the actual alignment *within the record* . +     store / extract bit field operations will check the alignment of the +     record against the mode of bit fields.  */    if (known_align != actual_align)      layout_decl (field, actual_align); -  /* Only the MS bitfields use this.  */ -  if (rli->prev_field == NULL && DECL_BIT_FIELD_TYPE(field)) -      rli->prev_field = field; +  if (DECL_BIT_FIELD_TYPE (field)) +    { +      unsigned int type_align = TYPE_ALIGN (type); + +      /* Only the MS bitfields use this.  We used to also put any kind of +	 packed bit fields into prev_field, but that makes no sense, because +	 an 8 bit packed bit field shouldn't impose more restriction on +	 following fields than a char field, and the alignment requirements +	 are also not fulfilled. +	 There is no sane value to set rli->remaining_in_alignment to when +	 a packed bitfield in prev_field is unaligned.  */ +      if (maximum_field_alignment != 0) +	type_align = MIN (type_align, maximum_field_alignment); +      gcc_assert (rli->prev_field +		  || actual_align >= type_align || DECL_PACKED (field) +		  || integer_zerop (DECL_SIZE (field)) +		  || !targetm.ms_bitfield_layout_p (rli->t)); +      if (rli->prev_field == NULL && actual_align >= type_align +	  && !integer_zerop (DECL_SIZE (field))) +	{ +	  rli->prev_field = field; +	  /* rli->remaining_in_alignment has not been set if the bitfield +	     has size zero, or if it is a packed bitfield.  */ +	  rli->remaining_in_alignment +	    = (tree_low_cst (TYPE_SIZE (TREE_TYPE (field)), 0) +	       - tree_low_cst (DECL_SIZE (field), 0)); +	  rli->prev_packed = DECL_PACKED (field); + +	} +      else if (rli->prev_field && DECL_PACKED (field)) +	{ +	  HOST_WIDE_INT bitsize = tree_low_cst (DECL_SIZE (field), 0); + +	  if (rli->remaining_in_alignment < bitsize) +	    rli->prev_field = NULL; +	  else +	    rli->remaining_in_alignment -= bitsize; +	} +    }    /* Now add size of this field to the size of the record.  If the size is       not constant, treat the field as being a multiple of bytes and just | 

