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]
Other format: [Raw text]

altivec stack frame patches


hi guys!

i'm pretty much done with the altivec stack frame business and i'd sure
like some input.

i still haven't done extensive testing, but considering it'll probably
take a few iterations to get right, i'd like to start taking suggestions
asap.

everything seems to be working with the exception that flow is trying to
delete epilogue code (the last restore of VRSAVE) because it doesn't
know that VRSAVE is used by the OS.  suggestions on how to flag VRSAVE
as always live?

(oh yeah, at David's request, i also removed a few unused parameters and
variables to get rid of warnings).

bomb away.

aldy

-- 
Aldy Hernandez			E-mail: aldyh@redhat.com
Professional Gypsy
Red Hat, Inc.

2001-11-14  Aldy Hernandez  <aldyh@redhat.com>

	* rs6000.c (direct_return): Check if we are saving altivec
	registers.
	(first_altivec_reg_to_save): New.
	Updated stack frame layout comments.
	(rs6000_stack_info): Calculate altivec register save size.
	Save link register if we saved some altivec registers.
	(rs6000_stack_info): Align save size to 16 if altivec abi or
	abi_darwin.
	(rs6000_stack_info): Calculate altivec register offsets.
	(rs6000_stack_info): Add altivec info to save_size.
	(debug_stack_info): Add altivec debug info.
	(rs6000_emit_prologue): Save altivec registers and vrsave.
	(compute_vrsave_mask): New.
	(altivec_expand_builtin): Remove unused variables.
	(rs6000_parse_abi_options): Add static qualifier.
	(rs6000_expand_builtin): Remove unused parameters.
	(altivec_expand_builtin): Cast bdesc_2arg to get rid of warning.
	(altivec_init_builtins): Same.
	(is_altivec_return_reg): New.
	(vrsave_operation): New.

	* rs6000.md ("get_vrsave"): New.
	("set_vrsave"): New.

	* rs6000.h (rs6000_stack): Add first_altivec_reg_save,
	altivec_save_offset, vrsave_save_offset, altive_size, vrsave_size,
	altivec_padding_size, vrsave_mask.
	(TOTAL_ALTIVEC_REGS): New.


Index: config/rs6000/rs6000.h
===================================================================
RCS file: /cvs/uberbaum/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.135
diff -c -p -r1.135 rs6000.h
*** rs6000.h	2001/11/09 22:34:47	1.135
--- rs6000.h	2001/11/15 01:07:01
*************** extern int rs6000_debug_arg;		/* debug a
*** 720,725 ****
--- 720,726 ----
  #define XER_REGNO    76
  #define FIRST_ALTIVEC_REGNO	77
  #define LAST_ALTIVEC_REGNO	108
+ #define TOTAL_ALTIVEC_REGS	(LAST_ALTIVEC_REGNO - FIRST_ALTIVEC_REGNO)
  #define VRSAVE_REGNO		109
  
  /* List the order in which to allocate registers.  Each register must be
*************** extern enum rs6000_abi rs6000_current_ab
*** 1249,1264 ****
--- 1250,1269 ----
  typedef struct rs6000_stack {
    int first_gp_reg_save;	/* first callee saved GP register used */
    int first_fp_reg_save;	/* first callee saved FP register used */
+   int first_altivec_reg_save;	/* first callee saved AltiVec register used */
    int lr_save_p;		/* true if the link reg needs to be saved */
    int cr_save_p;		/* true if the CR reg needs to be saved */
+   unsigned int vrsave_mask;	/* mask of vec registers to save */
    int toc_save_p;		/* true if the TOC needs to be saved */
    int push_p;			/* true if we need to allocate stack space */
    int calls_p;			/* true if the function makes any calls */
    enum rs6000_abi abi;		/* which ABI to use */
    int gp_save_offset;		/* offset to save GP regs from initial SP */
    int fp_save_offset;		/* offset to save FP regs from initial SP */
+   int altivec_save_offset;	/* offset to save AltiVec regs from inital SP */
    int lr_save_offset;		/* offset to save LR from initial SP */
    int cr_save_offset;		/* offset to save CR from initial SP */
+   int vrsave_save_offset;	/* offset to save VRSAVE from initial SP */
    int toc_save_offset;		/* offset to save the TOC pointer */
    int varargs_save_offset;	/* offset to save the varargs registers */
    int ehrd_offset;		/* offset to EH return data */
