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]

Patch to enhance #pragma pack support


Hi Guys,

  I would like to submit the enclosed patch for approval.  The patch
enhances GCC's ability to handle #pragma pack, so that it now
understands the full M$oft syntax for the pragma.  This patch was
originally submitted by <jeffdb@goodnet.com> but I have reworked it in
order to fit in with the current EGCS sources.

Cheers
	Nick

Tue Apr 13 13:18:02 1999  Nick Clifton  <nickc@cygnus.com>

	This patch is based  on a patch originally created by
	<jeffdb@goodnet.com>

	* varasm.c.c (get_maximum_field_alignment): New function.
	(set_maximum_field_alignment): New function.  Record the
	maximum alignment value for structure fields.

	* toplev.c (main): Implement new command line switch
        -falign-structs=<n>.
	(display_help): Document new command line switch.

	* invoke.texi: Document new command line switch.

	* c-pragma.h: Provide prototypes for
	get_maximum_field_alignment and
	set_maximum_field_alignment.

	* c-pragma.c (push_alignment): New parameter 'identifier'.
	This value is recorded in the alignment stack so that a
	future pop can unwind back to this level.
	(POP_AN_ENTRY): New macro to pop one entry in the alignment
	stack.
	(pop_alignment): New parameters 'alignment' and 'identifier'.
	If identifier is non NULL then the alignment stack is popped
	back to the matching level.  If alignment is not zero, then
	this value is used as the new alignmnent value after the
	popping has been completed.
	(pragma_strdup): New function: Duplicate a string.
	(handle_pragma_token): Handled extended MS syntax for #pragma
	pack.

Index: varasm.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/varasm.c,v
retrieving revision 1.57
diff -p -w -r1.57 varasm.c
*** varasm.c	1999/03/28 15:35:04	1.57
--- varasm.c	1999/04/14 21:12:35
*************** make_decl_one_only (decl)
*** 4419,4421 ****
--- 4419,4458 ----
    else
      abort ();
  }
+ 
+ /* What maximum_field_alignment would be if alignments greater than 4 were allowed.  */
+ static int real_maximum_field_alignment;
+ 
+ int
+ get_maximum_field_alignment ()
+ {
+   return real_maximum_field_alignment;
+ }
+ 
+ void
+ set_maximum_field_alignment (alignment)
+      int alignment;
+ {
+   switch (alignment)
+     {
+     case 0:
+     case 1:
+     case 2:
+     case 4:
+     case 8:
+     case 16:
+       break;
+     default:
+       warning ("Field alignment must be a small power of two, not %d",
+                alignment);
+       alignment = 8;
+     }
+ 
+   real_maximum_field_alignment = alignment;
+   
+   if (alignment < 8)
+     maximum_field_alignment = alignment * 8;
+   else
+     /* MSVC ignores alignments > 4.  */
+     maximum_field_alignment = 0;
+ }

Index: toplev.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/toplev.c,v
retrieving revision 1.174
diff -p -w -r1.174 toplev.c
*** toplev.c	1999/04/10 22:53:08	1.174
--- toplev.c	1999/04/14 21:12:48
*************** display_help ()
*** 4425,4430 ****
--- 4425,4431 ----
    printf ("  -ffixed-<register>      Mark <register> as being unavailable to the compiler\n");
    printf ("  -fcall-used-<register>  Mark <register> as being corrupted by function calls\n");
    printf ("  -fcall-saved-<register> Mark <register> as being preserved across functions\n");
+   printf ("  -falign-structs=<n>     Set maximum structure alignment to <n> bytes\n");
  
    for (i = NUM_ELEM (f_options); i--;)
      {
*************** main (argc, argv)
*** 5011,5016 ****
--- 5012,5019 ----
  		fix_register (&p[10], 0, 1);
  	      else if (!strncmp (p, "call-saved-", 11))
  		fix_register (&p[11], 0, 0);
+ 	      else if (!strncmp (p, "align-structs=", 14))
+ 		set_maximum_field_alignment (atoi (p + 14));
  	      else
  		error ("Invalid option `%s'", argv[i]);
  	    }

