This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the EGCS project.


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

va_list: ppc


Eyeballed.  Would one of the ppc-linux folks sick the test suite
on this for good measure?


r~



	* rs6000.c (setup_incoming_varargs): Use get_varargs_alias_set
	and tag the spill mems.
	(rs6000_expand_builtin_saveregs): Delete.
	(rs6000_build_va_list): New.
	(rs6000_va_start): New.
	(rs6000_va_arg): New.
	* rs6000.h (EXPAND_BUILTIN_SAVEREGS): Delete.
	(BUILD_VA_LIST_TYPE): New.
	(EXPAND_BUILTIN_VA_START): New.
	(EXPAND_BUILTIN_VA_ARG): New.

Index: rs6000/rs6000.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.84
diff -c -p -d -r1.84 rs6000.c
*** rs6000.c	1999/07/27 20:10:38	1.84
--- rs6000.c	1999/07/29 09:08:33
*************** Boston, MA 02111-1307, USA.  */
*** 31,39 ****
  #include "insn-attr.h"
  #include "flags.h"
  #include "recog.h"
- #include "expr.h"
  #include "obstack.h"
  #include "tree.h"
  #include "except.h"
  #include "function.h"
  #include "output.h"
--- 31,39 ----
  #include "insn-attr.h"
  #include "flags.h"
  #include "recog.h"
  #include "obstack.h"
  #include "tree.h"
+ #include "expr.h"
  #include "except.h"
  #include "function.h"
  #include "output.h"