*************** typedef struct rs6000_stack {
*** 1270,1277 ****
--- 1275,1286 ----
    int fixed_size;		/* fixed size of stack frame */
    int gp_size;			/* size of saved GP registers */
    int fp_size;			/* size of saved FP registers */
+   int altivec_size;		/* size of saved AltiVec registers */
    int cr_size;			/* size to hold CR if not in save_size */
    int lr_size;			/* size to hold LR if not in save_size */
+   int vrsave_size;		/* size to hold VRSAVE if not in save_size */
+   int altivec_padding_size;	/* size of altivec alignment padding if
+ 				   not in save_size */
    int toc_size;			/* size to hold TOC if not in save_size */
    int total_size;		/* total bytes allocated for stack */
  } rs6000_stack_t;
Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/uberbaum/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.233
diff -c -p -r1.233 rs6000.c
*** rs6000.c	2001/11/11 11:15:52	1.233
--- rs6000.c	2001/11/15 01:08:34
*************** static int rs6000_issue_rate PARAMS ((vo
*** 153,162 ****
  static void rs6000_init_builtins PARAMS ((tree));
  static void altivec_init_builtins PARAMS ((void));
  static rtx rs6000_expand_builtin PARAMS ((tree, rtx, rtx, enum machine_mode, int));
! static rtx altivec_expand_builtin PARAMS ((tree, rtx, rtx, enum machine_mode, int));
  static rtx altivec_expand_binop_builtin PARAMS ((enum insn_code, tree, rtx));
  
  static void rs6000_parse_abi_options PARAMS ((void));
  
  /* Default register names.  */
  char rs6000_reg_names[][8] =
--- 153,166 ----
  static void rs6000_init_builtins PARAMS ((tree));
  static void altivec_init_builtins PARAMS ((void));
  static rtx rs6000_expand_builtin PARAMS ((tree, rtx, rtx, enum machine_mode, int));
! static rtx altivec_expand_builtin PARAMS ((tree, rtx));
  static rtx altivec_expand_binop_builtin PARAMS ((enum insn_code, tree, rtx));
  
  static void rs6000_parse_abi_options PARAMS ((void));
+ static int first_altivec_reg_to_save PARAMS ((void));
+ static unsigned int compute_vrsave_mask PARAMS ((void));
+ static void is_altivec_return_reg PARAMS ((rtx, void *));
+ int vrsave_operation PARAMS ((rtx, enum machine_mode));
  
  /* Default register names.  */
  char rs6000_reg_names[][8] =
*************** rs6000_override_options (default_cpu)
*** 496,502 ****
  }
  
  /* Handle -mabi= options.  */
! void rs6000_parse_abi_options ()
  {
    if (rs6000_abi_string == 0)
      return;
--- 500,507 ----
  }
  
  /* Handle -mabi= options.  */
! static void
! rs6000_parse_abi_options ()
  {
    if (rs6000_abi_string == 0)
      return;
*************** direct_return ()
*** 585,592 ****
--- 590,599 ----
  
        if (info->first_gp_reg_save == 32
  	  && info->first_fp_reg_save == 64
+ 	  && info->first_altivec_reg_save == LAST_ALTIVEC_REGNO + 1
  	  && ! info->lr_save_p
  	  && ! info->cr_save_p
+ 	  && ! info->vrsave_mask
  	  && ! info->push_p)
  	return 1;
      }
*************** altivec_expand_binop_builtin (icode, arg
*** 3107,3127 ****
  }
  
  static rtx
! altivec_expand_builtin (exp, target, subtarget, mode, ignore)
       tree exp;
       rtx target;
-      rtx subtarget;
-      enum machine_mode mode;
-      int ignore;
  {
    struct builtin_description *d;
    size_t i;
    enum insn_code icode;
    tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
    tree arglist = TREE_OPERAND (exp, 1);
!   tree arg0, arg1, arg2, arg3;
!   rtx op0, op1, op2, pat;
!   enum machine_mode tmode, mode0, mode1, mode2;
    unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
    
    switch (fcode)
--- 3114,3131 ----
  }
  
  static rtx
! altivec_expand_builtin (exp, target)
       tree exp;
       rtx target;
  {
    struct builtin_description *d;
    size_t i;
    enum insn_code icode;
    tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
    tree arglist = TREE_OPERAND (exp, 1);
!   tree arg0, arg1;
!   rtx op0, op1, pat;
!   enum machine_mode tmode, mode0, mode1;
    unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
    
    switch (fcode)
*************** altivec_expand_builtin (exp, target, sub
*** 3169,3175 ****
      }
  
    /* Handle simple binary operations.  */
!   for (i = 0, d = bdesc_2arg; i < sizeof (bdesc_2arg) / sizeof *d; i++, d++)
      if (d->code == fcode)
        return altivec_expand_binop_builtin (d->icode, arglist, target);
  
--- 3173,3180 ----
      }
  
    /* Handle simple binary operations.  */
!   d = (struct builtin_description *) bdesc_2arg;
!   for (i = 0; i < sizeof (bdesc_2arg) / sizeof *d; i++, d++)
      if (d->code == fcode)
        return altivec_expand_binop_builtin (d->icode, arglist, target);
  
*************** static rtx
*** 3187,3198 ****
  rs6000_expand_builtin (exp, target, subtarget, mode, ignore)
       tree exp;
       rtx target;
!      rtx subtarget;
!      enum machine_mode mode;
!      int ignore;
  {
    if (TARGET_ALTIVEC)
!     return altivec_expand_builtin (exp, target, subtarget, mode, ignore);
  
    abort ();
  }
--- 3192,3203 ----
  rs6000_expand_builtin (exp, target, subtarget, mode, ignore)
       tree exp;
       rtx target;
!      rtx subtarget ATTRIBUTE_UNUSED;
!      enum machine_mode mode ATTRIBUTE_UNUSED;
!      int ignore ATTRIBUTE_UNUSED;
  {
    if (TARGET_ALTIVEC)
!     return altivec_expand_builtin (exp, target);
  
    abort ();
  }
*************** altivec_init_builtins (void)
*** 3321,3327 ****
    def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal", void_ftype_pint_v4si, ALTIVEC_BUILTIN_ST_INTERNAL);
  
    /* Add the simple binary operators.  */
!   for (i = 0, d = bdesc_2arg; i < sizeof (bdesc_2arg) / sizeof *d; i++, d++)
      {
        enum machine_mode mode0, mode1, mode2;
        tree type;
--- 3326,3333 ----
    def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal", void_ftype_pint_v4si, ALTIVEC_BUILTIN_ST_INTERNAL);
  
    /* Add the simple binary operators.  */
!   d = (struct builtin_description *) bdesc_2arg;
!   for (i = 0; i < sizeof (bdesc_2arg) / sizeof *d; i++, d++)
      {
        enum machine_mode mode0, mode1, mode2;
        tree type;
*************** store_multiple_operation (op, mode)
*** 3830,3835 ****
--- 3836,3877 ----
    return 1;
  }
  
+ /* Return 1 for a parallel vrsave operation.  */
+ 
+ int
+ vrsave_operation (op, mode)
+      rtx op;
+      enum machine_mode mode ATTRIBUTE_UNUSED;
+ {
+   int count = XVECLEN (op, 0);
+   unsigned int dest_regno, src_regno;
+   int i;
+ 
+   if (count <= 1
+       || GET_CODE (XVECEXP (op, 0, 0)) != SET
+       || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
+       || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC)
+     return 0;
+ 
+   dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
+   src_regno  = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
+ 
+   if (dest_regno != VRSAVE_REGNO
+       && src_regno != VRSAVE_REGNO)
+     return 0;
+ 
+   for (i = 1; i < count; i++)
+     {
+       rtx elt = XVECEXP (op, 0, i);
+ 
+       if (GET_CODE (elt) != CLOBBER
+ 	  && GET_CODE (elt) != USE)
+ 	return 0;
+     }
+ 
+   return 1;
+ }
+ 
  /* Return 1 for an PARALLEL suitable for mtcrf.  */
  
  int
*************** first_fp_reg_to_save ()
*** 5925,5930 ****
--- 5967,6051 ----
  
    return first_reg;
  }
+ 
+ /* Similar, for AltiVec regs.  */
+ 
+ static int
+ first_altivec_reg_to_save ()
+ {
+   int i;
+ 
+   /* Stack frame remains as is unless we are in AltiVec ABI.  */
+   if (! TARGET_ALTIVEC_ABI)
+     return LAST_ALTIVEC_REGNO + 1;
+ 
+   /* Find lowest numbered live register.  */
+   for (i = FIRST_ALTIVEC_REGNO + 20; i <= LAST_ALTIVEC_REGNO; ++i)
+     if (regs_ever_live[i])
+       break;
+ 
+   return i;
+ }
+ 
+ /* Return a 32-bit mask of the AltiVec registers we need to set in
+    VRSAVE.  Bit n of the return value is 1 if Vn is live.  The MSB in
+    the 32-bit word is 0.  */
+ 
+ static unsigned int
+ compute_vrsave_mask ()
+ {
+   unsigned int i, mask = 0;
+ 
+   /* First, find out if we use _any_ altivec registers.  */
+   for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
+     if (regs_ever_live[i])
+       mask |= 0x80000000 >> (i - FIRST_ALTIVEC_REGNO);
+ 
+   if (mask == 0)
+     return mask;
+ 
+   /* Next, add all registers that are call-clobbered.  We do this
+      because post-reload register optimizers such as regrename_optimize
+      may choose to use them.  They never change the register class
+      chosen by reload, so cannot create new uses of altivec registers
+      if there were none before, so the early exit above is safe.  */
+   /* ??? Alternately, we could define HARD_REGNO_RENAME_OK to disallow
+      altivec registers not saved in the mask, which might well make the
+      adjustments below more effective in eliding the save/restore of
+      VRSAVE in small functions.  */
+   for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
+     if (call_used_regs[i])
+       mask |= 0x80000000 >> (i - FIRST_ALTIVEC_REGNO);
+ 
+   /* Next, remove the argument registers from the set.  These must
+      be in the VRSAVE mask set by the caller, so we don't need to add
+      them in again.  More importantly, the mask we compute here is
+      used to generate CLOBBERs in the set_vrsave insn, and we do not
+      wish the argument registers to die.  */
+   for (i = cfun->args_info.vregno; i >= ALTIVEC_ARG_MIN_REG; --i)
+     mask &= ~(0x80000000 >> (i - FIRST_ALTIVEC_REGNO));
+ 
+   /* Similarly, remove the return value from the set.  */
+   {
+     bool yes = false;
+     diddle_return_value (is_altivec_return_reg, &yes);
+     if (yes)
+       mask &= ~(0x80000000 >> (ALTIVEC_ARG_RETURN - FIRST_ALTIVEC_REGNO));
+   }
+ 
+   return mask;
+ }
+ 
+ static void
+ is_altivec_return_reg (reg, xyes)
+      rtx reg;
+      void *xyes;
+ {
+   bool *yes = (bool *) xyes;
+   if (REGNO (reg) == ALTIVEC_ARG_RETURN)
+     *yes = true;
+ }
+ 
  
  /* Calculate the stack information for the current function.  This is
     complicated by having two separate calling sequences, the AIX calling
*************** first_fp_reg_to_save ()
*** 5953,5962 ****
  		+---------------------------------------+
  		| Float/int conversion temporary (X)	| 24+P+A+L
  		+---------------------------------------+
! 		| Save area for GP registers (G)	| 24+P+A+X+L
  		+---------------------------------------+
! 		| Save area for FP registers (F)	| 24+P+A+X+L+G
  		+---------------------------------------+
  	old SP->| back chain to caller's caller		|
  		+---------------------------------------+
  
--- 6074,6089 ----
  		+---------------------------------------+
  		| Float/int conversion temporary (X)	| 24+P+A+L
  		+---------------------------------------+
! 		| Save area for AltiVec registers (W)	| 24+P+A+L+X
  		+---------------------------------------+
! 		| AltiVec alignment padding (Y)		| 24+P+A+L+X+W
  		+---------------------------------------+
+ 		| Save area for VRSAVE register (Z)	| 24+P+A+L+X+W+Y
+ 		+---------------------------------------+
+ 		| Save area for GP registers (G)	| 24+P+A+X+L+X+W+Y+Z
+ 		+---------------------------------------+
+ 		| Save area for FP registers (F)	| 24+P+A+X+L+X+W+Y+Z+G
+ 		+---------------------------------------+
  	old SP->| back chain to caller's caller		|
  		+---------------------------------------+
  
*************** first_fp_reg_to_save ()
*** 5980,5991 ****
  		| Local variable space (L)		| 8+P+A+V
  		+---------------------------------------+    
  		| Float/int conversion temporary (X)	| 8+P+A+V+L
  		+---------------------------------------+
! 		| saved CR (C)				| 8+P+A+V+L+X
  		+---------------------------------------+    
! 		| Save area for GP registers (G)	| 8+P+A+V+L+X+C
  		+---------------------------------------+    
! 		| Save area for FP registers (F)	| 8+P+A+V+L+X+C+G
  		+---------------------------------------+
  	old SP->| back chain to caller's caller		|
  		+---------------------------------------+
--- 6107,6124 ----
  		| Local variable space (L)		| 8+P+A+V
  		+---------------------------------------+    
  		| Float/int conversion temporary (X)	| 8+P+A+V+L
+ 		+---------------------------------------+
+ 		| Save area for AltiVec registers (W)	| 8+P+A+V+L+X
+ 		+---------------------------------------+
+ 		| AltiVec alignment padding (Y)		| 8+P+A+V+L+X+W
  		+---------------------------------------+
! 		| Save area for VRSAVE register (Z)	| 8+P+A+V+L+X+W+Y
! 		+---------------------------------------+
! 		| saved CR (C)				| 8+P+A+V+L+X+W+Y+Z
  		+---------------------------------------+    
! 		| Save area for GP registers (G)	| 8+P+A+V+L+X+W+Y+Z+C
  		+---------------------------------------+    
! 		| Save area for FP registers (F)	| 8+P+A+V+L+X+W+Y+Z+C+G
  		+---------------------------------------+
  	old SP->| back chain to caller's caller		|
  		+---------------------------------------+
*************** rs6000_stack_info ()
*** 6041,6046 ****
--- 6174,6183 ----
    info_ptr->first_fp_reg_save = first_fp_reg_to_save ();
    info_ptr->fp_size = 8 * (64 - info_ptr->first_fp_reg_save);
  
+   info_ptr->first_altivec_reg_save = first_altivec_reg_to_save ();
+   info_ptr->altivec_size = 16 * (LAST_ALTIVEC_REGNO + 1
+ 				 - info_ptr->first_altivec_reg_save);
+ 
    /* Does this function call anything?  */
    info_ptr->calls_p = (! current_function_is_leaf
  		       || cfun->machine->ra_needs_full_frame);
*************** rs6000_stack_info ()
*** 6053,6058 ****
--- 6190,6196 ----
  #endif
        || (info_ptr->first_fp_reg_save != 64
  	  && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save))