Index: invoke.texi
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/invoke.texi,v
retrieving revision 1.106
diff -p -w -r1.106 invoke.texi
*** invoke.texi	1999/04/14 05:34:37	1.106
--- invoke.texi	1999/04/14 21:25:54
*************** in the following sections.
*** 418,423 ****
--- 418,424 ----
  -fargument-alias  -fargument-noalias
  -fargument-noalias-global
  -fleading-underscore
+ -falign-structs
  @end smallexample
  @end table
  
*************** three-way choice.
*** 6096,6101 ****
--- 6097,6110 ----
  Pack all structure members together without holes.  Usually you would
  not want to use this option, since it makes the code suboptimal, and
  the offsets of structure members won't agree with system libraries.
+ 
+ @item -falign-structs=<n>
+ Set the maximum structure packing value to @samp{<n>} bytes.  If this
+ value is 0 then no maximum will be set, otherwise if alignment rules
+ and/or command line switches would normally force a field in a structure
+ to have an alignment greater than the value set by this command line
+ option, that alignment will be ignored and that value set here used
+ instead.  Permissable values for @samp{<n>} are: 0, 1,2,4,8 or 16.
  
  @item -fcheck-memory-usage
  Generate extra code to check each memory access.  GNU CC will generate

Index: c-pragma.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-pragma.h,v
retrieving revision 1.8
diff -p -w -r1.8 c-pragma.h
*** c-pragma.h	1999/02/26 01:29:20	1.8
--- c-pragma.h	1999/04/14 21:13:07
*************** enum pragma_state
*** 99,102 ****
--- 98,107 ----
  extern int handle_pragma_token PROTO((const char *, tree));
  
  #endif /* HANDLE_GENERIC_PRAGMAS */
+ 
+ /* Actually defined in varasm.c, since they need to be visible even when not
+    using pragmas.  */
+ extern int get_maximum_field_alignment PROTO ((void));
+ extern void set_maximum_field_alignment PROTO ((int));
+ 
  #endif /* _C_PRAGMA_H */

Index: c-pragma.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-pragma.c,v
retrieving revision 1.15
diff -p -w -r1.15 c-pragma.c
*** c-pragma.c	1999/02/26 01:29:19	1.15
--- c-pragma.c	1999/04/14 21:13:19
*************** Boston, MA 02111-1307, USA.  */
*** 35,136 ****
  /* When structure field packing is in effect, this variable is the
     number of bits to use as the maximum alignment.  When packing is not
     in effect, this is zero.  */
- 
  extern int maximum_field_alignment;
  #endif
  
- 
  #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
  typedef struct align_stack
  {
    int                  alignment;
!   unsigned int         num_pushes;
    struct align_stack * prev;
! } align_stack;
  
  static struct align_stack * alignment_stack = NULL;
  
! static int  push_alignment PROTO((int));
! static int  pop_alignment  PROTO((void));
  
! /* Push an alignment value onto the stack.  */
  static int
! push_alignment (alignment)
       int alignment;
! {
!   switch (alignment)
!     {
!     case 0:
!     case 1:
!     case 2:
!     case 4:
!     case 8:
!     case 16:
!       break;
!     default:
!       warning ("\
! Alignment must be a small power of two, not %d, in #pragma pack",
! 	       alignment);
!       return 0;
!     }
!   
!   if (alignment_stack == NULL
!       || alignment_stack->alignment != alignment)
      {
        align_stack * entry;
  
        entry = (align_stack *) xmalloc (sizeof (* entry));
  
!       if (entry == NULL)
  	{
  	  warning ("Out of memory pushing #pragma pack");
  	  return 0;
  	}
  
!       entry->alignment  = alignment;
!       entry->num_pushes = 1;
        entry->prev       = alignment_stack;
        
        alignment_stack = entry;
  
!       if (alignment < 8)
! 	maximum_field_alignment = alignment * 8;
!       else
! 	/* MSVC ignores alignments > 4.  */
! 	maximum_field_alignment = 0;
!     }
!   else
!     alignment_stack->num_pushes ++;
  
    return 1;
  }
  
