altivec stack frame patches

Aldy Hernandez aldyh@redhat.com
Tue Nov 13 15:03:00 GMT 2001


take two... cleaned up.  fixed everything suggested.  it bootstraps too.

2001-11-15  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.
	(ALTIVEC_REG_BIT): New.
	(generate_set_vrsave): New.

	* rs6000.md (get_vrsave): New.
	(set_vrsave): New.
	(*set_vrsave_internal): 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.
	(EPILOGUE_USES): Add VRSAVE_REGNO.


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 15:29:33
*************** 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;
*************** typedef struct rs6000_args
*** 1669,1674 ****
--- 1678,1684 ----
  
  #define	EPILOGUE_USES(REGNO)					\
    ((reload_completed && (REGNO) == LINK_REGISTER_REGNUM)	\
+    || (REGNO) == VRSAVE_REGNO					\
     || (current_function_calls_eh_return				\
         && TARGET_AIX						\
         && (REGNO) == TOC_REGISTER))
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 15:30:48
*************** 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,167 ----
  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));
+ static rtx generate_set_vrsave PARAMS ((rtx, rs6000_stack_t *));
  
  /* Default register names.  */
  char rs6000_reg_names[][8] =
*************** static const char alt_reg_names[][8] =
*** 234,239 ****
--- 239,247 ----
  #undef TARGET_EXPAND_BUILTIN
  #define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
  
+ /* The VRSAVE bitmask puts bit %v0 as the most significant bit.  */
+ #define ALTIVEC_REG_BIT(REGNO) (0x80000000 >> ((REGNO) - FIRST_ALTIVEC_REGNO))
+ 
  struct gcc_target targetm = TARGET_INITIALIZER;
  
  /* Override command line options.  Mostly we process the processor
*************** rs6000_override_options (default_cpu)
*** 496,502 ****
  }
  
  /* Handle -mabi= options.  */
! void rs6000_parse_abi_options ()
  {
    if (rs6000_abi_string == 0)
      return;
--- 504,511 ----
  }
  
  /* Handle -mabi= options.  */
! static void
! rs6000_parse_abi_options ()
  {
    if (rs6000_abi_string == 0)
      return;
*************** direct_return ()
*** 585,592 ****
--- 594,603 ----
  
        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 == 0
  	  && ! 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)
--- 3118,3135 ----
  }
  
  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);
  
--- 3177,3184 ----
      }
  
    /* 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 ();
  }
--- 3196,3207 ----
  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;
--- 3330,3337 ----
    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 ****
--- 3840,3880 ----
    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)
+ 	return 0;
+     }
+ 
+   return 1;
+ }
+ 
  /* Return 1 for an PARALLEL suitable for mtcrf.  */
  
  int
*************** first_fp_reg_to_save ()
*** 5925,5930 ****
--- 5970,6054 ----
  
    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 |= ALTIVEC_REG_BIT (i);
+ 
+   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 |= ALTIVEC_REG_BIT (i);
+ 
+   /* 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 &= ~ALTIVEC_REG_BIT (i);
+ 
+   /* Similarly, remove the return value from the set.  */
+   {
+     bool yes = false;
+     diddle_return_value (is_altivec_return_reg, &yes);
+     if (yes)
+       mask &= ~ALTIVEC_REG_BIT (ALTIVEC_ARG_RETURN);
+   }
+ 
+   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 ()
*** 5952,5962 ****
  		| Local variable space (L)		| 24+P+A
  		+---------------------------------------+
  		| 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		|
  		+---------------------------------------+
  
--- 6076,6092 ----
  		| Local variable space (L)		| 24+P+A
  		+---------------------------------------+
  		| 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		|
  		+---------------------------------------+
--- 6110,6127 ----
  		| 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 ****
--- 6177,6186 ----
    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 ****
--- 6193,6199 ----
  #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,6108 ****
    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)
      {
--- 6235,6252 ----
    info_ptr->vars_size    = RS6000_ALIGN (get_frame_size (), 8);
    info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
  					 8);
  