+       || info_ptr->first_altivec_reg_save <= LAST_ALTIVEC_REGNO
        || (abi == ABI_V4 && current_function_calls_alloca)
        || (abi == ABI_SOLARIS && current_function_calls_alloca)
        || (DEFAULT_ABI == ABI_DARWIN
*************** rs6000_stack_info ()
*** 6094,6107 ****
    info_ptr->vars_size    = RS6000_ALIGN (get_frame_size (), 8);
    info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
  					 8);
!   info_ptr->save_size    = RS6000_ALIGN (info_ptr->fp_size
! 					 + info_ptr->gp_size
! 					 + ehrd_size
! 					 + info_ptr->cr_size
! 					 + info_ptr->lr_size
! 					 + info_ptr->toc_size, 8);
!   if (DEFAULT_ABI == ABI_DARWIN)
!     info_ptr->save_size = RS6000_ALIGN (info_ptr->save_size, 16);
  
    /* Calculate the offsets.  */
    switch (abi)
--- 6232,6241 ----
    info_ptr->vars_size    = RS6000_ALIGN (get_frame_size (), 8);
    info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
  					 8);
! 
!   /* Save VRSAVE if we use any vector register.  */
!   info_ptr->vrsave_mask = compute_vrsave_mask ();
!   info_ptr->vrsave_size  = reg_size;
  
    /* Calculate the offsets.  */
    switch (abi)