! /* Undo a push of an alignment onto the stack.  */
  static int
! pop_alignment ()
  {
    if (alignment_stack == NULL)
      {
        warning ("\
  #pragma pack(pop) encountered without corresponding #pragma pack(push,<n>)");
        return 0;
      }
  
!   if (-- alignment_stack->num_pushes == 0)
      {
!       align_stack * entry;
        
!       entry = alignment_stack->prev;
  
!       if (entry == NULL || entry->alignment > 4)
! 	maximum_field_alignment = 0;
!       else
! 	maximum_field_alignment = entry->alignment * 8;
  
!       free (alignment_stack);
  
!       alignment_stack = entry;
      }
  
    return 1;
  }
--- 35,180 ----
  /* When structure field packing is in effect, this variable is the
     number of bits to use as the maximum alignment.  When packing is not
     in effect, this is zero.  */
  extern int maximum_field_alignment;
  #endif
  
  #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
+ 
+ /* The following code is designed to handle the Microsoft syntax for #pragma pack.
+    That syntax is (approximately):
+ 
+      #pragma pack( [ {push | pop} [, identifier ] ] [, n ] )
+ 
+   ie:
+      #pragma pack (push)
+                   (push, 4)
+ 		  (push, id)
+ 		  (push, id, 4) 
+                   (pop)
+ 		  (pop, 4)
+ 		  (pop, id)
+ 		  (pop, id, 4)
+                   (4)
+                   ()
+ */
+    
  typedef struct align_stack
  {
    int                  alignment;
!   char *               ident;
    struct align_stack * prev;
! }
! align_stack;
  
  static struct align_stack * alignment_stack = NULL;
+ 
+ static int  push_alignment PROTO ((int, char *));
+ static int  pop_alignment  PROTO ((int, char *));
  
! /* Set alignment value without changing the stack level.  */
  
! /* Push an alignment value onto the stack. 
!    If ALIGNMENT is 0 then create a new stack entry with the current packing
!    level, otherwise push the current packing level onto the stack, and reset
!    the packing level to the value of alignment.  IDENTIFIER is the string that
!    caused us to call this function.  It is recorded so that a pop can unwind
!    the stack back to the place where a specific packing level was set.  */
  static int
! push_alignment (alignment, identifier)
       int alignment;
!      char * identifier;
      {
        align_stack * entry;
  
        entry = (align_stack *) xmalloc (sizeof (* entry));
  
!   if (entry == 0)
  	{
  	  warning ("Out of memory pushing #pragma pack");
  	  return 0;
  	}
  
!   entry->alignment = get_maximum_field_alignment ();
!   entry->ident     = identifier; /* May be NULL */
        entry->prev       = alignment_stack;
        
        alignment_stack = entry;
  
!   if (alignment != 0) /* Don't just push change, make it take affect right away.  */
!     set_maximum_field_alignment (alignment);
  
    return 1;
  }
  
! #define POP_AN_ENTRY				\
!   {						\
!     align_stack * entry;			\
! 						\
!     if (alignment_stack->ident != NULL)		\
!       free (alignment_stack->ident);		\
! 						\
!     entry = alignment_stack->prev;		\
!     free (alignment_stack);			\
!     alignment_stack = entry;			\
!   }
! 
! /* Undo a push of an alignment onto the stack. 
!    An ALIGNMENT of 0 means just pop the last stack entry and assign it's alignment
!    to the current packing level, otherwise pop the last stack entry but override
!    its packing level with the value of alignment.
!    If IDENTIFIER is not NULL then pop back to the stack entry with that identifier
!    rather than just popping back one level.  */
  static int
