diff options
author | Geoffrey Keating <geoffk@cygnus.com> | 2000-02-10 04:30:45 +0000 |
---|---|---|
committer | Geoffrey Keating <geoffk@cygnus.com> | 2000-02-10 04:30:45 +0000 |
commit | cf236edd44d3cb4a730b71389ca782959d925d4e (patch) | |
tree | b69f5e6438e0dc153cf3b4d75c4f0632864baea3 | |
parent | 355675ddb4b0006a3d3fe44a327aa5d4eccd26c4 (diff) |
* rs6000.h (INCOMING_RETURN_ADDR_RTX): New macro.
* aix.h (SETUP_FRAME_ADDRESSES): Define.
* rs6000.c [TARGET_AIX] (insn_after_throw): New static variable.
[TARGET_AIX] (rs6000_aix_emit_builtin_unwind_init): New function.
[TARGET_AIX] (rs6000_emit_eh_toc_restore): New function.
* rs6000-protos.h: Prototype rs6000_emit_eh_toc_restore,
rs6000_aix_emit_builtin_unwind_init.
* rs6000.md (eh_epilogue) [TARGET_AIX]: Call
rs6000_emit_eh_toc_restore on AIX.
(return_eh_si): Use r2.
(return_eh_di): Use r2.
* aix43.h: Turn on HAS_INIT_SECTION and LD_INIT_SWITCH,
since we're breaking binary compatibility anyway.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/newppc-branch@31882 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/config/rs6000/ChangeLog | 18 | ||||
-rw-r--r-- | gcc/config/rs6000/aix.h | 8 | ||||
-rw-r--r-- | gcc/config/rs6000/aix43.h | 2 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000-protos.h | 3 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 130 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.h | 6 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 7 |
7 files changed, 170 insertions, 4 deletions
diff --git a/gcc/config/rs6000/ChangeLog b/gcc/config/rs6000/ChangeLog index 1ab276c8fbd..96637cda885 100644 --- a/gcc/config/rs6000/ChangeLog +++ b/gcc/config/rs6000/ChangeLog @@ -1,3 +1,21 @@ +2000-02-09 Geoff Keating <geoffk@cygnus.com> + + * rs6000.h (INCOMING_RETURN_ADDR_RTX): New macro. + + * aix.h (SETUP_FRAME_ADDRESSES): Define. + * rs6000.c [TARGET_AIX] (insn_after_throw): New static variable. + [TARGET_AIX] (rs6000_aix_emit_builtin_unwind_init): New function. + [TARGET_AIX] (rs6000_emit_eh_toc_restore): New function. + * rs6000-protos.h: Prototype rs6000_emit_eh_toc_restore, + rs6000_aix_emit_builtin_unwind_init. + * rs6000.md (eh_epilogue) [TARGET_AIX]: Call + rs6000_emit_eh_toc_restore on AIX. + (return_eh_si): Use r2. + (return_eh_di): Use r2. + + * aix43.h: Turn on HAS_INIT_SECTION and LD_INIT_SWITCH, + since we're breaking binary compatibility anyway. + 2000-02-09 Clinton Popetz <cpopetz@cygnus.com> * config/rs6000/rs6000-protos.h: (get_TOC_alias_set, uses_TOC, diff --git a/gcc/config/rs6000/aix.h b/gcc/config/rs6000/aix.h index acc6d313bce..6a2eeb7b818 100644 --- a/gcc/config/rs6000/aix.h +++ b/gcc/config/rs6000/aix.h @@ -471,3 +471,11 @@ toc_section () \ /* dwarf2out keys off this, but we don't have to have a real definition. */ #define UNALIGNED_INT_ASM_OP bite_me + +/* __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 with his. */ +#define SETUP_FRAME_ADDRESSES() rs6000_aix_emit_builtin_unwind_init () + diff --git a/gcc/config/rs6000/aix43.h b/gcc/config/rs6000/aix43.h index 06b241e0773..3822c0a2aa3 100644 --- a/gcc/config/rs6000/aix43.h +++ b/gcc/config/rs6000/aix43.h @@ -197,7 +197,6 @@ do { \ #undef RS6000_CALL_GLUE #define RS6000_CALL_GLUE "{cror 31,31,31|nop}" -#if 0 /* AIX 4.2 and above provides initialization and finalization function support from linker command line. */ #undef HAS_INIT_SECTION @@ -205,4 +204,3 @@ do { \ #undef LD_INIT_SWITCH #define LD_INIT_SWITCH "-binitfini" -#endif diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h index 031a49bc797..87a0cf3b852 100644 --- a/gcc/config/rs6000/rs6000-protos.h +++ b/gcc/config/rs6000/rs6000-protos.h @@ -92,7 +92,7 @@ extern void rs6000_fatal_bad_address PARAMS ((rtx)); extern int stmw_operation PARAMS ((rtx, enum machine_mode)); extern int mtcrf_operation PARAMS ((rtx, enum machine_mode)); extern int lmw_operation PARAMS ((rtx, enum machine_mode)); - +extern void rs6000_emit_eh_toc_restore PARAMS ((rtx)); #endif /* RTX_CODE */ #ifdef TREE_CODE @@ -149,5 +149,6 @@ extern int uses_TOC PARAMS ((void)); extern struct rtx_def *create_TOC_reference PARAMS ((rtx)); extern void rs6000_emit_prologue PARAMS ((void)); extern void rs6000_emit_load_toc_table PARAMS ((int)); +extern void rs6000_aix_emit_builtin_unwind_init PARAMS ((void)); extern void rs6000_emit_epilogue PARAMS ((int)); extern void debug_stack_info PARAMS ((rs6000_stack_t *)); diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 41e9dffd810..ae3fce90027 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -4424,6 +4424,136 @@ create_TOC_reference(symbol) ggc_alloc_string (toc_label_name, -1))))); } +#if TARGET_AIX +/* __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. + + 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); + + 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, + 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, r2; + 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); + 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 (trunc_int_for_mode (TARGET_32BIT + ? 0x80410014 + : 0xE8410028, SImode))); + + if (insn_after_throw == NULL_RTX) + abort(); + emit_move_insn (opcode, insn_after_throw); + + emit_note (NULL_PTR, NOTE_INSN_LOOP_BEG); + emit_label (loop_start); + + do_compare_rtx_and_jump (opcode, tocompare, NE, 1, + SImode, NULL_RTX, 0, 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, 0, NULL_RTX, + loop_exit); + + mem = gen_rtx_MEM (Pmode, bottom_of_stack); + 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)); + + emit_note (NULL_PTR, NOTE_INSN_LOOP_CONT); + emit_jump (loop_start); + emit_note (NULL_PTR, NOTE_INSN_LOOP_END); + emit_label (loop_exit); +} +#endif /* TARGET_AIX */ /* This ties together stack memory (MEM with an alias set of rs6000_sr_alias_set) diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 20710f28682..26ac7465409 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -2790,6 +2790,12 @@ do { \ #define ASM_OPEN_PAREN "(" #define ASM_CLOSE_PAREN ")" +/* Pick up the return address upon entry to a procedure. Used for + dwarf2 unwind information. This also enables the table driven + mechanism. */ + +#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM) + /* Define results of standard character escape sequences. */ #define TARGET_BELL 007 #define TARGET_BS 010 diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index d5b0b3f81bc..7c59a797f63 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -25,7 +25,6 @@ ;; Number Use ;; 0 frsp for POWER machines ;; 0/v blockage -;; 1/v nonlocal_goto_receiver for MINIMAL_TOC ;; 5 used to tie the stack contents and the stack pointer ;; 6 address of a word pointing to the TOC ;; 7 address of the TOC (more-or-less) @@ -11237,6 +11236,10 @@ operands[2] = r; } +#if TARGET_AIX + rs6000_emit_eh_toc_restore (operands[1]); +#endif + emit_insn (gen_eh_reg_restore ()); if (Pmode == SImode) @@ -11300,6 +11303,7 @@ (define_insn "return_eh_si" [(use (match_operand:SI 0 "register_operand" "l,c")) (return) + (use (reg:SI 2)) (use (reg:SI 3))] "TARGET_32BIT" "@ @@ -11310,6 +11314,7 @@ (define_insn "return_eh_di" [(use (match_operand:DI 0 "register_operand" "l,c")) (return) + (use (reg:DI 2)) (use (reg:DI 3))] "TARGET_64BIT" "@ |