*************** rs6000_stack_info ()
*** 6115,6121 ****
      case ABI_DARWIN:
        info_ptr->fp_save_offset   = - info_ptr->fp_size;
        info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
!       info_ptr->ehrd_offset      = info_ptr->gp_save_offset - ehrd_size;
        info_ptr->cr_save_offset   = reg_size; /* first word when 64-bit.  */
        info_ptr->lr_save_offset   = 2*reg_size;
        break;
--- 6249,6277 ----
      case ABI_DARWIN:
        info_ptr->fp_save_offset   = - info_ptr->fp_size;
        info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
! 
!       if (TARGET_ALTIVEC_ABI)
! 	{
! 	  info_ptr->vrsave_save_offset
! 	    = info_ptr->gp_save_offset - info_ptr->vrsave_size;
! 
! 	  /* Align stack so vector save area is on a quadword boundary.  */
! 	  if (info_ptr->altivec_size)
! 	    info_ptr->altivec_padding_size
! 	      = 16 - (-info_ptr->vrsave_save_offset % 16);
! 	  else
! 	    info_ptr->altivec_padding_size = 0;
! 
! 	  info_ptr->altivec_save_offset
! 	    = info_ptr->vrsave_save_offset
! 	    - info_ptr->altivec_padding_size
! 	    - info_ptr->altivec_size;
! 
! 	  /* Adjust for AltiVec case.  */
! 	  info_ptr->ehrd_offset = info_ptr->altivec_save_offset - ehrd_size;
! 	}
!       else
! 	info_ptr->ehrd_offset      = info_ptr->gp_save_offset - ehrd_size;
        info_ptr->cr_save_offset   = reg_size; /* first word when 64-bit.  */
        info_ptr->lr_save_offset   = 2*reg_size;
        break;