*************** setup_incoming_varargs (cum, mode, type,
*** 1679,1686 ****
  {
    CUMULATIVE_ARGS next_cum;
    int reg_size = TARGET_32BIT ? 4 : 8;
!   rtx save_area;
!   int first_reg_offset;
  
    if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
      {
--- 1679,1686 ----
  {
    CUMULATIVE_ARGS next_cum;
    int reg_size = TARGET_32BIT ? 4 : 8;
!   rtx save_area, mem;
!   int first_reg_offset, set;
  
    if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
      {
*************** setup_incoming_varargs (cum, mode, type,
*** 1718,1729 ****
  	first_reg_offset += RS6000_ARG_SIZE (TYPE_MODE (type), type, 1);
      }
  
    if (!no_rtl && first_reg_offset < GP_ARG_NUM_REG)
      {
        move_block_from_reg
! 	(GP_ARG_MIN_REG + first_reg_offset,
! 	 gen_rtx_MEM (BLKmode,
! 		      plus_constant (save_area, first_reg_offset * reg_size)),
  	 GP_ARG_NUM_REG - first_reg_offset,
  	 (GP_ARG_NUM_REG - first_reg_offset) * UNITS_PER_WORD);
  
--- 1718,1733 ----
  	first_reg_offset += RS6000_ARG_SIZE (TYPE_MODE (type), type, 1);
      }
  
+   set = get_varargs_alias_set ();
    if (!no_rtl && first_reg_offset < GP_ARG_NUM_REG)
      {
+       mem = gen_rtx_MEM (BLKmode,
+ 		         plus_constant (save_area,
+ 					first_reg_offset * reg_size)),
+       MEM_ALIAS_SET (mem) = set;
+ 
        move_block_from_reg
! 	(GP_ARG_MIN_REG + first_reg_offset, mem,
  	 GP_ARG_NUM_REG - first_reg_offset,
  	 (GP_ARG_NUM_REG - first_reg_offset) * UNITS_PER_WORD);
  
*************** setup_incoming_varargs (cum, mode, type,
*** 1751,1758 ****
  
        while (fregno <= FP_ARG_V4_MAX_REG)
  	{
! 	  emit_move_insn (gen_rtx_MEM (DFmode, plus_constant (save_area, off)),
! 			  gen_rtx_REG (DFmode, fregno));
  	  fregno++;
  	  off += 8;
  	}
--- 1755,1763 ----
  
        while (fregno <= FP_ARG_V4_MAX_REG)
  	{
! 	  mem = gen_rtx_MEM (DFmode, plus_constant (save_area, off));
!           MEM_ALIAS_SET (mem) = set;
! 	  emit_move_insn (mem, gen_rtx_REG (DFmode, fregno));
  	  fregno++;
  	  off += 8;
  	}
*************** setup_incoming_varargs (cum, mode, type,
*** 1760,1856 ****
        emit_label (lab);
      }
  }
- 
- /* If defined, is a C expression that produces the machine-specific
-    code for a call to `__builtin_saveregs'.  This code will be moved
-    to the very beginning of the function, before any parameter access
-    are made.  The return value of this function should be an RTX that
-    contains the value to use as the return of `__builtin_saveregs'.
- 
-    On the Power/PowerPC return the address of the area on the stack
-    used to hold arguments.  Under AIX, this includes the 8 word register
-    save area. 
  
!    Under V.4, things are more complicated.  We do not have access to
!    all of the virtual registers required for va_start to do its job,
!    so we construct the va_list in its entirity here, and reduce va_start
!    to a block copy.  This is similar to the way we do things on Alpha.  */
  
! struct rtx_def *
! rs6000_expand_builtin_saveregs ()
  {
!   rtx block, mem_gpr_fpr, mem_reg_save_area, mem_overflow, tmp;
!   tree fntype;
!   int stdarg_p;
!   HOST_WIDE_INT words, gpr, fpr;
  
    if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
!     return virtual_incoming_args_rtx;
  
!   fntype = TREE_TYPE (current_function_decl);
!   stdarg_p = (TYPE_ARG_TYPES (fntype) != 0
! 	      && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
! 		  != void_type_node));
  
!   /* Allocate the va_list constructor.  */
!   block = assign_stack_local (BLKmode, 3 * UNITS_PER_WORD, BITS_PER_WORD);
!   RTX_UNCHANGING_P (block) = 1;
!   RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
  
!   mem_gpr_fpr = change_address (block, word_mode, XEXP (block, 0));
!   mem_overflow = change_address (block, ptr_mode, 
! 			         plus_constant (XEXP (block, 0),
! 						UNITS_PER_WORD));
!   mem_reg_save_area = change_address (block, ptr_mode, 
! 				      plus_constant (XEXP (block, 0),
! 						     2 * UNITS_PER_WORD));
  
!   /* Construct the two characters of `gpr' and `fpr' as a unit.  */
    words = current_function_args_info.words;
!   gpr = current_function_args_info.sysv_gregno - GP_ARG_MIN_REG;
!   fpr = current_function_args_info.fregno - FP_ARG_MIN_REG;
  
    /* Varargs has the va_dcl argument, but we don't count it.  */
    if (!stdarg_p)
      {
!       if (gpr > GP_ARG_NUM_REG)
          words -= 1;
        else
!         gpr -= 1;
      }
  
!   if (BYTES_BIG_ENDIAN)
      {
!       HOST_WIDE_INT bits = gpr << 8 | fpr;
!       if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD)
!         tmp = GEN_INT (bits << (BITS_PER_WORD - 16));
!       else
! 	{
! 	  bits <<= BITS_PER_WORD - HOST_BITS_PER_WIDE_INT - 16;
! 	  tmp = immed_double_const (0, bits, word_mode);
! 	}
      }
    else
!     tmp = GEN_INT (fpr << 8 | gpr);
  
!   emit_move_insn (mem_gpr_fpr, tmp);
  
!   /* Find the overflow area.  */
!   tmp = expand_binop (Pmode, add_optab, virtual_incoming_args_rtx,
! 		      GEN_INT (words * UNITS_PER_WORD),
! 		      mem_overflow, 0, OPTAB_WIDEN);
!   if (tmp != mem_overflow)
!     emit_move_insn (mem_overflow, tmp);
  
!   /* Find the register save area.  */
!   tmp = expand_binop (Pmode, add_optab, virtual_stack_vars_rtx,
! 		      GEN_INT (-RS6000_VARARGS_SIZE),
! 		      mem_reg_save_area, 0, OPTAB_WIDEN);
!   if (tmp != mem_reg_save_area)
!     emit_move_insn (mem_reg_save_area, tmp);
  
!   /* Return the address of the va_list constructor.  */
!   return XEXP (block, 0);
  }
  
  /* Generate a memory reference for expand_block_move, copying volatile,
--- 1765,2022 ----
        emit_label (lab);
      }
  }
  
! /* Create the va_list data type.  */
  
! tree
! rs6000_build_va_list ()
  {
!   tree f_gpr, f_fpr, f_ovf, f_sav, record;
!   tree uchar_type_node;
  
+   /* Only SVR4 needs something special.  */
    if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
!     return ptr_type_node;
  
!   record = make_node (RECORD_TYPE);
!   uchar_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
!   
!   f_gpr = build_decl (FIELD_DECL, get_identifier ("gpr"), uchar_type_node);
!   f_fpr = build_decl (FIELD_DECL, get_identifier ("fpr"), uchar_type_node);
!   f_ovf = build_decl (FIELD_DECL, get_identifier ("overflow_arg_area"),
! 		      ptr_type_node);
!   f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"),
! 		      ptr_type_node);
  
!   DECL_FIELD_CONTEXT (f_gpr) = record;
!   DECL_FIELD_CONTEXT (f_fpr) = record;
!   DECL_FIELD_CONTEXT (f_ovf) = record;
!   DECL_FIELD_CONTEXT (f_sav) = record;
  
!   TYPE_FIELDS (record) = f_gpr;
!   TREE_CHAIN (f_gpr) = f_fpr;
!   TREE_CHAIN (f_fpr) = f_ovf;
!   TREE_CHAIN (f_ovf) = f_sav;
  
!   layout_type (record);
! 
!   return record;
! }
! 
! /* Implement va_start.  */
! 
! void
! rs6000_va_start (stdarg_p, valist, nextarg)
!      int stdarg_p;
!      tree valist;
!      rtx nextarg;
! {
!   HOST_WIDE_INT words, n_gpr, n_fpr;
!   tree f_gpr, f_fpr, f_ovf, f_sav;
!   tree gpr, fpr, ovf, sav, t;
! 
!   /* Only SVR4 needs something special.  */
!   if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
!     {
!       std_expand_builtin_va_start (stdarg_p, valist, nextarg);
!       return;
!     }
! 
!   f_gpr = TYPE_FIELDS (va_list_type_node);
!   f_fpr = TREE_CHAIN (f_gpr);
!   f_ovf = TREE_CHAIN (f_fpr);
!   f_sav = TREE_CHAIN (f_ovf);
! 
!   gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
!   fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
!   ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
!   sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
! 
!   /* Count number of gp and fp argument registers used.  */
    words = current_function_args_info.words;
!   n_gpr = current_function_args_info.sysv_gregno - GP_ARG_MIN_REG;
!   n_fpr = current_function_args_info.fregno - FP_ARG_MIN_REG;
  
    /* Varargs has the va_dcl argument, but we don't count it.  */
    if (!stdarg_p)
      {
!       if (n_gpr > GP_ARG_NUM_REG)
          words -= 1;
        else
!         n_gpr -= 1;
      }
  
!   t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, build_int_2 (n_gpr, 0));
!   TREE_SIDE_EFFECTS (t) = 1;
!   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 
!   t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, build_int_2 (n_fpr, 0));
!   TREE_SIDE_EFFECTS (t) = 1;
!   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 
!   /* Find the overflow area.  */
!   t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
!   if (words != 0)
!     t = build (PLUS_EXPR, TREE_TYPE (ovf), t,
! 	       build_int_2 (words * UNITS_PER_WORD, 0));
!   t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
!   TREE_SIDE_EFFECTS (t) = 1;
!   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 
!   /* Find the register save area.  */
!   t = make_tree (TREE_TYPE (sav), virtual_stack_vars_rtx);
!   t = build (PLUS_EXPR, TREE_TYPE (sav), t,
! 	     build_int_2 (-RS6000_VARARGS_SIZE, -1));
!   t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
!   TREE_SIDE_EFFECTS (t) = 1;
!   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
! }
! 
! /* Implement va_arg.  */
! 
! rtx
! rs6000_va_arg (valist, type)
!      tree valist, type;
! {
!   tree f_gpr, f_fpr, f_ovf, f_sav;
!   tree gpr, fpr, ovf, sav, reg, t, u;
!   int indirect_p, size, rsize, n_reg, sav_ofs, sav_scale;
!   rtx lab_false, lab_over, addr_rtx, r;
! 
!   /* Only SVR4 needs something special.  */
!   if (DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
!     return std_expand_builtin_va_arg (valist, type);
! 
!   f_gpr = TYPE_FIELDS (va_list_type_node);
!   f_fpr = TREE_CHAIN (f_gpr);
!   f_ovf = TREE_CHAIN (f_fpr);
!   f_sav = TREE_CHAIN (f_ovf);
! 
!   gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr);
!   fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr);
!   ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf);
!   sav = build (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav);
! 
!   size = int_size_in_bytes (type);
!   rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
! 
!   if (AGGREGATE_TYPE_P (type) || TYPE_MODE (type) == TFmode)
      {
!       /* Aggregates and long doubles are passed by reference.  */
!       indirect_p = 1;
!       reg = gpr;
!       n_reg = 1;
!       sav_ofs = 0;
!       sav_scale = 4;
!       size = rsize = UNITS_PER_WORD;
      }
