From d62294f57e859308c23fcbd156bb88b21e8f4547 Mon Sep 17 00:00:00 2001 From: Fariborz Jahanian Date: Wed, 18 Aug 2004 16:33:10 +0000 Subject: [PATCH] save_world/rest_world for ppc-darwin. Approved by Geoff Keating. From-SVN: r86191 --- gcc/ChangeLog | 26 ++ gcc/config/rs6000/altivec.md | 22 ++ gcc/config/rs6000/rs6000-protos.h | 2 + gcc/config/rs6000/rs6000.c | 432 +++++++++++++++++++++++++++++- gcc/config/rs6000/rs6000.h | 6 + 5 files changed, 476 insertions(+), 12 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3bb39234550..9e38a2a7844 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +2004-08-18 Fariborz Jahanian + + * config/rs6000/altivec.md: Add new patterns for calls to + save_world/rest_world functions. + + * config/rs6000/rs6000-protos.h: (save_world_operation, + restore_world_operation) new declarations. + + * config/rs6000/rs6000.c: (struct rs6000_stack) new world_save_p + field added. + (rs6000_stack_info): Set world_save_p field. + (save_world_operation): New function. + (restore_world_operation): New function. + (compute_save_world_info): New function. + (rs6000_stack_info): Call compute_save_world_info. + (rs6000_emit_prologue): Check for world_save_p and generate + pattern to call save_world for saving all non-volatile and + special registers. + (rs6000_emit_epilogue): Check for world_save_p and generate + pattern to call rest_world to restore saved registers. + + config/rs6000/rs6000.h: macros FIRST_SAVED_ALTIVEC_REGNO, + FIRST_SAVED_FP_REGNO, FIRST_SAVED_GP_REGNO defined. + (rs6000_reg_names): New entries added for save_world_operation and + restore_world_operation. + 2004-08-18 Caroline Tice * Makefile.in (STAGEFEEDBACK_FLAGS_TO_PASS) Add diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md index 6d127b4e204..ff58d8e3fa8 100644 --- a/gcc/config/rs6000/altivec.md +++ b/gcc/config/rs6000/altivec.md @@ -295,6 +295,28 @@ }" [(set_attr "type" "*")]) +(define_insn "*save_world" + [(match_parallel 0 "save_world_operation" + [(clobber (match_operand:SI 1 "register_operand" "=l")) + (use (match_operand:SI 2 "call_operand" "s"))])] + "TARGET_MACHO && (DEFAULT_ABI == ABI_DARWIN) && TARGET_32BIT" + { + return "bl %z2"; + } + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*restore_world" + [(match_parallel 0 "restore_world_operation" + [(return) + (use (match_operand:SI 1 "register_operand" "l")) + (use (match_operand:SI 2 "call_operand" "s")) + (clobber (match_operand:SI 3 "gpc_reg_operand" "=r"))])] + "TARGET_MACHO && (DEFAULT_ABI == ABI_DARWIN) && TARGET_32BIT" + { + return "b %z2"; + }) + ;; Simple binary operations. (define_insn "addv16qi3" diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 2e5afb6cb44..d146265f133 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -89,6 +89,8 @@ extern bool legitimate_constant_pool_address_p (rtx); extern int expand_block_clear (rtx[]); extern int expand_block_move (rtx[]); extern int load_multiple_operation (rtx, enum machine_mode); +extern int save_world_operation (rtx, enum machine_mode); +extern int restore_world_operation (rtx, enum machine_mode); extern const char * rs6000_output_load_multiple (rtx[]); extern int store_multiple_operation (rtx, enum machine_mode); extern int branch_comparison_operator (rtx, enum machine_mode); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 0c38a602f9c..d103ac38a15 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -79,6 +79,8 @@ typedef struct rs6000_stack { 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 */ + int world_save_p; /* true if we're saving *everything*: + r13-r31, cr, f14-f31, vrsave, v20-v31 */ 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 */ @@ -714,6 +716,7 @@ static void rs6000_parse_tls_size_option (void); static void rs6000_parse_yes_no_option (const char *, const char *, int *); static int first_altivec_reg_to_save (void); static unsigned int compute_vrsave_mask (void); +static void compute_save_world_info(rs6000_stack_t *info_ptr); static void is_altivec_return_reg (rtx, void *); static rtx generate_set_vrsave (rtx, rs6000_stack_t *, int); int easy_vector_constant (rtx, enum machine_mode); @@ -8529,6 +8532,143 @@ expand_block_move (rtx operands[]) return 1; } + +/* Return 1 if OP is suitable for a save_world call in prologue. It is + known to be a PARALLEL. */ +int +save_world_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + int index; + int i; + rtx elt; + int count = XVECLEN (op, 0); + + if (count != 55) + return 0; + + index = 0; + if (GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER + || GET_CODE (XVECEXP (op, 0, index++)) != USE) + return 0; + + for (i=1; i <= 18; i++) + { + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_DEST (elt)) != MEM + || ! memory_operand (SET_DEST (elt), DFmode) + || GET_CODE (SET_SRC (elt)) != REG + || GET_MODE (SET_SRC (elt)) != DFmode) + return 0; + } + + for (i=1; i <= 12; i++) + { + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_DEST (elt)) != MEM + || GET_CODE (SET_SRC (elt)) != REG + || GET_MODE (SET_SRC (elt)) != V4SImode) + return 0; + } + + for (i=1; i <= 19; i++) + { + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_DEST (elt)) != MEM + || ! memory_operand (SET_DEST (elt), Pmode) + || GET_CODE (SET_SRC (elt)) != REG + || GET_MODE (SET_SRC (elt)) != Pmode) + return 0; + } + + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_DEST (elt)) != MEM + || ! memory_operand (SET_DEST (elt), Pmode) + || GET_CODE (SET_SRC (elt)) != REG + || REGNO (SET_SRC (elt)) != CR2_REGNO + || GET_MODE (SET_SRC (elt)) != Pmode) + return 0; + + if (GET_CODE (XVECEXP (op, 0, index++)) != USE + || GET_CODE (XVECEXP (op, 0, index++)) != USE + || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER) + return 0; + return 1; +} + +/* Return 1 if OP is suitable for a save_world call in prologue. It is + known to be a PARALLEL. */ +int +restore_world_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + int index; + int i; + rtx elt; + int count = XVECLEN (op, 0); + + if (count != 59) + return 0; + + index = 0; + if (GET_CODE (XVECEXP (op, 0, index++)) != RETURN + || GET_CODE (XVECEXP (op, 0, index++)) != USE + || GET_CODE (XVECEXP (op, 0, index++)) != USE + || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER) + return 0; + + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != MEM + || ! memory_operand (SET_SRC (elt), Pmode) + || GET_CODE (SET_DEST (elt)) != REG + || REGNO (SET_DEST (elt)) != CR2_REGNO + || GET_MODE (SET_DEST (elt)) != Pmode) + return 0; + + for (i=1; i <= 19; i++) + { + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != MEM + || ! memory_operand (SET_SRC (elt), Pmode) + || GET_CODE (SET_DEST (elt)) != REG + || GET_MODE (SET_DEST (elt)) != Pmode) + return 0; + } + + for (i=1; i <= 12; i++) + { + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != MEM + || GET_CODE (SET_DEST (elt)) != REG + || GET_MODE (SET_DEST (elt)) != V4SImode) + return 0; + } + + for (i=1; i <= 18; i++) + { + elt = XVECEXP (op, 0, index++); + if (GET_CODE (elt) != SET + || GET_CODE (SET_SRC (elt)) != MEM + || ! memory_operand (SET_SRC (elt), DFmode) + || GET_CODE (SET_DEST (elt)) != REG + || GET_MODE (SET_DEST (elt)) != DFmode) + return 0; + } + + if (GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER + || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER + || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER + || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER + || GET_CODE (XVECEXP (op, 0, index++)) != USE) + return 0; + return 1; +} + /* Return 1 if OP is a load multiple operation. It is known to be a PARALLEL and the first section will be tested. */ @@ -11362,6 +11502,57 @@ compute_vrsave_mask (void) return mask; } +/* For a very restricted set of circumstances, we can cut down the + size of prologs/epilogs by calling our own save/restore-the-world + routines. */ + +static void +compute_save_world_info(rs6000_stack_t *info_ptr) +{ + info_ptr->world_save_p = + (DEFAULT_ABI == ABI_DARWIN) + && ! (current_function_calls_setjmp && flag_exceptions) + && info_ptr->first_fp_reg_save == FIRST_SAVED_FP_REGNO + && info_ptr->first_gp_reg_save == FIRST_SAVED_GP_REGNO + && info_ptr->first_altivec_reg_save == FIRST_SAVED_ALTIVEC_REGNO + && info_ptr->cr_save_p; + + /* This will not work in conjunction with sibcalls. Make sure there + are none. (This check is expensive, but seldom executed.) */ + if ( info_ptr->world_save_p ) + { + rtx insn; + for ( insn = get_last_insn_anywhere (); insn; insn = PREV_INSN (insn)) + if ( GET_CODE (insn) == CALL_INSN + && SIBLING_CALL_P (insn)) + { + info_ptr->world_save_p = 0; + break; + } + } + + if (info_ptr->world_save_p) + { + /* Even if we're not touching VRsave, make sure there's room on the + stack for it, if it looks like we're calling SAVE_WORLD, which + will attempt to save it. */ + info_ptr->vrsave_size = 4; + + /* "Save" the VRsave register too if we're saving the world. */ + if (info_ptr->vrsave_mask == 0) + info_ptr->vrsave_mask = compute_vrsave_mask (); + + /* Because the Darwin register save/restore routines only handle + F14 .. F31 and V20 .. V31 as per the ABI, perform a consistancy + check and abort if there's something worng. */ + if (info_ptr->first_fp_reg_save < FIRST_SAVED_FP_REGNO + || info_ptr->first_altivec_reg_save < FIRST_SAVED_ALTIVEC_REGNO) + abort (); + } + return; +} + + static void is_altivec_return_reg (rtx reg, void *xyes) { @@ -11602,6 +11793,8 @@ rs6000_stack_info (void) else info_ptr->vrsave_size = 0; + compute_save_world_info (info_ptr); + /* Calculate the offsets. */ switch (DEFAULT_ABI) { @@ -12716,8 +12909,128 @@ rs6000_emit_prologue (void) rs6000_emit_stack_tie (); } + /* Handle world saves specially here. */ + if (info->world_save_p) + { + int i, j, sz; + rtx treg; + rtvec p; + + /* save_world expects lr in r0. */ + if (info->lr_save_p) + { + insn = emit_move_insn (gen_rtx_REG (Pmode, 0), + gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)); + RTX_FRAME_RELATED_P (insn) = 1; + } + + /* The SAVE_WORLD and RESTORE_WORLD routines make a number of + assumptions about the offsets of various bits of the stack + frame. Abort if things aren't what they should be. */ + if (info->gp_save_offset != -220 + || info->fp_save_offset != -144 + || info->lr_save_offset != 8 + || info->cr_save_offset != 4 + || !info->push_p + || !info->lr_save_p + || (current_function_calls_eh_return && info->ehrd_offset != -432) + || (info->vrsave_save_offset != -224 + || info->altivec_save_offset != (-224 -16 -192))) + abort (); + + treg = gen_rtx_REG (SImode, 11); + emit_move_insn (treg, GEN_INT (-info->total_size)); + + /* SAVE_WORLD takes the caller's LR in R0 and the frame size + in R11. It also clobbers R12, so beware! */ + + /* Preserve CR2 for save_world prologues */ + sz = 6; + sz += 32 - info->first_gp_reg_save; + sz += 64 - info->first_fp_reg_save; + sz += LAST_ALTIVEC_REGNO - info->first_altivec_reg_save + 1; + p = rtvec_alloc (sz); + j = 0; + RTVEC_ELT (p, j++) = gen_rtx_CLOBBER (VOIDmode, + gen_rtx_REG (Pmode, + LINK_REGISTER_REGNUM)); + RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode, + gen_rtx_SYMBOL_REF (Pmode, + "*save_world")); + /* We do floats first so that the instruction pattern matches + properly. */ + for (i = 0; i < 64 - info->first_fp_reg_save; i++) + { + rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i); + rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->fp_save_offset + + sp_offset + 8 * i)); + rtx mem = gen_rtx_MEM (DFmode, addr); + set_mem_alias_set (mem, rs6000_sr_alias_set); + + RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg); + } + for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++) + { + rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i); + rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->altivec_save_offset + + sp_offset + 16 * i)); + rtx mem = gen_rtx_MEM (V4SImode, addr); + set_mem_alias_set (mem, rs6000_sr_alias_set); + + RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg); + } + for (i = 0; i < 32 - info->first_gp_reg_save; i++) + { + rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i); + rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->gp_save_offset + + sp_offset + reg_size * i)); + rtx mem = gen_rtx_MEM (reg_mode, addr); + set_mem_alias_set (mem, rs6000_sr_alias_set); + + RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg); + } + + { + /* CR register traditionally saved as CR2. */ + rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO); + rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->cr_save_offset + + sp_offset)); + rtx mem = gen_rtx_MEM (reg_mode, addr); + set_mem_alias_set (mem, rs6000_sr_alias_set); + + RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg); + } + /* Prevent any attempt to delete the setting of r0 and treg! */ + RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 0)); + RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode, treg); + RTVEC_ELT (p, j++) = gen_rtx_CLOBBER (VOIDmode, sp_reg_rtx); + + insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p)); + rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, + NULL_RTX, NULL_RTX); + + if (current_function_calls_eh_return) + { + unsigned int i; + for (i = 0; ; ++i) + { + unsigned int regno = EH_RETURN_DATA_REGNO (i); + if (regno == INVALID_REGNUM) + break; + emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno, + info->ehrd_offset + sp_offset + + reg_size * (int) i, + info->total_size); + } + } + } + /* Save AltiVec registers if needed. */ - if (TARGET_ALTIVEC_ABI && info->altivec_size != 0) + if (! info->world_save_p && TARGET_ALTIVEC_ABI && info->altivec_size != 0) { int i; @@ -12758,7 +13071,7 @@ rs6000_emit_prologue (void) epilogue. */ if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE - && info->vrsave_mask != 0) + && ! info->world_save_p && info->vrsave_mask != 0) { rtx reg, mem, vrsave; int offset; @@ -12786,7 +13099,7 @@ rs6000_emit_prologue (void) } /* If we use the link register, get it into r0. */ - if (info->lr_save_p) + if (! info->world_save_p && info->lr_save_p) { insn = emit_move_insn (gen_rtx_REG (Pmode, 0), gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)); @@ -12794,7 +13107,7 @@ rs6000_emit_prologue (void) } /* If we need to save CR, put it into r12. */ - if (info->cr_save_p && frame_reg_rtx != frame_ptr_rtx) + if (! info->world_save_p && info->cr_save_p && frame_reg_rtx != frame_ptr_rtx) { rtx set; @@ -12816,7 +13129,7 @@ rs6000_emit_prologue (void) /* Do any required saving of fpr's. If only one or two to save, do it ourselves. Otherwise, call function. */ - if (saving_FPRs_inline) + if (! info->world_save_p && saving_FPRs_inline) { int i; for (i = 0; i < 64 - info->first_fp_reg_save; i++) @@ -12827,7 +13140,7 @@ rs6000_emit_prologue (void) info->fp_save_offset + sp_offset + 8 * i, info->total_size); } - else if (info->first_fp_reg_save != 64) + else if (! info->world_save_p && info->first_fp_reg_save != 64) { int i; char rname[30]; @@ -12863,7 +13176,7 @@ rs6000_emit_prologue (void) /* Save GPRs. This is done as a PARALLEL if we are using the store-multiple instructions. */ - if (using_store_multiple) + if (! info->world_save_p && using_store_multiple) { rtvec p; int i; @@ -12885,7 +13198,7 @@ rs6000_emit_prologue (void) rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, NULL_RTX, NULL_RTX); } - else + else if (! info->world_save_p) { int i; for (i = 0; i < 32 - info->first_gp_reg_save; i++) @@ -12944,7 +13257,7 @@ rs6000_emit_prologue (void) /* ??? There's no need to emit actual instructions here, but it's the easiest way to get the frame unwind information emitted. */ - if (current_function_calls_eh_return) + if (! info->world_save_p && current_function_calls_eh_return) { unsigned int i, regno; @@ -12979,7 +13292,7 @@ rs6000_emit_prologue (void) } /* Save lr if we used it. */ - if (info->lr_save_p) + if (! info->world_save_p && info->lr_save_p) { rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->lr_save_offset + sp_offset)); @@ -12994,7 +13307,7 @@ rs6000_emit_prologue (void) } /* Save CR if we use any that must be preserved. */ - if (info->cr_save_p) + if (! info->world_save_p && info->cr_save_p) { rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->cr_save_offset + sp_offset)); @@ -13027,7 +13340,7 @@ rs6000_emit_prologue (void) /* Update stack and set back pointer unless this is V.4, for which it was done previously. */ - if (info->push_p + if (! info->world_save_p && info->push_p && !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return)) rs6000_emit_allocate_stack (info->total_size, FALSE); @@ -13196,6 +13509,101 @@ rs6000_emit_epilogue (int sibcall) || rs6000_cpu == PROCESSOR_PPC750 || optimize_size); + if (info->world_save_p) + { + int i, j; + char rname[30]; + const char *alloc_rname; + rtvec p; + + /* eh_rest_world_r10 will return to the location saved in the LR + stack slot (which is not likely to be our caller.) + Input: R10 -- stack adjustment. Clobbers R0, R11, R12, R7, R8. + rest_world is similar, except any R10 parameter is ignored. + The exception-handling stuff that was here in 2.95 is no + longer necessary. */ + + p = rtvec_alloc (9 + + 1 + + 32 - info->first_gp_reg_save + + LAST_ALTIVEC_REGNO + 1 - info->first_altivec_reg_save + + 63 + 1 - info->first_fp_reg_save); + + strcpy (rname, (current_function_calls_eh_return) ? + "*eh_rest_world_r10" : "*rest_world"); + alloc_rname = ggc_strdup (rname); + + j = 0; + RTVEC_ELT (p, j++) = gen_rtx_RETURN (VOIDmode); + RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode, + gen_rtx_REG (Pmode, + LINK_REGISTER_REGNUM)); + RTVEC_ELT (p, j++) + = gen_rtx_USE (VOIDmode, gen_rtx_SYMBOL_REF (Pmode, alloc_rname)); + /* The instruction pattern requires a clobber here; + it is shared with the restVEC helper. */ + RTVEC_ELT (p, j++) + = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 11)); + + { + /* CR register traditionally saved as CR2. */ + rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO); + rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->cr_save_offset)); + rtx mem = gen_rtx_MEM (reg_mode, addr); + set_mem_alias_set (mem, rs6000_sr_alias_set); + + RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem); + } + + for (i = 0; i < 32 - info->first_gp_reg_save; i++) + { + rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i); + rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->gp_save_offset + + reg_size * i)); + rtx mem = gen_rtx_MEM (reg_mode, addr); + set_mem_alias_set (mem, rs6000_sr_alias_set); + + RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem); + } + for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++) + { + rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i); + rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->altivec_save_offset + + 16 * i)); + rtx mem = gen_rtx_MEM (V4SImode, addr); + set_mem_alias_set (mem, rs6000_sr_alias_set); + + RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem); + } + for (i = 0; info->first_fp_reg_save + i <= 63; i++) + { + rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i); + rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->fp_save_offset + + 8 * i)); + rtx mem = gen_rtx_MEM (DFmode, addr); + set_mem_alias_set (mem, rs6000_sr_alias_set); + + RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem); + } + RTVEC_ELT (p, j++) + = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 0)); + RTVEC_ELT (p, j++) + = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 12)); + RTVEC_ELT (p, j++) + = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 7)); + RTVEC_ELT (p, j++) + = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 8)); + RTVEC_ELT (p, j++) + = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, 10)); + emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p)); + + return; + } + /* If we have a frame pointer, a call to alloca, or a large stack frame, restore the old stack pointer using the backchain. Otherwise, we know what size to update it with. */ diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 6b3a36ceca1..1f5caaa96fc 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -916,6 +916,10 @@ extern const char *rs6000_warn_altivec_long_switch; #define SPE_ACC_REGNO 111 #define SPEFSCR_REGNO 112 +#define FIRST_SAVED_ALTIVEC_REGNO (FIRST_ALTIVEC_REGNO+20) +#define FIRST_SAVED_FP_REGNO (14+32) +#define FIRST_SAVED_GP_REGNO 13 + /* List the order in which to allocate registers. Each register must be listed once, even those in FIXED_REGISTERS. @@ -2587,6 +2591,8 @@ extern char rs6000_reg_names[][8]; /* register names (0 vs. %r0). */ {"lmw_operation", {PARALLEL}}, \ {"stmw_operation", {PARALLEL}}, \ {"vrsave_operation", {PARALLEL}}, \ + {"save_world_operation", {PARALLEL}}, \ + {"restore_world_operation", {PARALLEL}}, \ {"mfcr_operation", {PARALLEL}}, \ {"mtcrf_operation", {PARALLEL}}, \ {"branch_comparison_operator", {EQ, NE, LE, LT, GE, \