*************** rs6000_stack_info ()
*** 6125,6136 ****
        info_ptr->fp_save_offset   = - info_ptr->fp_size;
        info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
        info_ptr->cr_save_offset   = info_ptr->gp_save_offset - info_ptr->cr_size;
!       info_ptr->toc_save_offset  = info_ptr->cr_save_offset - info_ptr->toc_size;
        info_ptr->ehrd_offset      = info_ptr->toc_save_offset - ehrd_size;
        info_ptr->lr_save_offset   = reg_size;
        break;
      }
  
    total_raw_size	 = (info_ptr->vars_size
  			    + info_ptr->parm_size
  			    + info_ptr->save_size
--- 6281,6328 ----
        info_ptr->fp_save_offset   = - info_ptr->fp_size;
        info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
        info_ptr->cr_save_offset   = info_ptr->gp_save_offset - info_ptr->cr_size;
! 
!       if (TARGET_ALTIVEC_ABI)
! 	{
! 	  info_ptr->vrsave_save_offset
! 	    = info_ptr->cr_save_offset - info_ptr->vrsave_size;
! 
! 	  /* Align stack so vector save area is on a quadword boundary.  */
! 	  if (info_ptr->altivec_size)
! 	    info_ptr->altivec_padding_size
! 	      = 16 - (-info_ptr->vrsave_save_offset % 16);
! 	  else
! 	    info_ptr->altivec_padding_size = 0;
! 
! 	  info_ptr->altivec_save_offset
! 	    = info_ptr->vrsave_save_offset
! 	    - info_ptr->altivec_padding_size
! 	    - info_ptr->altivec_size;
! 
! 	  /* Adjust for AltiVec case.  */
! 	  info_ptr->toc_save_offset
! 	    = info_ptr->altivec_save_offset - info_ptr->toc_size;
! 	}
!       else
! 	info_ptr->toc_save_offset  = info_ptr->cr_save_offset - info_ptr->toc_size;
        info_ptr->ehrd_offset      = info_ptr->toc_save_offset - ehrd_size;
        info_ptr->lr_save_offset   = reg_size;
        break;
      }
  
