BETTER FIX for GCC/G++ 1.37 -fpcc-struct-return under SCO UNIX

Chip Salzenberg chip at tct.uucp
Sun Jan 6 08:03:40 AEST 1991


According to sef at kithrup.COM (Sean Eric Fagan):
>For a function called test, taking three parameters (int, char, int), and
>returning a structure, msc passed in 16 bytes, and got rid of 16 bytes after
>the call; rcc passed in 16 bytes, but only got rid of 12 bytes afterwards.
>*sigh*

I'll echo that sigh.  I could have sworn I tested rcc and found it to
work like Microsoft.  We just upgraded to the 3.2v2 dev sys, so maybe
the behavior changed.  Or maybe it was a reality shift.  :-)

In any case, here is the NEW AND IMPROVED patch for GCC/G++ for
functions returning structures in the Microsoft style, for use with
SCO UNIX system libraries.

NOTE: This patch _works_ just like the old one, but it's better
documented, and it's properly conditionalized ("#ifdef M_UNIX").

Shar and enjoy.

=START====================================================================
This file is a shar archive containing patches for GCC 1.37 and G++
1.37 under SCO UNIX.  They make GCC/G++ -fpcc-struct-return compile
definitions of and calls to functions returning structures in the same
way as Microsoft C, the standard C compiler under SCO UNIX.

NOTE THAT THIS PATCH SUPERSEDES THE ONE I POSTED A WEEK AGO.
THE PREVIOUS PATCH WORKED, BUT WAS NOT CONDITIONALIZED PROPERLY.
THIS PATCH CAN BE INSTALLED ON ALL SYSTEMS WITHOUT ILL EFFECT.

Wit this patch, programs compiled with GCC/G++ -fpcc-struct-return can
call SCO library functions that return structures, such as div(),
ldiv(), and the dbm library.

This patch affects the structure-return convention only if M_UNIX is
defined.  If you compile GCC/G++ using "cc" (Microsoft), then M_UNIX
is automatically defined.  If you use "rcc" (PCC), I recommend that
you invoke it with the parameters "-DM_I386 -DM_UNIX".

