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>
* 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.
......
......@@ -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;
......
......@@ -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
......
......@@ -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;
}")
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