+   info_ptr->save_size    = RS6000_ALIGN (info_ptr->fp_size
+ 					 + info_ptr->gp_size
+ 					 + info_ptr->altivec_size
+ 					 + info_ptr->altivec_padding_size
+ 					 + info_ptr->vrsave_size
+ 					 + ehrd_size
+ 					 + info_ptr->cr_size
+ 					 + info_ptr->lr_size
+ 					 + info_ptr->vrsave_size
+ 					 + info_ptr->toc_size,
+ 					 (TARGET_ALTIVEC_ABI || ABI_DARWIN)
+ 					 ? 16 : 8);
+ 
    total_raw_size	 = (info_ptr->vars_size
  			    + info_ptr->parm_size
  			    + info_ptr->save_size
*************** rs6000_stack_info ()
*** 6172,6177 ****
--- 6364,6375 ----
    if (info_ptr->gp_size == 0)
      info_ptr->gp_save_offset = 0;
  
+   if (! TARGET_ALTIVEC_ABI || info_ptr->altivec_size == 0)
+     info_ptr->altivec_save_offset = 0;
+ 
+   if (! TARGET_ALTIVEC_ABI || ! info_ptr->vrsave_mask)
+     info_ptr->vrsave_save_offset = 0;
+ 
    if (! info_ptr->lr_save_p)
      info_ptr->lr_save_offset = 0;
  
*************** debug_stack_info (info)
*** 6211,6222 ****
--- 6409,6427 ----
  
    fprintf (stderr, "\tABI                 = %5s\n", abi_string);
  
+   if (TARGET_ALTIVEC_ABI)
+     fprintf (stderr, "\tALTIVEC ABI extensions enabled.\n");
+ 
    if (info->first_gp_reg_save != 32)
      fprintf (stderr, "\tfirst_gp_reg_save   = %5d\n", info->first_gp_reg_save);
  
    if (info->first_fp_reg_save != 64)
      fprintf (stderr, "\tfirst_fp_reg_save   = %5d\n", info->first_fp_reg_save);
  
+   if (info->first_altivec_reg_save <= LAST_ALTIVEC_REGNO)
+     fprintf (stderr, "\tfirst_altivec_reg_save = %5d\n",
+ 	     info->first_altivec_reg_save);
+ 
    if (info->lr_save_p)
      fprintf (stderr, "\tlr_save_p           = %5d\n", info->lr_save_p);
  
*************** debug_stack_info (info)
*** 6226,6231 ****
--- 6431,6439 ----
    if (info->toc_save_p)
      fprintf (stderr, "\ttoc_save_p          = %5d\n", info->toc_save_p);
  
+   if (info->vrsave_mask)
+     fprintf (stderr, "\tvrsave_mask         = 0x%x\n", info->vrsave_mask);
+ 
    if (info->push_p)
      fprintf (stderr, "\tpush_p              = %5d\n", info->push_p);
  
*************** debug_stack_info (info)
*** 6238,6243 ****
--- 6446,6459 ----
    if (info->fp_save_offset)
      fprintf (stderr, "\tfp_save_offset      = %5d\n", info->fp_save_offset);
  
+   if (info->altivec_save_offset)
+     fprintf (stderr, "\taltivec_save_offset = %5d\n",
+ 	     info->altivec_save_offset);
+ 
+   if (info->vrsave_save_offset)
+     fprintf (stderr, "\tvrsave_save_offset  = %5d\n",
+ 	     info->vrsave_save_offset);
+ 
    if (info->lr_save_offset)
      fprintf (stderr, "\tlr_save_offset      = %5d\n", info->lr_save_offset);
  
*************** debug_stack_info (info)
*** 6271,6276 ****
--- 6487,6502 ----
    if (info->fp_size)
      fprintf (stderr, "\tfp_size             = %5d\n", info->fp_size);
  
+   if (info->altivec_size)
+     fprintf (stderr, "\taltivec_size        = %5d\n", info->altivec_size);
+ 
+   if (info->vrsave_size)
+     fprintf (stderr, "\tvrsave_size         = %5d\n", info->vrsave_size);
+ 
+   if (info->altivec_padding_size)
+     fprintf (stderr, "\taltivec_padding_size= %5d\n",
+ 	     info->altivec_padding_size);
+ 
    if (info->lr_size)
      fprintf (stderr, "\tlr_size             = %5d\n", info->lr_size);
  
*************** rs6000_emit_prologue ()
*** 7041,7046 ****
--- 7267,7353 ----
    if (info->push_p && DEFAULT_ABI != ABI_V4 && DEFAULT_ABI != ABI_SOLARIS)
      rs6000_emit_allocate_stack (info->total_size, FALSE);
  
+   /* Save AltiVec registers if needed.  */
+   if (TARGET_ALTIVEC_ABI && info->altivec_size)
+     {
+       int i;
+ 
+       /* There should be a non inline version of this, for when we
+ 	 are saving lots of vector registers.  */
+       for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
+ 	if (regs_ever_live[i] && ! call_used_regs[i])
+ 	  {
+ 	    rtx addr, areg, savereg, mem;
+ 
+ 	    savereg = gen_rtx_REG (V4SImode, i);
+ 
+ 	    areg = gen_rtx_REG (Pmode, 0);
+ 	    emit_move_insn
+ 	      (areg, GEN_INT (info->altivec_save_offset
+ 			      + sp_offset
+ 			      + 16 * (i - info->first_altivec_reg_save)));
+ 
+ 	    /* AltiVec addressing mode is [reg+reg].  */
+ 	    addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
+ 	    mem = gen_rtx_MEM (V4SImode, addr);
+ 	    set_mem_alias_set (mem, rs6000_sr_alias_set);
+ 
+ 	    insn = emit_move_insn (mem, savereg);
+ 	    rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, 
+ 				  NULL_RTX, NULL_RTX);
+ 	  }
+     }
+ 
+   /* VRSAVE is a bit vector representing which AltiVec registers
+      are used.  The OS uses this to determine which vector
+      registers to save on a context switch.  We need to save
+      VRSAVE on the stack frame, add whatever AltiVec registers we
+      used in this function, and do the corresponding magic in the
+      epilogue.  */
+ 
+   if (TARGET_ALTIVEC && info->vrsave_mask)
+     {
+       rtx reg, addr, mem;
+       rtx clobs[TOTAL_ALTIVEC_REGS + 1];
+       int i, nclob;
+ 
+       /* Get VRSAVE onto a GPR.  */
+       reg = gen_rtx_REG (SImode, 12);
+       emit_insn (gen_get_vrsave (reg));
+ 
+       /* Save VRSAVE.  */
+       addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ 			   GEN_INT (info->vrsave_save_offset + sp_offset));
+       mem = gen_rtx_MEM (SImode, addr);
+       set_mem_alias_set (mem, rs6000_sr_alias_set);
+       insn = emit_move_insn (mem, reg);
+       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+ 			    NULL_RTX, NULL_RTX);
+ 
+       /* Include the registers in the mask.  */
+       emit_insn (gen_iorsi3 (reg, reg, GEN_INT ((int) info->vrsave_mask)));
+ 
+       clobs[0] = gen_set_vrsave (reg);
+       
+       nclob = 1;
+ 
+       /* CLOBBER the registers in the mask.  */
+ 
+       for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
+ 	if (info->vrsave_mask & (0x80000000 >> (i - FIRST_ALTIVEC_REGNO)))
+ 	  clobs[nclob++] = gen_rtx_CLOBBER (VOIDmode,
+ 					    gen_rtx_REG (V4SImode, i));
+ 
+       insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nclob));
+ 
+       for (i = 0; i < nclob; ++i)
+ 	XVECEXP (insn, 0, i) = clobs[i];
+ 
+       insn = emit_insn (insn);
+       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+ 			    NULL_RTX, NULL_RTX);
+     }
+ 
    /* Set frame pointer, if needed.  */
    if (frame_pointer_needed)
      {
*************** rs6000_emit_epilogue (sibcall)
*** 7319,7324 ****
--- 7626,7671 ----
  				       info->first_fp_reg_save + i),
  			  mem);
  	}
