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