aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeoffrey Keating <geoffk@cygnus.com>2000-02-10 04:30:45 +0000
committerGeoffrey Keating <geoffk@cygnus.com>2000-02-10 04:30:45 +0000
commitcf236edd44d3cb4a730b71389ca782959d925d4e (patch)
treeb69f5e6438e0dc153cf3b4d75c4f0632864baea3
parent355675ddb4b0006a3d3fe44a327aa5d4eccd26c4 (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/ChangeLog18
-rw-r--r--gcc/config/rs6000/aix.h8
-rw-r--r--gcc/config/rs6000/aix43.h2
-rw-r--r--gcc/config/rs6000/rs6000-protos.h3
-rw-r--r--gcc/config/rs6000/rs6000.c130
-rw-r--r--gcc/config/rs6000/rs6000.h6
-rw-r--r--gcc/config/rs6000/rs6000.md7
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"
"@