+ 
+   /* Restore AltiVec registers if needed.  */
+   if (TARGET_ALTIVEC_ABI && info->altivec_size)
+     {
+       int i;
+ 
+       for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
+ 	if (regs_ever_live[i] && ! call_used_regs[i])
+ 	  {
+ 	    rtx addr, areg, mem;
+ 
+ 	    areg = gen_rtx_REG (Pmode, 0);
+ 	    emit_move_insn
+ 	      (areg, GEN_INT (info->altivec_save_offset
+ 			      + sp_offset
+ 			      + 16 * (i - info->first_altivec_reg_save)));
+ 
+ 	    /* AltiVec addressing mode is [reg+reg].  */
+ 	    addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
+ 	    mem = gen_rtx_MEM (V4SImode, addr);
+ 	    set_mem_alias_set (mem, rs6000_sr_alias_set);
+ 
+ 	    emit_move_insn (gen_rtx_REG (V4SImode, i), mem);
+ 	  }
+     }
+ 
+   /* Restore VRSAVE if needed.  */
+   if (TARGET_ALTIVEC_ABI && info->vrsave_mask)
+     {
+       rtx addr, mem, reg, insn;
+ 
+       addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ 			   GEN_INT (info->vrsave_save_offset + sp_offset));
+       mem = gen_rtx_MEM (SImode, addr);
+       set_mem_alias_set (mem, rs6000_sr_alias_set);
+       reg = gen_rtx_REG (SImode, 12);
+       emit_move_insn (reg, mem);
+ 
+       insn = emit_insn (gen_set_vrsave (reg));
+     }
  
    /* If we saved cr, restore it here.  Just those that were used.  */
    if (info->cr_save_p)
