diff options
Diffstat (limited to 'gcc/config/rs6000/rs6000.c')
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 166 |
1 files changed, 53 insertions, 113 deletions
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index fa296d5db94..8f268974aa5 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -10800,132 +10800,40 @@ create_TOC_reference (symbol) gen_rtx_SYMBOL_REF (Pmode, toc_label_name)))); } -/* __throw will restore its own return address to be the same as the - return address of the function that the throw is being made to. - This is unfortunate, because we want to check the original - return address to see if we need to restore the TOC. - So we have to squirrel it away here. - This is used only in compiling __throw and __rethrow. +/* If _Unwind_* has been called from within the same module, + toc register is not guaranteed to be saved to 40(1) on function + entry. Save it there in that case. */ - Most of this code should be removed by CSE. */ -static rtx insn_after_throw; - -/* This does the saving... */ void rs6000_aix_emit_builtin_unwind_init () { rtx mem; rtx stack_top = gen_reg_rtx (Pmode); rtx opcode_addr = gen_reg_rtx (Pmode); - - insn_after_throw = gen_reg_rtx (SImode); + rtx opcode = gen_reg_rtx (SImode); + rtx tocompare = gen_reg_rtx (SImode); + rtx no_toc_save_needed = gen_label_rtx (); mem = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx); emit_move_insn (stack_top, mem); - mem = gen_rtx_MEM (Pmode, - gen_rtx_PLUS (Pmode, stack_top, + mem = gen_rtx_MEM (Pmode, + gen_rtx_PLUS (Pmode, stack_top, GEN_INT (2 * GET_MODE_SIZE (Pmode)))); emit_move_insn (opcode_addr, mem); - emit_move_insn (insn_after_throw, gen_rtx_MEM (SImode, opcode_addr)); -} - -/* Emit insns to _restore_ the TOC register, at runtime (specifically - in _eh.o). Only used on AIX. - - The idea is that on AIX, function calls look like this: - bl somefunction-trampoline - lwz r2,20(sp) - - and later, - somefunction-trampoline: - stw r2,20(sp) - ... load function address in the count register ... - bctr - or like this, if the linker determines that this is not a cross-module call - and so the TOC need not be restored: - bl somefunction - nop - or like this, if the compiler could determine that this is not a - cross-module call: - bl somefunction - now, the tricky bit here is that register 2 is saved and restored - by the _linker_, so we can't readily generate debugging information - for it. So we need to go back up the call chain looking at the - insns at return addresses to see which calls saved the TOC register - and so see where it gets restored from. - - Oh, and all this gets done in RTL inside the eh_epilogue pattern, - just before the actual epilogue. - - On the bright side, this incurs no space or time overhead unless an - exception is thrown, except for the extra code in libgcc.a. - - The parameter STACKSIZE is a register containing (at runtime) - the amount to be popped off the stack in addition to the stack frame - of this routine (which will be __throw or __rethrow, and so is - guaranteed to have a stack frame). */ - -void -rs6000_emit_eh_toc_restore (stacksize) - rtx stacksize; -{ - rtx top_of_stack; - rtx bottom_of_stack = gen_reg_rtx (Pmode); - rtx tocompare = gen_reg_rtx (SImode); - rtx opcode = gen_reg_rtx (SImode); - rtx opcode_addr = gen_reg_rtx (Pmode); - rtx mem; - rtx loop_start = gen_label_rtx (); - rtx no_toc_restore_needed = gen_label_rtx (); - rtx loop_exit = gen_label_rtx (); - - mem = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx); - set_mem_alias_set (mem, rs6000_sr_alias_set); - emit_move_insn (bottom_of_stack, mem); - - top_of_stack = expand_binop (Pmode, add_optab, - bottom_of_stack, stacksize, - NULL_RTX, 1, OPTAB_WIDEN); - - emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014 + emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr)); + emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014 : 0xE8410028, SImode)); - if (insn_after_throw == NULL_RTX) - abort (); - emit_move_insn (opcode, insn_after_throw); - - emit_note (NOTE_INSN_LOOP_BEG); - emit_label (loop_start); - - do_compare_rtx_and_jump (opcode, tocompare, NE, 1, + do_compare_rtx_and_jump (opcode, tocompare, EQ, 1, SImode, NULL_RTX, NULL_RTX, - no_toc_restore_needed); - - mem = gen_rtx_MEM (Pmode, - gen_rtx_PLUS (Pmode, bottom_of_stack, - GEN_INT (5 * GET_MODE_SIZE (Pmode)))); - emit_move_insn (gen_rtx_REG (Pmode, 2), mem); - - emit_label (no_toc_restore_needed); - do_compare_rtx_and_jump (top_of_stack, bottom_of_stack, EQ, 1, - Pmode, NULL_RTX, NULL_RTX, - loop_exit); - - mem = gen_rtx_MEM (Pmode, bottom_of_stack); - set_mem_alias_set (mem, rs6000_sr_alias_set); - emit_move_insn (bottom_of_stack, mem); - - mem = gen_rtx_MEM (Pmode, - gen_rtx_PLUS (Pmode, bottom_of_stack, - GEN_INT (2 * GET_MODE_SIZE (Pmode)))); - emit_move_insn (opcode_addr, mem); - emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr)); + no_toc_save_needed); - emit_note (NOTE_INSN_LOOP_CONT); - emit_jump (loop_start); - emit_note (NOTE_INSN_LOOP_END); - emit_label (loop_exit); + mem = gen_rtx_MEM (Pmode, + gen_rtx_PLUS (Pmode, stack_top, + GEN_INT (5 * GET_MODE_SIZE (Pmode)))); + emit_move_insn (mem, gen_rtx_REG (Pmode, 2)); + emit_label (no_toc_save_needed); } /* This ties together stack memory (MEM with an alias set of @@ -11347,7 +11255,8 @@ rs6000_emit_prologue () || FP_SAVE_INLINE (info->first_fp_reg_save)); /* For V.4, update stack before we do any saving and set back pointer. */ - if (info->push_p && DEFAULT_ABI == ABI_V4) + if (info->push_p + && (DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return)) { if (info->total_size < 32767) sp_offset = info->total_size; @@ -11575,6 +11484,23 @@ rs6000_emit_prologue () { unsigned int i, regno; + /* In AIX ABI we need to pretend we save r2 here. */ + if (TARGET_AIX) + { + rtx addr, reg, mem; + + reg = gen_rtx_REG (reg_mode, 2); + addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (sp_offset + 5 * reg_size)); + mem = gen_rtx_MEM (reg_mode, addr); + set_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); + PATTERN (insn) = gen_blockage (); + } + for (i = 0; ; ++i) { regno = EH_RETURN_DATA_REGNO (i); @@ -11633,7 +11559,8 @@ rs6000_emit_prologue () /* Update stack and set back pointer unless this is V.4, for which it was done previously. */ - if (info->push_p && DEFAULT_ABI != ABI_V4) + if (info->push_p + && !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return)) rs6000_emit_allocate_stack (info->total_size, FALSE); /* Set frame pointer, if needed. */ @@ -11812,7 +11739,8 @@ rs6000_emit_epilogue (sibcall) } else if (info->push_p) { - if (DEFAULT_ABI == ABI_V4) + if (DEFAULT_ABI == ABI_V4 + || current_function_calls_eh_return) sp_offset = info->total_size; else { @@ -11897,6 +11825,17 @@ rs6000_emit_epilogue (sibcall) { unsigned int i, regno; + if (TARGET_AIX) + { + rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (sp_offset + 5 * reg_size)); + rtx mem = gen_rtx_MEM (reg_mode, addr); + + set_mem_alias_set (mem, rs6000_sr_alias_set); + + emit_move_insn (gen_rtx_REG (reg_mode, 2), mem); + } + for (i = 0; ; ++i) { rtx mem; @@ -12048,7 +11987,8 @@ rs6000_emit_epilogue (sibcall) (which may not have any obvious dependency on the stack). This doesn't hurt performance, because there is no scheduling that can be done after this point. */ - if (DEFAULT_ABI == ABI_V4) + if (DEFAULT_ABI == ABI_V4 + || current_function_calls_eh_return) { if (frame_reg_rtx != sp_reg_rtx) rs6000_emit_stack_tie (); |