Commit 83720594 by Richard Henderson Committed by Richard Henderson

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
parent 1020a5ab
2001-03-28 Richard Henderson <rth@redhat.com> 2001-03-28 Richard Henderson <rth@redhat.com>
* 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. * config/i386/i386.c (general_no_elim_operand): Disallow virtual regs.
(ix86_save_reg): If maybe_eh_return, true for EH_RETURN_DATA_REGNOs. (ix86_save_reg): If maybe_eh_return, true for EH_RETURN_DATA_REGNOs.
True for pic register if current_function_calls_eh_return. True for pic register if current_function_calls_eh_return.
......
...@@ -4808,6 +4808,7 @@ rs6000_stack_info () ...@@ -4808,6 +4808,7 @@ rs6000_stack_info ()
rs6000_stack_t *info_ptr = &info; rs6000_stack_t *info_ptr = &info;
int reg_size = TARGET_POWERPC64 ? 8 : 4; int reg_size = TARGET_POWERPC64 ? 8 : 4;
enum rs6000_abi abi; enum rs6000_abi abi;
int ehrd_size;
int total_raw_size; int total_raw_size;
/* Zero all fields portably */ /* Zero all fields portably */
...@@ -4860,6 +4861,19 @@ rs6000_stack_info () ...@@ -4860,6 +4861,19 @@ rs6000_stack_info ()
info_ptr->cr_size = reg_size; 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 */ /* Determine various sizes */
info_ptr->reg_size = reg_size; info_ptr->reg_size = reg_size;
info_ptr->fixed_size = RS6000_SAVE_AREA; info_ptr->fixed_size = RS6000_SAVE_AREA;
...@@ -4868,6 +4882,7 @@ rs6000_stack_info () ...@@ -4868,6 +4882,7 @@ rs6000_stack_info ()
info_ptr->parm_size = RS6000_ALIGN (current_function_outgoing_args_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->save_size = RS6000_ALIGN (info_ptr->fp_size
+ info_ptr->gp_size + info_ptr->gp_size
+ ehrd_size
+ info_ptr->cr_size + info_ptr->cr_size
+ info_ptr->lr_size + info_ptr->lr_size
+ info_ptr->toc_size, 8); + info_ptr->toc_size, 8);
...@@ -4883,6 +4898,7 @@ rs6000_stack_info () ...@@ -4883,6 +4898,7 @@ rs6000_stack_info ()
case ABI_AIX_NODESC: case ABI_AIX_NODESC:
info_ptr->fp_save_offset = - info_ptr->fp_size; 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->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->cr_save_offset = reg_size; /* first word when 64-bit. */
info_ptr->lr_save_offset = 2*reg_size; info_ptr->lr_save_offset = 2*reg_size;
break; break;
...@@ -4893,6 +4909,7 @@ rs6000_stack_info () ...@@ -4893,6 +4909,7 @@ rs6000_stack_info ()
info_ptr->gp_save_offset = info_ptr->fp_save_offset - info_ptr->gp_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->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->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; info_ptr->lr_save_offset = reg_size;
break; break;
} }
...@@ -5585,7 +5602,7 @@ rs6000_frame_related (insn, reg, val, reg2, rreg) ...@@ -5585,7 +5602,7 @@ rs6000_frame_related (insn, reg, val, reg2, rreg)
/* Emit function prologue as insns. */ /* Emit function prologue as insns. */
void void
rs6000_emit_prologue() rs6000_emit_prologue ()
{ {
rs6000_stack_t *info = rs6000_stack_info (); rs6000_stack_t *info = rs6000_stack_info ();
enum machine_mode reg_mode = TARGET_POWERPC64 ? DImode : SImode; enum machine_mode reg_mode = TARGET_POWERPC64 ? DImode : SImode;
...@@ -5741,6 +5758,31 @@ rs6000_emit_prologue() ...@@ -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. */ /* Save lr if we used it. */
if (info->lr_save_p) if (info->lr_save_p)
{ {
...@@ -5876,7 +5918,7 @@ output_prolog (file, size) ...@@ -5876,7 +5918,7 @@ output_prolog (file, size)
need special notes to explain where r11 is in relation to the stack. */ need special notes to explain where r11 is in relation to the stack. */
void void
rs6000_emit_epilogue(sibcall) rs6000_emit_epilogue (sibcall)
int sibcall; int sibcall;
{ {
rs6000_stack_t *info; rs6000_stack_t *info;
...@@ -5895,6 +5937,7 @@ rs6000_emit_epilogue(sibcall) ...@@ -5895,6 +5937,7 @@ rs6000_emit_epilogue(sibcall)
using_load_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64 using_load_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
&& info->first_gp_reg_save < 31); && info->first_gp_reg_save < 31);
restoring_FPRs_inline = (sibcall restoring_FPRs_inline = (sibcall
|| current_function_calls_eh_return
|| info->first_fp_reg_save == 64 || info->first_fp_reg_save == 64
|| FP_SAVE_INLINE (info->first_fp_reg_save)); || FP_SAVE_INLINE (info->first_fp_reg_save));
use_backchain_to_restore_sp = (frame_pointer_needed use_backchain_to_restore_sp = (frame_pointer_needed
...@@ -5960,6 +6003,26 @@ rs6000_emit_epilogue(sibcall) ...@@ -5960,6 +6003,26 @@ rs6000_emit_epilogue(sibcall)
emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM),
gen_rtx_REG (Pmode, 0)); 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 /* Restore GPRs. This is done as a PARALLEL if we are using
the load-multiple instructions. */ the load-multiple instructions. */
...@@ -6095,6 +6158,14 @@ rs6000_emit_epilogue(sibcall) ...@@ -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) if (!sibcall)
{ {
rtvec p; rtvec p;
......
...@@ -1180,6 +1180,7 @@ typedef struct rs6000_stack { ...@@ -1180,6 +1180,7 @@ typedef struct rs6000_stack {
int cr_save_offset; /* offset to save CR from initial SP */ int cr_save_offset; /* offset to save CR from initial SP */
int toc_save_offset; /* offset to save the TOC pointer */ int toc_save_offset; /* offset to save the TOC pointer */
int varargs_save_offset; /* offset to save the varargs registers */ 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 reg_size; /* register size (4 or 8) */
int varargs_size; /* size to hold V.4 args passed in regs */ int varargs_size; /* size to hold V.4 args passed in regs */
int vars_size; /* variable save area size */ int vars_size; /* variable save area size */
...@@ -1569,8 +1570,11 @@ typedef struct rs6000_args ...@@ -1569,8 +1570,11 @@ typedef struct rs6000_args
and frame pointer registers are already be assumed to be used as and frame pointer registers are already be assumed to be used as
needed. */ needed. */
#define EPILOGUE_USES(REGNO) \ #define EPILOGUE_USES(REGNO) \
(reload_completed && (REGNO) == LINK_REGISTER_REGNUM) ((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, /* This macro generates the assembly code for function exit,
on machines that need it. If FUNCTION_EPILOGUE is not defined on machines that need it. If FUNCTION_EPILOGUE is not defined
...@@ -2641,6 +2645,10 @@ do { \ ...@@ -2641,6 +2645,10 @@ do { \
#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM) #define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (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 results of standard character escape sequences. */
#define TARGET_BELL 007 #define TARGET_BELL 007
#define TARGET_BS 010 #define TARGET_BS 010
......
...@@ -13381,118 +13381,66 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32); ...@@ -13381,118 +13381,66 @@ operands[2] = GEN_INT (INTVAL (operands[1]) >> 32);
"TARGET_64BIT" "TARGET_64BIT"
"b %z2") "b %z2")
; This is used in compiling the routines __throw and __rethrow. ; This is used in compiling the unwind routines.
; It's a little different to the usual definition... (define_expand "eh_return"
[(use (match_operand 0 "general_operand" ""))
(define_expand "eh_epilogue" (use (match_operand 1 "general_operand" ""))]
[(use (match_operand 0 "general_operand" "r"))
(use (match_operand 1 "general_operand" "r"))
(use (match_operand 2 "general_operand" "c"))]
"" ""
" "
{ {
rtx stack_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM); if (TARGET_TOC)
rtx insn; rs6000_emit_eh_toc_restore (operands[0]);
if (TARGET_32BIT)
/* This is required for binary compatibility. If it's wrong, emit_insn (gen_eh_set_lr_si (operands[1]));
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]));
else else
insn = emit_jump_insn (gen_return_eh_di (operands[2])); emit_insn (gen_eh_set_lr_di (operands[1]));
emit_barrier_after (insn); emit_move_insn (EH_RETURN_STACKADJ_RTX, operands[0]);
DONE; DONE;
}") }")
; We can't expand this before we know which registers are restored, ; We can't expand this before we know where the link register is stored.
; but we do want to expand it before flow2 because that way flow2 can (define_insn "eh_set_lr_si"
; remove the redundant loads of the link register. [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] 9)
(define_expand "eh_reg_restore" (clobber (match_scratch:SI 1 "=&r"))]
[(unspec_volatile [(const_int 0)] 9)] "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 (define_split
[(unspec_volatile [(const_int 0)] 9)] [(unspec_volatile [(match_operand 0 "register_operand" "")] 9)
"reload_completed && TARGET_SCHED_PROLOG" (clobber (match_scratch 1 ""))]
[(unspec_volatile [(const_int 0)] 9)] "reload_completed"
[(const_int 0)]
" "
{ {
rs6000_emit_epilogue (TRUE); rs6000_stack_t *info = rs6000_stack_info ();
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 \"\";
}")
if (info->lr_save_p)
{
rtx frame_rtx = stack_pointer_rtx;
int sp_offset = 0;
rtx tmp;
(define_insn "return_eh_si" if (frame_pointer_needed
[(return) || current_function_calls_alloca
(use (match_operand:SI 0 "register_operand" "lc")) || info->total_size > 32767)
(use (reg:SI 2)) {
(use (reg:SI 3))] emit_move_insn (operands[1], gen_rtx_MEM (Pmode, frame_rtx));
"TARGET_32BIT" frame_rtx = operands[1];
"b%T0" }
[(set_attr "type" "jmpreg")]) else if (info->push_p)
sp_offset = info->total_size;
(define_insn "return_eh_di" tmp = plus_constant (frame_rtx, info->lr_save_offset + sp_offset);
[(return) tmp = gen_rtx_MEM (Pmode, tmp);
(use (match_operand:DI 0 "register_operand" "lc")) emit_move_insn (tmp, operands[0]);
(use (reg:DI 2)) }
(use (reg:DI 3))] else
"TARGET_64BIT" emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), operands[0]);
"b%T0" DONE;
[(set_attr "type" "jmpreg")]) }")
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment