This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
ia64 eh, part 23
- To: gcc-patches at gcc dot gnu dot org
- Subject: ia64 eh, part 23
- From: Richard Henderson <rth at redhat dot com>
- Date: Wed, 28 Mar 2001 03:19:57 -0800
Update the powerpc port for the changes to eh_return.
r~
* 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.
Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.171
diff -c -p -d -r1.171 rs6000.c
*** rs6000.c 2001/03/22 18:48:51 1.171
--- rs6000.c 2001/03/28 11:15:43
*************** rs6000_stack_info ()
*** 4808,4813 ****
--- 4808,4814 ----
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 */
*************** rs6000_stack_info ()
*** 4860,4865 ****
--- 4861,4879 ----
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;
*************** rs6000_stack_info ()
*** 4868,4873 ****
--- 4882,4888 ----
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);
*************** rs6000_stack_info ()
*** 4883,4888 ****
--- 4898,4904 ----
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;
*************** rs6000_stack_info ()
*** 4893,4898 ****
--- 4909,4915 ----
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;
}
*************** rs6000_frame_related (insn, reg, val, re
*** 5585,5591 ****
/* Emit function prologue as insns. */
void
! rs6000_emit_prologue()
{
rs6000_stack_t *info = rs6000_stack_info ();
enum machine_mode reg_mode = TARGET_POWERPC64 ? DImode : SImode;
--- 5602,5608 ----
/* Emit function prologue as insns. */
void
! rs6000_emit_prologue ()
{
rs6000_stack_t *info = rs6000_stack_info ();
enum machine_mode reg_mode = TARGET_POWERPC64 ? DImode : SImode;
*************** rs6000_emit_prologue()
*** 5741,5746 ****
--- 5758,5788 ----
}
}
+ /* ??? 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)
{
*************** output_prolog (file, size)
*** 5876,5882 ****
need special notes to explain where r11 is in relation to the stack. */
void
! rs6000_emit_epilogue(sibcall)
int sibcall;
{
rs6000_stack_t *info;
--- 5918,5924 ----
need special notes to explain where r11 is in relation to the stack. */
void
! rs6000_emit_epilogue (sibcall)
int sibcall;
{
rs6000_stack_t *info;
*************** rs6000_emit_epilogue(sibcall)
*** 5895,5900 ****
--- 5937,5943 ----
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
*************** rs6000_emit_epilogue(sibcall)
*** 5960,5965 ****
--- 6003,6028 ----
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. */
*************** rs6000_emit_epilogue(sibcall)
*** 6093,6098 ****
--- 6156,6169 ----
: gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
GEN_INT (sp_offset)));
}
+ }
+
+ 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)
Index: config/rs6000/rs6000.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.h,v
retrieving revision 1.105
diff -c -p -d -r1.105 rs6000.h
*** rs6000.h 2001/02/08 20:30:16 1.105
--- rs6000.h 2001/03/28 11:15:43
*************** typedef struct rs6000_stack {
*** 1180,1185 ****
--- 1180,1186 ----
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 */
*************** typedef struct rs6000_args
*** 1569,1576 ****
and frame pointer registers are already be assumed to be used as
needed. */
! #define EPILOGUE_USES(REGNO) \
! (reload_completed && (REGNO) == LINK_REGISTER_REGNUM)
/* This macro generates the assembly code for function exit,
on machines that need it. If FUNCTION_EPILOGUE is not defined
--- 1570,1580 ----
and frame pointer registers are already be assumed to be used as
needed. */
! #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
*************** do { \
*** 2640,2645 ****
--- 2644,2653 ----
#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
Index: config/rs6000/rs6000.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.109
diff -c -p -d -r1.109 rs6000.md
*** rs6000.md 2001/03/08 05:44:49 1.109
--- rs6000.md 2001/03/28 11:15:43
*************** operands[2] = GEN_INT (INTVAL (operands[
*** 13381,13498 ****
"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"))]
""
"
{
! 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]));
else
! insn = emit_jump_insn (gen_return_eh_di (operands[2]));
! emit_barrier_after (insn);
!
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)]
! ""
! "")
(define_split
! [(unspec_volatile [(const_int 0)] 9)]
! "reload_completed && TARGET_SCHED_PROLOG"
! [(unspec_volatile [(const_int 0)] 9)]
"
{
! 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 \"\";
}")
-
-
- (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")])
-
- (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")])
--- 13381,13446 ----
"TARGET_64BIT"
"b %z2")
! ; This is used in compiling the unwind routines.
! (define_expand "eh_return"
! [(use (match_operand 0 "general_operand" ""))
! (use (match_operand 1 "general_operand" ""))]
""
"
{
! if (TARGET_TOC)
! rs6000_emit_eh_toc_restore (operands[0]);
! if (TARGET_32BIT)
! emit_insn (gen_eh_set_lr_si (operands[1]));
else
! 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 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 [(match_operand 0 "register_operand" "")] 9)
! (clobber (match_scratch 1 ""))]
! "reload_completed"
! [(const_int 0)]
"
{
! rs6000_stack_t *info = rs6000_stack_info ();
! if (info->lr_save_p)
! {
! rtx frame_rtx = stack_pointer_rtx;
! int sp_offset = 0;
! rtx tmp;
! 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;
! 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;
}")