+   else if (FLOAT_TYPE_P (type) && ! TARGET_SOFT_FLOAT)
+     {
+       /* FP args go in FP registers, if present.  */
+       indirect_p = 0;
+       reg = fpr;
+       n_reg = 1;
+       sav_ofs = 8*4;
+       sav_scale = 8;
+     }
    else
!     {
!       /* Otherwise into GP registers.  */
!       indirect_p = 0;
!       reg = gpr;
!       n_reg = rsize;
!       sav_ofs = 0;
!       sav_scale = 4;
!     }
  
!   /*
!    * Pull the value out of the saved registers ...
!    */
  
!   lab_false = gen_label_rtx ();
!   lab_over = gen_label_rtx ();
!   addr_rtx = gen_reg_rtx (Pmode);
  
!   emit_cmp_and_jump_insns (expand_expr (reg, NULL_RTX, QImode, EXPAND_NORMAL),
! 			   GEN_INT (8 - n_reg + 1),
! 			   GE, const1_rtx, QImode, 1, 1, lab_false);
  
!   /* Long long is aligned in the registers.  */
!   if (n_reg > 1)
!     {
!       u = build (BIT_AND_EXPR, TREE_TYPE (reg), reg,
! 		 build_int_2 (n_reg - 1, 0));
!       u = build (PLUS_EXPR, TREE_TYPE (reg), reg, u);
!       u = build (MODIFY_EXPR, TREE_TYPE (reg), reg, u);
!       TREE_SIDE_EFFECTS (u) = 1;
!       expand_expr (u, const0_rtx, VOIDmode, EXPAND_NORMAL);
!     }
! 
!   if (sav_ofs)
!     t = build (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0));
!   else
!     t = sav;
! 
!   u = build (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, build_int_2 (n_reg, 0));
!   TREE_SIDE_EFFECTS (u) = 1;
! 
!   u = build1 (CONVERT_EXPR, integer_type_node, u);
!   TREE_SIDE_EFFECTS (u) = 1;
! 
!   u = build (MULT_EXPR, integer_type_node, u, build_int_2 (sav_scale, 0));
!   TREE_SIDE_EFFECTS (u) = 1;
! 
!   t = build (PLUS_EXPR, ptr_type_node, t, u);
!   TREE_SIDE_EFFECTS (t) = 1;
! 
!   r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
!   if (r != addr_rtx)
!     emit_move_insn (addr_rtx, r);
! 
!   emit_jump_insn (gen_jump (lab_over));
!   emit_barrier ();
!   emit_label (lab_false);
! 
!   /*
!    * ... otherwise out of the overflow area.
!    */
! 
!   /* Make sure we don't find reg 7 for the next int arg.  */
!   if (n_reg > 1)
!     {
!       t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, build_int_2 (8, 0));
!       TREE_SIDE_EFFECTS (t) = 1;
!     }
! 
!   /* Care for on-stack alignment if needed.  */
!   if (rsize <= 1)
!     t = ovf;
!   else
!     {
!       t = build (PLUS_EXPR, TREE_TYPE (ovf), ovf, build_int_2 (7, 0));
!       t = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-8, -1));
!     }
!   t = save_expr (t);
! 
!   r = expand_expr (t, addr_rtx, Pmode, EXPAND_NORMAL);
!   if (r != addr_rtx)
!     emit_move_insn (addr_rtx, r);
! 
!   t = build (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (size, 0));
!   t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
!   TREE_SIDE_EFFECTS (t) = 1;
!   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
! 
!   emit_label (lab_over);
! 
!   if (indirect_p)
!     {
!       r = gen_rtx_MEM (Pmode, addr_rtx);
!       MEM_ALIAS_SET (r) = get_varargs_alias_set ();
!       emit_move_insn (addr_rtx, r);
!     }
! 
!   return addr_rtx;
  }
  
  /* Generate a memory reference for expand_block_move, copying volatile,
Index: rs6000/rs6000.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.56
diff -c -p -d -r1.56 rs6000.h
*** rs6000.h	1999/07/27 20:10:38	1.56
--- rs6000.h	1999/07/29 09:08:33
*************** typedef struct rs6000_args
*** 1566,1579 ****
  #define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
    setup_incoming_varargs (&CUM, MODE, TYPE, &PRETEND_SIZE, NO_RTL)
  
! /* If defined, is a C expression that produces the machine-specific
!    code for a call to `__builtin_saveregs'.  This code will be moved
!    to the very beginning of the function, before any parameter access
!    are made.  The return value of this function should be an RTX that
!    contains the value to use as the return of `__builtin_saveregs'.  */
  