! pop_alignment (alignment, identifier)
!      int alignment;
!      char * identifier;
  {
    if (alignment_stack == NULL)
      {
+       /* Not sure if vc++ handles it this way, but hopefully the affected header
+ 	 will work correctly */
+       if (alignment != 0)
+ 	set_maximum_field_alignment (alignment);
+       
        warning ("\
  #pragma pack(pop) encountered without corresponding #pragma pack(push,<n>)");
        return 0;
      }
  
!   if (identifier != NULL)
      {
!       align_stack * search;
        
!       search = alignment_stack;
  
!       while (search != NULL)
! 	{
! 	  /* Scan entries until identifier is found. */
! 	  if (search->ident != NULL &&
! 	      strcmp (identifier, search->ident) == 0)
! 	    break;
  
! 	  search = search->prev;
! 	}
  
!       if (search == NULL)
! 	/* No matching identifier was found. */
! 	warning ("\
! #pragma pack(pop, %s) encountered without corresponding \n#pragma pack(push, %s)",
!                  identifier, identifier);
!       else
! 	{
! 	  /* Pop back to just above the entry we found.  */
! 	  while (alignment_stack != search)
! 	    POP_AN_ENTRY
      }
+     }
+ 
+   /* Set the alignment to what it was prior to the push.  */
+   set_maximum_field_alignment (alignment ? alignment : alignment_stack->alignment);
+       
+   /* Then get rid of the stack entry.  */
+   POP_AN_ENTRY
  
    return 1;
  }
*************** insert_pack_attributes (node, attributes
*** 192,197 ****
--- 236,257 ----
  }
  #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
  
+ static char * pragma_strdup PROTO ((const char *));
+ static char *
+ pragma_strdup (const char * string)
+ {
+   char * name;
+ 
+   name = permalloc (strlen (string) + 1);
+ 
+   if (name == NULL)
+     warning ("Out of memory parsing #pragma");
+   else
+     strcpy (name, string);
+ 
+   return name;
+ }
+ 
  /* Handle one token of a pragma directive.  TOKEN is the current token, and
     STRING is its printable form.  Some front ends do not support generating
     tokens, and will only pass in a STRING.  Also some front ends will reuse
*************** handle_pragma_token (string, token)
*** 212,220 ****
  {
    static enum pragma_state state = ps_start;
    static enum pragma_state type;
    static char * name;
    static char * value;
!   static int align;
  
    /* If we have reached the end of the #pragma directive then
       determine what value we should return.  */
