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.
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 */
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;
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);
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;
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;
}
/* 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;
}
}
+ /* ??? 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)
{
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;
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
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. */
}
}
+ 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;
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 */
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
#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
"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;
+}")