From 83720594cedb0b10abc4c0e28b8ec71e8a5f999d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 28 Mar 2001 03:19:20 -0800 Subject: [PATCH] rs6000.c (rs6000_stack_info): Allocate space for eh_return data registers. * config/rs6000/rs6000.c (rs6000_stack_info): Allocate space for eh_return data registers. (rs6000_emit_prologue): Save eh_return data registers. (rs6000_emit_epilogue): Force inline restores if eh_return. Restore eh_return data registers. Mind EH_RETURN_STACKADJ_RTX. * config/rs6000/rs6000.h (rs6000_stack_t): Add ehrd_offset. (EH_RETURN_DATA_REGNO, EH_RETURN_STACKADJ_RTX): New. (EPILOGUE_USES): True for TOC_REGISTER if calls_eh_return and the target uses one. * config/rs6000/rs6000.md (eh_epilogue, eh_reg_restore): Remove. (return_eh_si, return_eh_di): Remove. (eh_return): New, from corpse of eh_epilogue. (eh_set_lr_si, eh_set_lr_di): New. From-SVN: r40927 --- gcc/ChangeLog | 14 ++++ gcc/config/rs6000/rs6000.c | 75 +++++++++++++++++- gcc/config/rs6000/rs6000.h | 12 ++- gcc/config/rs6000/rs6000.md | 150 ++++++++++++------------------------ 4 files changed, 146 insertions(+), 105 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c94073eded9..b6d3eb9f2e5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,19 @@ 2001-03-28 Richard Henderson + * config/rs6000/rs6000.c (rs6000_stack_info): Allocate space + for eh_return data registers. + (rs6000_emit_prologue): Save eh_return data registers. + (rs6000_emit_epilogue): Force inline restores if eh_return. + Restore eh_return data registers. Mind EH_RETURN_STACKADJ_RTX. + * config/rs6000/rs6000.h (rs6000_stack_t): Add ehrd_offset. + (EH_RETURN_DATA_REGNO, EH_RETURN_STACKADJ_RTX): New. + (EPILOGUE_USES): True for TOC_REGISTER if calls_eh_return and + the target uses one. + * config/rs6000/rs6000.md (eh_epilogue, eh_reg_restore): Remove. + (return_eh_si, return_eh_di): Remove. + (eh_return): New, from corpse of eh_epilogue. + (eh_set_lr_si, eh_set_lr_di): New. + * config/i386/i386.c (general_no_elim_operand): Disallow virtual regs. (ix86_save_reg): If maybe_eh_return, true for EH_RETURN_DATA_REGNOs. True for pic register if current_function_calls_eh_return. diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index ea42bf53899..4b24bfb800f 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -4808,6 +4808,7 @@ rs6000_stack_info () rs6000_stack_t *info_ptr = &info; int reg_size = TARGET_POWERPC64 ? 8 : 4; enum rs6000_abi abi; + int ehrd_size; int total_raw_size; /* Zero all fields portably */ @@ -4860,6 +4861,19 @@ rs6000_stack_info () info_ptr->cr_size = reg_size; } + /* If the current function calls __builtin_eh_return, then we need + to allocate stack space for registers that will hold data for + the exception handler. */ + if (current_function_calls_eh_return) + { + unsigned int i; + for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i) + continue; + ehrd_size = i * UNITS_PER_WORD; + } + else + ehrd_size = 0; + /* Determine various sizes */ info_ptr->reg_size = reg_size; info_ptr->fixed_size = RS6000_SAVE_AREA; @@ -4868,6 +4882,7 @@ rs6000_stack_info () 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); @@ -4883,6 +4898,7 @@ rs6000_stack_info () case ABI_AIX_NODESC: 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; @@ -4893,6 +4909,7 @@ rs6000_stack_info () 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; } @@ -5585,7 +5602,7 @@ rs6000_frame_related (insn, reg, val, reg2, rreg) /* Emit function prologue as insns. */ void -rs6000_emit_prologue() +rs6000_emit_prologue () { rs6000_stack_t *info = rs6000_stack_info (); enum machine_mode reg_mode = TARGET_POWERPC64 ? DImode : SImode; @@ -5741,6 +5758,31 @@ rs6000_emit_prologue() } } + /* ??? 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) + { + unsigned int i, regno; + for (i = 0; ; ++i) + { + rtx addr, reg, mem; + + regno = EH_RETURN_DATA_REGNO (i); + if (regno == INVALID_REGNUM) + break; + + reg = gen_rtx_REG (reg_mode, regno); + addr = plus_constant (frame_reg_rtx, + info->ehrd_offset + sp_offset + reg_size * i); + mem = gen_rtx_MEM (reg_mode, addr); + 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); + } + } + /* Save lr if we used it. */ if (info->lr_save_p) { @@ -5876,7 +5918,7 @@ output_prolog (file, size) need special notes to explain where r11 is in relation to the stack. */ void -rs6000_emit_epilogue(sibcall) +rs6000_emit_epilogue (sibcall) int sibcall; { rs6000_stack_t *info; @@ -5895,6 +5937,7 @@ rs6000_emit_epilogue(sibcall) using_load_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64 && info->first_gp_reg_save < 31); restoring_FPRs_inline = (sibcall + || current_function_calls_eh_return || info->first_fp_reg_save == 64 || FP_SAVE_INLINE (info->first_fp_reg_save)); use_backchain_to_restore_sp = (frame_pointer_needed @@ -5960,6 +6003,26 @@ rs6000_emit_epilogue(sibcall) emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), gen_rtx_REG (Pmode, 0)); + /* Load exception handler data registers, if needed. */ + if (current_function_calls_eh_return) + { + unsigned int i, regno; + for (i = 0; ; ++i) + { + rtx addr, mem; + + regno = EH_RETURN_DATA_REGNO (i); + if (regno == INVALID_REGNUM) + break; + + addr = plus_constant (frame_reg_rtx, + info->ehrd_offset + sp_offset + reg_size * i); + mem = gen_rtx_MEM (reg_mode, addr); + MEM_ALIAS_SET (mem) = rs6000_sr_alias_set; + + emit_move_insn (gen_rtx_REG (reg_mode, regno), mem); + } + } /* Restore GPRs. This is done as a PARALLEL if we are using the load-multiple instructions. */ @@ -6095,6 +6158,14 @@ rs6000_emit_epilogue(sibcall) } } + if (current_function_calls_eh_return) + { + rtx sa = EH_RETURN_STACKADJ_RTX; + emit_insn (Pmode == SImode + ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx, sa) + : gen_adddi3 (sp_reg_rtx, sp_reg_rtx, sa)); + } + if (!sibcall) { rtvec p; diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index fc70c506c3a..a520b57cce7 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -1180,6 +1180,7 @@ typedef struct rs6000_stack { int cr_save_offset; /* offset to save CR 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 */ int reg_size; /* register size (4 or 8) */ int varargs_size; /* size to hold V.4 args passed in regs */ int vars_size; /* variable save area size */ @@ -1569,8 +1570,11 @@ typedef struct rs6000_args and frame pointer registers are already be assumed to be used as needed. */ -#define EPILOGUE_USES(REGNO) \ - (reload_completed && (REGNO) == LINK_REGISTER_REGNUM) +#define EPILOGUE_USES(REGNO) \ + ((reload_completed && (REGNO) == LINK_REGISTER_REGNUM) \ + || (current_function_calls_eh_return \ + && TARGET_TOC \ + && (REGNO) == TOC_REGISTER)) /* This macro generates the assembly code for function exit, on machines that need it. If FUNCTION_EPILOGUE is not defined @@ -2641,6 +2645,10 @@ do { \ #define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM) #define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (LINK_REGISTER_REGNUM) +/* Describe how we implement __builtin_eh_return. */ +#define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 3 : INVALID_REGNUM) +#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, 10) + /* Define results of standard character escape sequences. */ #define TARGET_BELL 007 #define TARGET_BS 010 diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 1629d0a3c80..e92cbc8703b 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -13381,118 +13381,66 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); "TARGET_64BIT" "b %z2") -; This is used in compiling the routines __throw and __rethrow. -; It's a little different to the usual definition... - -(define_expand "eh_epilogue" - [(use (match_operand 0 "general_operand" "r")) - (use (match_operand 1 "general_operand" "r")) - (use (match_operand 2 "general_operand" "c"))] +; This is used in compiling the unwind routines. +(define_expand "eh_return" + [(use (match_operand 0 "general_operand" "")) + (use (match_operand 1 "general_operand" ""))] "" " { - rtx stack_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); - rtx insn; - - /* This is required for binary compatibility. If it's wrong, - it probably means that eh_regs() in except.c is broken. */ - if (GET_CODE (operands[0]) != REG || REGNO (operands[0]) != 3) - abort(); - - /* These can be anything that doesn't interfere with the epilogue. */ - if (GET_CODE (operands[1]) != REG || REGNO (operands[1]) != 4) - { - rtx r = gen_rtx_REG (Pmode, 4); - emit_move_insn (r, operands[1]); - operands[1] = r; - } - - if (GET_CODE (operands[2]) != REG - || REGNO (operands[2]) != COUNT_REGISTER_REGNUM) - { - rtx r = gen_rtx_REG (Pmode, COUNT_REGISTER_REGNUM); - emit_move_insn (r, operands[2]); - operands[2] = r; - } - -#if TARGET_AIX - rs6000_emit_eh_toc_restore (operands[1]); -#endif - - emit_insn (gen_eh_reg_restore ()); - - if (Pmode == SImode) - emit_insn (gen_addsi3 (stack_reg, stack_reg, operands[1])); - else - emit_insn (gen_adddi3 (stack_reg, stack_reg, operands[1])); - - if (Pmode == SImode) - insn = emit_jump_insn (gen_return_eh_si (operands[2])); + if (TARGET_TOC) + rs6000_emit_eh_toc_restore (operands[0]); + if (TARGET_32BIT) + emit_insn (gen_eh_set_lr_si (operands[1])); else - insn = emit_jump_insn (gen_return_eh_di (operands[2])); - emit_barrier_after (insn); - + emit_insn (gen_eh_set_lr_di (operands[1])); + emit_move_insn (EH_RETURN_STACKADJ_RTX, operands[0]); DONE; }") -; We can't expand this before we know which registers are restored, -; but we do want to expand it before flow2 because that way flow2 can -; remove the redundant loads of the link register. -(define_expand "eh_reg_restore" - [(unspec_volatile [(const_int 0)] 9)] - "" - "") +; We can't expand this before we know where the link register is stored. +(define_insn "eh_set_lr_si" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] 9) + (clobber (match_scratch:SI 1 "=&r"))] + "TARGET_32BIT" + "#") + +(define_insn "eh_set_lr_di" + [(unspec_volatile [(match_operand:DI 0 "register_operand" "r")] 9) + (clobber (match_scratch:DI 1 "=&r"))] + "TARGET_64BIT" + "#") (define_split - [(unspec_volatile [(const_int 0)] 9)] - "reload_completed && TARGET_SCHED_PROLOG" - [(unspec_volatile [(const_int 0)] 9)] + [(unspec_volatile [(match_operand 0 "register_operand" "")] 9) + (clobber (match_scratch 1 ""))] + "reload_completed" + [(const_int 0)] " { - rs6000_emit_epilogue (TRUE); - DONE; -}") - -(define_insn "" - [(unspec_volatile [(const_int 0)] 9)] - "" - "* -{ - if (TARGET_SCHED_PROLOG) - return \"#\"; - - /* This is slightly ugly, but at least we don't have multiple - copies of the epilogue-emitting code. */ - start_sequence (); - - /* A NOTE_INSN_DELETED is supposed to be at the start - and end of the \"toplevel\" insn chain. */ - emit_note (0, NOTE_INSN_DELETED); - rs6000_emit_epilogue (TRUE); - emit_note (0, NOTE_INSN_DELETED); - - if (TARGET_DEBUG_STACK) - debug_rtx_list (get_insns(), 100); - final (get_insns(), asm_out_file, FALSE, FALSE); - end_sequence (); - return \"\"; -}") + rs6000_stack_t *info = rs6000_stack_info (); + if (info->lr_save_p) + { + rtx frame_rtx = stack_pointer_rtx; + int sp_offset = 0; + rtx tmp; -(define_insn "return_eh_si" - [(return) - (use (match_operand:SI 0 "register_operand" "lc")) - (use (reg:SI 2)) - (use (reg:SI 3))] - "TARGET_32BIT" - "b%T0" - [(set_attr "type" "jmpreg")]) + if (frame_pointer_needed + || current_function_calls_alloca + || info->total_size > 32767) + { + emit_move_insn (operands[1], gen_rtx_MEM (Pmode, frame_rtx)); + frame_rtx = operands[1]; + } + else if (info->push_p) + sp_offset = info->total_size; -(define_insn "return_eh_di" - [(return) - (use (match_operand:DI 0 "register_operand" "lc")) - (use (reg:DI 2)) - (use (reg:DI 3))] - "TARGET_64BIT" - "b%T0" - [(set_attr "type" "jmpreg")]) + tmp = plus_constant (frame_rtx, info->lr_save_offset + sp_offset); + tmp = gen_rtx_MEM (Pmode, tmp); + emit_move_insn (tmp, operands[0]); + } + else + emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), operands[0]); + DONE; +}") -- 2.30.2