--- 272,285 ----
  {
    static enum pragma_state state = ps_start;
    static enum pragma_state type;
+   static int    align;
+ #ifdef HANDLE_PRAGMA_WEAK
    static char * name;
    static char * value;
! #endif  
! #ifdef HANDLE_PRAGMA_PACK_PUSH_POP  
!   static char * ident;
! #endif
  
    /* If we have reached the end of the #pragma directive then
       determine what value we should return.  */
*************** handle_pragma_token (string, token)
*** 237,243 ****
  	case ps_pack:
  	  if (state == ps_right)
  	    {
! 	      maximum_field_alignment = align * 8;
  	      ret_val = 1;
  	    }
  	  else
--- 302,308 ----
  	case ps_pack:
  	  if (state == ps_right)
  	    {
! 	      set_maximum_field_alignment (align);
  	      ret_val = 1;
  	    }
  	  else
*************** handle_pragma_token (string, token)
*** 248,263 ****
  #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
  	case ps_push:
  	  if (state == ps_right)
! 	    ret_val = push_alignment (align);
  	  else
! 	    warning ("incomplete '#pragma pack(push,<n>)'");
  	  break;
  	  
  	case ps_pop:
  	  if (state == ps_right)
! 	    ret_val = pop_alignment ();
  	  else
! 	    warning ("missing closing parenthesis in '#pragma pack(pop)'");
  	  break;
  #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
  	  
--- 313,328 ----
  #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
  	case ps_push:
  	  if (state == ps_right)
! 	    ret_val = push_alignment (align, ident);
  	  else
! 	    warning ("incomplete '#pragma pack(push...)'");
  	  break;
  	  
  	case ps_pop:
  	  if (state == ps_right)
! 	    ret_val = pop_alignment (align, ident);
  	  else
! 	    warning ("missing closing parenthesis in '#pragma pack(pop...)'");
  	  break;
  #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
  	  
*************** handle_pragma_token (string, token)
*** 318,334 ****
        
  #ifdef HANDLE_PRAGMA_WEAK
      case ps_weak:
!       name = permalloc (strlen (string) + 1);
!       if (name == NULL)
! 	{
! 	  warning ("Out of memory parsing #pragma weak");
! 	  state = ps_bad;
! 	}
!       else
! 	{
! 	  strcpy (name, string);
! 	  state = ps_name;
! 	}
        break;
        
      case ps_name:
--- 383,389 ----
        
  #ifdef HANDLE_PRAGMA_WEAK
      case ps_weak:
!       state = (name = pragma_strdup (string)) ? ps_name : ps_bad;
        break;
        
      case ps_name:
*************** handle_pragma_token (string, token)
*** 336,352 ****
        break;
  
      case ps_equals:
!       value = permalloc (strlen (string) + 1);
!       if (value == NULL)
! 	{
! 	  warning ("Out of memory parsing #pragma weak");
! 	  state = ps_bad;
! 	}
!       else
! 	{
! 	  strcpy (value, string);
! 	  state = ps_value;
! 	}
        break;
  
      case ps_value:
--- 391,397 ----
        break;
  
      case ps_equals:
!       state = (value = pragma_strdup (string)) ? ps_value : ps_bad;
        break;
  
      case ps_value:
*************** handle_pragma_token (string, token)
*** 360,366 ****
        break;
  
      case ps_left:
- 
        if (token && TREE_CODE(token) == INTEGER_CST) 
  	align = TREE_INT_CST_LOW(token);
        else
--- 405,410 ----
*************** handle_pragma_token (string, token)
*** 370,375 ****
--- 414,423 ----
  	case 1:
  	case 2:
  	case 4:
+ #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
+ 	case 8:
+ 	case 16:
+ #endif
  	  state = ps_align;
  	  break;
  
*************** handle_pragma_token (string, token)
*** 382,387 ****
--- 430,437 ----
  		type = state = ps_push;
  	      else if (strcmp (string, "pop") == 0)
  		type = state = ps_pop;
+ 	      align = 0;
+ 	      ident = NULL;
  	    }
  #endif
  	  break;
*************** handle_pragma_token (string, token)
*** 392,400 ****
  	}
        break;
  
- #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
-     case ps_pop:
- #endif
      case ps_align:
        state = (strcmp (string, ")") ? ps_bad : ps_right);
        break;
--- 442,447 ----
*************** handle_pragma_token (string, token)
*** 405,417 ****
  #endif /* HANDLE_PRAGMA_PACK */
  
  #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
      case ps_push:
!       state = (strcmp (string, ",") ? ps_bad : ps_comma);
        break;
  
      case ps_comma:
        align = atoi (string);
        state = ps_align;
        break;
  #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
        
--- 452,483 ----
  #endif /* HANDLE_PRAGMA_PACK */
  
  #ifdef HANDLE_PRAGMA_PACK_PUSH_POP
+     case ps_pop:
      case ps_push:
!       state = ps_bad;
!       if (string[1] == 0)
! 	{
! 	  if      (string[0] == ')') state = ps_align;
! 	  else if (string[0] == ',') state = ps_comma;
! 	}
        break;
  
      case ps_comma:
+       state = ps_bad;
+       if (isascii (string[0]) && isdigit (string[0]))
+ 	{
        align = atoi (string);
        state = ps_align;
+ 	}
+       else if (isascii (string[0]) && isalpha (string[0]))
+ 	{
+ 	  if (ident != NULL)
+ 	    warning ("Multiple idenitifiers found in #pragma pack");
+ 	  else if ((ident = pragma_strdup (string)) != NULL)
+ 	    state = type;
+ 	}
+       else
+ 	warning ("Only an identifier or a value may follow push or pop");
        break;
  #endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
        


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