If you define NUKE_MICROSOFT from the command line or from your
configuration header file, then these patches are disabled and the PCC
convention is used.  NUKE_MICROSOFT is provided for those of you who
prefer using "rcc" (SCO's name for PCC) instead of "cc".  Of course,
if you use "rcc", then you don't need this patch at all.  :-)

Technical details follow:

As distributed, GCC/G++ -fpcc-struct-return assumes that a function
that returns a structure will pop the return-area pointer from the
stack using the "ret 4" instruction, thus leaving only the normal
function parameters on the stack to be removed by the caller.

Microsoft C does things differently.  With Microsoft, the function
returning the structure is expected to return normally using a simple
"ret" instruction, and both the return-area pointer and the normal
arguments must be removed from the stack by the caller.

With these patches, GCC/G++ -fpcc-struct-return make the caller remove
all function arguments including the return-area pointer, and make the
function returning the structure end with a simple "ret".

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  GCC.struct2 G++.struct2
# Wrapped by chip at tct on Sat Jan  5 13:33:51 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'GCC.struct2' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'GCC.struct2'\"
else
echo shar: Extracting \"'GCC.struct2'\" \(5403 characters\)
sed "s/^X//" >'GCC.struct2' <<'END_OF_FILE'
XIndex: expr.c
X***************
X*** 4010,4016 ****
X    funtype = TREE_TYPE (funtype);
X  
X!   /* If struct_value_rtx is 0, it means pass the address
X!      as if it were an extra parameter.  */
X!   if (structure_value_addr && struct_value_rtx == 0)
X      {
X        rtx tem;
X--- 4010,4026 ----
X    funtype = TREE_TYPE (funtype);
X  
X!   /* If structure_value_addr is set, it means pass the address
X!      as if it were an extra parameter.  We typically avoid doing
X!      so here, which would imply that the caller has to pop it off
X!      the stack.  An exception is SCO UNIX (Microsoft C), which
X!      always requires the caller to do the pop.  Microsoft C is
X!      considered "pcc" for purposes of command line flags.  :-) */
X!   if (structure_value_addr
X! #if defined(M_UNIX) && !defined(NUKE_MICROSOFT)	 /* Microsoft: caller pops */
X!       && flag_pcc_struct_return
X! #else
X!       && struct_value_rtx == 0
X! #endif
X!       )
X      {
X        rtx tem;
X***************
X*** 4027,4032 ****
X  				       force_reg (Pmode, structure_value_addr)),
X  				actparms);
X- 	  structure_value_addr_parm = 1;
X  	}
X      }
X  
X--- 4037,4042 ----
X  				       force_reg (Pmode, structure_value_addr)),
X  				actparms);
X  	}
X+       structure_value_addr_parm = 1;
X      }
X  
X***************
X*** 4439,4443 ****
X      adjust_stack (protected_stack);
X  
X!   /* Pass the function the address in which to return a structure value.  */
X    if (structure_value_addr && ! structure_value_addr_parm)
X      emit_move_insn (struct_value_rtx,
X--- 4449,4456 ----
X      adjust_stack (protected_stack);
X  
X!   /* If the function will be returning a structure, and if the address in
X!      which to return the value isn't being passed as a parameter, pass it
X!      now.  This may result in a register move or in a push; if it's a push,
X!      we count on the called routine to pop it.  */
X    if (structure_value_addr && ! structure_value_addr_parm)
X      emit_move_insn (struct_value_rtx,
X***************
X*** 4482,4494 ****
X  
X    /* Figure out the register where the value, if any, will come back.  */
X!   valreg = 0;
X!   if (TYPE_MODE (TREE_TYPE (exp)) != VOIDmode
X!       && ! structure_value_addr)
X!     {
X!       if (pcc_struct_value)
X! 	valreg = hard_libcall_value (Pmode);
X!       else
X! 	valreg = hard_function_value (TREE_TYPE (exp), fndecl);
X!     }
X  
X    /* Generate the actual call instruction.  */
X--- 4495,4505 ----
X  
X    /* Figure out the register where the value, if any, will come back.  */
X!   if (pcc_struct_value)
X!     valreg = hard_libcall_value (Pmode);
X!   else if (TYPE_MODE (TREE_TYPE (exp)) != VOIDmode
X! 	   && ! structure_value_addr)
X!     valreg = hard_function_value (TREE_TYPE (exp), fndecl);
X!   else
X!     valreg = 0;
X  
X    /* Generate the actual call instruction.  */
X***************
X*** 4542,4555 ****
X        target = const0_rtx;
X      }
X-   else if (structure_value_addr)
X-     {
X-       if (target == 0 || GET_CODE (target) != MEM)
X- 	target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
X- 			  memory_address (BLKmode, structure_value_addr));
X-     }
X    else if (pcc_struct_value)
X      {
X-       valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)),
X- 				    fndecl);
X        if (target == 0)
X  	target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
X--- 4553,4558 ----
X***************
X*** 4562,4565 ****
X--- 4565,4574 ----
X  			 expr_size (exp),
X  			 TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
X+     }
X+   else if (structure_value_addr)
X+     {
X+       if (target == 0 || GET_CODE (target) != MEM)
X+ 	target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
X+ 			  memory_address (BLKmode, structure_value_addr));
X      }
X    else if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp)))
XIndex: dist/out-i386.c
X***************
X*** 801,810 ****
X    register int nregs, limit;
X    int assure_sp_pos;
X    extern int frame_pointer_needed;
X    extern int current_function_pops_args;
X    extern int current_function_args_size;
X    limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
X    nregs = 0;
X! 
X  
X    for (regno = (limit -1); regno >= 0; regno--)
X--- 801,818 ----
X    register int nregs, limit;
X    int assure_sp_pos;
X+   int return_struct_adjust;
X    extern int frame_pointer_needed;
X    extern int current_function_pops_args;
X    extern int current_function_args_size;
X+   extern int flag_pcc_struct_return;
X+ 
X    limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
X    nregs = 0;
X!   return_struct_adjust =
X!     (current_function_returns_struct
X! #ifdef M_UNIX /* SCO UNIX (Microsoft C) never does "ret 4" */
X!      && !flag_pcc_struct_return
X! #endif
X!      ) ? 4 : 0;
X  
X    for (regno = (limit -1); regno >= 0; regno--)
X***************
X*** 836,843 ****
X    if (current_function_pops_args && current_function_args_size)
X      fprintf (file, "\tret %s%d\n", IP,
X! 	     (current_function_args_size
X! 	      + (current_function_returns_struct ? 4 : 0)));
X!   else if (current_function_returns_struct)
X!     fprintf (file, "\tret %s4\n", IP);
X    else
X      fprintf (file, "\tret\n");
X--- 844,850 ----
X    if (current_function_pops_args && current_function_args_size)
X      fprintf (file, "\tret %s%d\n", IP,
X! 	     (current_function_args_size + return_struct_adjust));
X!   else if (return_struct_adjust)
X!     fprintf (file, "\tret %s%d\n", IP, return_struct_adjust);
X    else
X      fprintf (file, "\tret\n");
END_OF_FILE
if test 5403 -ne `wc -c <'GCC.struct2'`; then
    echo shar: \"'GCC.struct2'\" unpacked with wrong size!