! #define EXPAND_BUILTIN_SAVEREGS() \
!   rs6000_expand_builtin_saveregs ()
  
  /* This macro generates the assembly code for function entry.
     FILE is a stdio stream to output the code to.
--- 1566,1582 ----
  #define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
    setup_incoming_varargs (&CUM, MODE, TYPE, &PRETEND_SIZE, NO_RTL)
  
! /* Define the `__builtin_va_list' type for the ABI.  */
! #define BUILD_VA_LIST_TYPE(VALIST) \
!   (VALIST) = rs6000_build_va_list ()
  
! /* Implement `va_start' for varargs and stdarg.  */
! #define EXPAND_BUILTIN_VA_START(stdarg, valist, nextarg) \
!   rs6000_va_start (stdarg, valist, nextarg)
! 
! /* Implement `va_arg'.  */
! #define EXPAND_BUILTIN_VA_ARG(valist, type) \
!   rs6000_va_arg (valist, type)
  
  /* This macro generates the assembly code for function entry.
     FILE is a stdio stream to output the code to.
*************** extern struct rtx_def *function_arg ();
*** 3297,3303 ****
  extern int function_arg_partial_nregs ();
  extern int function_arg_pass_by_reference ();
  extern void setup_incoming_varargs ();
! extern struct rtx_def *rs6000_expand_builtin_saveregs ();
  extern struct rtx_def *rs6000_stack_temp ();
  extern int expand_block_move ();
  extern int load_multiple_operation ();
--- 3300,3308 ----
  extern int function_arg_partial_nregs ();
  extern int function_arg_pass_by_reference ();
  extern void setup_incoming_varargs ();
! extern union tree_node *rs6000_va_list ();
! extern void rs6000_va_start ();
! extern struct rtx_def *rs6000_va_arg ();
  extern struct rtx_def *rs6000_stack_temp ();
  extern int expand_block_move ();
  extern int load_multiple_operation ();

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