Index: config/rs6000/rs6000.md
===================================================================
RCS file: /cvs/uberbaum/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.130
diff -c -p -r1.130 rs6000.md
*** rs6000.md	2001/11/07 20:49:41	1.130
--- rs6000.md	2001/11/15 01:10:42
***************
*** 13445,13450 ****
--- 13445,13474 ----
     vor\t%0,%1,%1"
    [(set_attr "type" "altivec")])
  
+ ;; Copy VRSAVE into a GPR.
+ (define_insn "get_vrsave"
+   [(set (match_operand:SI 0 "register_operand" "=r")
+ 	(unspec:SI [(reg:SI 109)] 28))]
+   "TARGET_ALTIVEC"
+   "mfspr\t%0,256"
+   [(set_attr "type" "altivec")])
+ 
+ ;; Copy a GPR into VRSAVE.
+ (define_insn "*set_vrsave_internal"
+   [(match_parallel 0 "vrsave_operation"
+      [(set (reg:SI 109)
+ 	   (unspec:SI [(match_operand:SI 1 "register_operand" "r")] 30))])]
+   "TARGET_ALTIVEC"
+   "mtspr\t256,%1"
+   [(set_attr "type" "altivec")])
+ 
+ (define_insn "set_vrsave"
+   [(set (reg:SI 109)
+ 	(unspec:SI [(match_operand:SI 0 "register_operand" "r")] 30))]
+   "TARGET_ALTIVEC"
+   "mtspr\t256,%0"
+   [(set_attr "type" "altivec")])
+ 
  ;; Simple binary operations.
  
  (define_insn "altivec_vaddubm"


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