fi
# end of 'GCC.struct2'
fi
if test -f 'G++.struct2' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'G++.struct2'\"
else
echo shar: Extracting \"'G++.struct2'\" \(3698 characters\)
sed "s/^X//" >'G++.struct2' <<'END_OF_FILE'
XIndex: expr.c
X***************
X*** 4323,4329 ****
X    funtype = TREE_TYPE (funtype);
X  
X!   /* If struct_value_rtx is 0, it means pass the address
X!      as if it were an extra parameter.  */
X!   if (structure_value_addr && struct_value_rtx == 0)
X      {
X        rtx tem;
X--- 4323,4339 ----
X    funtype = TREE_TYPE (funtype);
X  
X!   /* If structure_value_addr is set, it means pass the address
X!      as if it were an extra parameter.  We typically avoid doing
X!      so here, which would imply that the caller has to pop it off
X!      the stack.  An exception is SCO UNIX (Microsoft C), which
X!      always requires the caller to do the pop.  Microsoft C is
X!      considered "pcc" for purposes of command line flags.  :-) */
X!   if (structure_value_addr
X! #if defined(M_UNIX) && !defined(NUKE_MICROSOFT)	 /* Microsoft: caller pops */
X!       && flag_pcc_struct_return
X! #else
X!       && struct_value_rtx == 0
X! #endif
X!       )
X      {
X        rtx tem;
X***************
X*** 4340,4345 ****
X  				       force_reg (Pmode, structure_value_addr)),
X  				actparms);
X- 	  structure_value_addr_parm = 1;
X  	}
X      }
X  
X--- 4350,4355 ----
X  				       force_reg (Pmode, structure_value_addr)),
X  				actparms);
X  	}
X+       structure_value_addr_parm = 1;
X      }
X  
X***************
X*** 4730,4737 ****
X  
X    /* Figure out the register where the value, if any, will come back.  */
X!   valreg = 0;
X!   if (TYPE_MODE (TREE_TYPE (exp)) != VOIDmode
X!       && TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
X      valreg = hard_function_value (TREE_TYPE (exp), fndecl);
X  
X    /* Now compute and store all non-register parms.
X--- 4740,4751 ----
X  
X    /* Figure out the register where the value, if any, will come back.  */
X!   if (pcc_struct_value)
X!     valreg = hard_libcall_value (Pmode);
X!   else if (TYPE_MODE (TREE_TYPE (exp)) != VOIDmode
X! 	   && TYPE_MODE (TREE_TYPE (exp)) != BLKmode
X! 	   && ! structure_value_addr)
X      valreg = hard_function_value (TREE_TYPE (exp), fndecl);
X+   else
X+     valreg = 0;
X  
X    /* Now compute and store all non-register parms.
X***************
X*** 4767,4771 ****
X      adjust_stack (protected_stack);
X  
X!   /* Pass the function the address in which to return a structure value.  */
X    if (structure_value_addr && ! structure_value_addr_parm)
X      emit_move_insn (struct_value_rtx,
X--- 4781,4788 ----
X      adjust_stack (protected_stack);
X  
X!   /* If the function will be returning a structure, and if the address in
X!      which to return the value isn't being passed as a parameter, pass it
X!      now.  This may result in a register move or in a push; if it's a push,
X!      we count on the called routine to pop it.  */
X    if (structure_value_addr && ! structure_value_addr_parm)
X      emit_move_insn (struct_value_rtx,
X***************
X*** 4859,4872 ****
X        target = const0_rtx;
X      }
X-   else if (structure_value_addr)
X-     {
X-       if (target == 0 || GET_CODE (target) != MEM)
X- 	target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
X- 			  memory_address (BLKmode, structure_value_addr));
X-     }
X    else if (pcc_struct_value)
X      {
X-       valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)),
X- 				    fndecl);
X        if (target == 0)
X  	target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
X--- 4876,4881 ----
X***************
X*** 4879,4882 ****
X--- 4888,4897 ----
X  			 expr_size (exp),
X  			 TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
X+     }
X+   else if (structure_value_addr)
X+     {
X+       if (target == 0 || GET_CODE (target) != MEM)
X+ 	target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
X+ 			  memory_address (BLKmode, structure_value_addr));
X      }
X    else if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp)))
END_OF_FILE
if test 3698 -ne `wc -c <'G++.struct2'`; then
    echo shar: \"'G++.struct2'\" unpacked with wrong size!
fi
# end of 'G++.struct2'
fi
echo shar: End of shell archive.
exit 0
=END======================================================================

-- 
Chip Salzenberg at Teltronics/TCT     <chip at tct.uucp>, <uunet!pdn!tct!chip>
 "If Usenet exists, then what is its mailing address?"  -- Chip Salzenberg
             "c/o The Daily Planet, Metropolis."  -- Jeff Daiell



More information about the Comp.unix.sysv386 mailing list