+   if (TARGET_ALTIVEC_ABI)
+     {
+       info_ptr->vrsave_mask = compute_vrsave_mask ();
+       info_ptr->vrsave_size  = 4;
+     }
+   else
+     {
+       info_ptr->vrsave_mask = 0;
+       info_ptr->vrsave_size = 0;
+     }
+ 
    /* 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;
--- 6259,6287 ----
      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 != 0)
! 	    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
--- 6291,6338 ----
        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 != 0)
! 	    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 ****
--- 6374,6385 ----
    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 == 0)
+     info_ptr->vrsave_save_offset = 0;
+ 
    if (! info_ptr->lr_save_p)
      info_ptr->lr_save_offset = 0;
  
*************** debug_stack_info (info)
*** 6211,6222 ****
--- 6419,6437 ----
  
    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 ****
--- 6441,6449 ----
    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 ****
--- 6456,6469 ----
    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 ****
--- 6497,6512 ----
    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_frame_related (insn, reg, val, re
*** 6805,6810 ****
--- 7041,7076 ----
  					REG_NOTES (insn));
  }
  
+ /* Returns an insn that has a vrsave set operation with the
+    appropriate CLOBBERs.  */
+ 
+ static rtx
+ generate_set_vrsave (reg, info)
+      rtx reg;
+      rs6000_stack_t *info;
+ {
+   int nclobs, i;
+   rtx insn, clobs[TOTAL_ALTIVEC_REGS + 1];
+ 
+   clobs[0] = gen_set_vrsave (reg);
+ 
+   nclobs = 1;
+ 
+   /* CLOBBER the registers in the mask.  */
+ 
+   for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
+     if (info->vrsave_mask != 0 && ALTIVEC_REG_BIT (i) != 0)
+       clobs[nclobs++] = gen_rtx_CLOBBER (VOIDmode,
+ 					 gen_rtx_REG (V4SImode, i));
+ 
+   insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nclobs));
+ 
+   for (i = 0; i < nclobs; ++i)
+     XVECEXP (insn, 0, i) = clobs[i];
+ 
+   return insn;
+ }
+ 
  /* Emit function prologue as insns.  */
  
  void
*************** rs6000_emit_prologue ()
*** 7041,7046 ****
--- 7307,7376 ----
    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 != 0)
+     {
+       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 != 0)
+     {
+       rtx reg, addr, mem;
+ 
+       /* 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)));
+ 
+       insn = emit_insn (generate_set_vrsave (reg, info));
+ 
+       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 ****
--- 7649,7694 ----
  				       info->first_fp_reg_save + i),
  			  mem);
  	}
+ 
+   /* Restore AltiVec registers if needed.  */
+   if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
+     {
+       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 != 0)
+     {
+       rtx addr, mem, reg;
+ 
+       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);
+ 
+       emit_insn (generate_set_vrsave (reg, info));
+     }
  
    /* 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.132
diff -c -p -r1.132 rs6000.md
*** rs6000.md	2001/11/15 15:04:10	1.132
--- rs6000.md	2001/11/15 15:32:22
***************
*** 13445,13450 ****
--- 13445,13475 ----
     vor %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 %0,256"
+   [(set_attr "type" "altivec")])
+ 
+ (define_insn "*set_vrsave_internal"
+   [(match_parallel 0 "vrsave_operation"
+      [(set (reg:SI 109)
+ 	   (unspec:SI [(match_operand:SI 1 "register_operand" "r")
+ 		       (reg:SI 109)] 30))])]
+   "TARGET_ALTIVEC"
+   "mtspr 256,%1"
+   [(set_attr "type" "altivec")])
+ 
+ (define_insn "set_vrsave"
+   [(set (reg:SI 109)
+ 	(unspec:SI [(match_operand:SI 0 "register_operand" "r")
+ 		    (reg:SI 109)] 30))]
+   "TARGET_ALTIVEC"
+   "mtspr 256,%0"
+   [(set_attr "type" "altivec")])
+ 
  ;; Simple binary operations.
  
  (define_insn "altivec_vaddubm"



More information about the Gcc-patches mailing list