summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>1998-09-15 19:19:12 +0000
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>1998-09-15 19:19:12 +0000
commitec37ccb4cc413884d02d17d3351b46d8f53ad63a (patch)
tree5f8b92560efd1078cbd16601e8b3502296539971
parente393f69e6c3e1117ecd702fef8f20704f8bf88b0 (diff)
downloadppe42-gcc-ec37ccb4cc413884d02d17d3351b46d8f53ad63a.tar.gz
ppe42-gcc-ec37ccb4cc413884d02d17d3351b46d8f53ad63a.zip
* tree.h (BUILT_IN_CALLER_RETURN_ADDRESS): Unused. Kill.
(BUILT_IN_FP, BUILT_IN_SP, BUILT_IN_SET_RETURN_ADDR_REG): Kill. (BUILT_IN_EH_STUB_OLD, BUILT_IN_EH_STUB, BUILT_IN_SET_EH_REGS): Kill. (BUILT_IN_EH_RETURN, BUILT_IN_DWARF_CFA): New. * c-decl.c (init_decl_processing): Update accordingly. * expr.c (expand_builtin): Likewise. * cp/decl.c (init_decl_processing): Likewise. * rtl.h (global_rtl): Add cfa entry. (virtual_cfa_rtx, VIRTUAL_CFA_REGNUM): New. (LAST_VIRTUAL_REGISTER): Update. * emit-rtl.c (global_rtl): Add cfa entry. (init_emit): Initialize it. * function.c (cfa_offset): New. (instantiate_virtual_regs): Initialize it. (instantiate_virtual_regs_1): Instantiate virtual_cfa_rtx. (expand_function_end): Call expand_eh_return. * tm.texi (ARG_POINTER_CFA_OFFSET): New. * except.c (current_function_eh_stub_label): Kill. (current_function_eh_old_stub_label): Likwise; update all references. (expand_builtin_set_return_addr_reg): Kill. (expand_builtin_eh_stub_old, expand_builtin_eh_stub): Kill. (expand_builtin_set_eh_regs): Kill. (eh_regs): Produce a third reg for the actual handler address. (eh_return_context, eh_return_stack_adjust): New. (eh_return_handler, eh_return_stub_label): New. (init_eh_for_function): Initialize them. (expand_builtin_eh_return, expand_eh_return): New. * except.h: Update prototypes. * flow.c (find_basic_blocks_1): Update references to the stub label. * function.h (struct function): Kill stub label elements. * libgcc2.c (in_reg_window): For REG_SAVED_REG, check that the register number is one that would be in the previous window. Provide a dummy definition for non-windowed targets. (get_reg_addr): New function. (get_reg, put_reg, copy_reg): Use it. (__throw): Rely on in_reg_window, not INCOMING_REGNO. Kill stub generating code and use __builtin_eh_return. Use __builtin_dwarf_cfa. * alpha.c (alpha_eh_epilogue_sp_ofs): New. (alpha_init_expanders): Initialize it. (alpha_expand_epilogue): Use it. * alpha.h: Declare it. * alpha.md (eh_epilogue): New. * m68h.h (ARG_POINTER_CFA_OFFSET): New. * sparc.h (ARG_POINTER_CFA_OFFSET): New. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@22436 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog51
-rw-r--r--gcc/c-decl.c22
-rw-r--r--gcc/config/alpha/alpha.c45
-rw-r--r--gcc/config/alpha/alpha.h4
-rw-r--r--gcc/config/alpha/alpha.md16
-rw-r--r--gcc/config/m68k/m68k.h3
-rw-r--r--gcc/config/sparc/sparc.h4
-rw-r--r--gcc/cp/ChangeLog4
-rw-r--r--gcc/cp/decl.c4
-rw-r--r--gcc/emit-rtl.c6
-rw-r--r--gcc/except.c242
-rw-r--r--gcc/except.h12
-rw-r--r--gcc/expr.c20
-rw-r--r--gcc/flow.c13
-rw-r--r--gcc/function.c21
-rw-r--r--gcc/function.h2
-rw-r--r--gcc/libgcc2.c148
-rw-r--r--gcc/rtl.h13
-rw-r--r--gcc/tm.texi11
-rw-r--r--gcc/tree.h8
20 files changed, 372 insertions, 277 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index fd810b06868..5e646cdae06 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,54 @@
+Tue Sep 15 19:09:06 1998 Richard Henderson <rth@cygnus.com>
+
+ * tree.h (BUILT_IN_CALLER_RETURN_ADDRESS): Unused. Kill.
+ (BUILT_IN_FP, BUILT_IN_SP, BUILT_IN_SET_RETURN_ADDR_REG): Kill.
+ (BUILT_IN_EH_STUB_OLD, BUILT_IN_EH_STUB, BUILT_IN_SET_EH_REGS): Kill.
+ (BUILT_IN_EH_RETURN, BUILT_IN_DWARF_CFA): New.
+ * c-decl.c (init_decl_processing): Update accordingly.
+ * expr.c (expand_builtin): Likewise.
+
+ * rtl.h (global_rtl): Add cfa entry.
+ (virtual_cfa_rtx, VIRTUAL_CFA_REGNUM): New.
+ (LAST_VIRTUAL_REGISTER): Update.
+ * emit-rtl.c (global_rtl): Add cfa entry.
+ (init_emit): Initialize it.
+ * function.c (cfa_offset): New.
+ (instantiate_virtual_regs): Initialize it.
+ (instantiate_virtual_regs_1): Instantiate virtual_cfa_rtx.
+ (expand_function_end): Call expand_eh_return.
+ * tm.texi (ARG_POINTER_CFA_OFFSET): New.
+
+ * except.c (current_function_eh_stub_label): Kill.
+ (current_function_eh_old_stub_label): Likwise; update all references.
+ (expand_builtin_set_return_addr_reg): Kill.
+ (expand_builtin_eh_stub_old, expand_builtin_eh_stub): Kill.
+ (expand_builtin_set_eh_regs): Kill.
+ (eh_regs): Produce a third reg for the actual handler address.
+ (eh_return_context, eh_return_stack_adjust): New.
+ (eh_return_handler, eh_return_stub_label): New.
+ (init_eh_for_function): Initialize them.
+ (expand_builtin_eh_return, expand_eh_return): New.
+ * except.h: Update prototypes.
+ * flow.c (find_basic_blocks_1): Update references to the stub label.
+ * function.h (struct function): Kill stub label elements.
+
+ * libgcc2.c (in_reg_window): For REG_SAVED_REG, check that the
+ register number is one that would be in the previous window.
+ Provide a dummy definition for non-windowed targets.
+ (get_reg_addr): New function.
+ (get_reg, put_reg, copy_reg): Use it.
+ (__throw): Rely on in_reg_window, not INCOMING_REGNO. Kill stub
+ generating code and use __builtin_eh_return. Use __builtin_dwarf_cfa.
+
+ * alpha.c (alpha_eh_epilogue_sp_ofs): New.
+ (alpha_init_expanders): Initialize it.
+ (alpha_expand_epilogue): Use it.
+ * alpha.h: Declare it.
+ * alpha.md (eh_epilogue): New.
+
+ * m68h.h (ARG_POINTER_CFA_OFFSET): New.
+ * sparc.h (ARG_POINTER_CFA_OFFSET): New.
+
Tue Sep 15 19:31:58 1998 Michael Meissner <meissner@cygnus.com>
* i960.h (CONST_COSTS): Fix thinko. Test flag, not the constant
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 168400bd7f5..f05dc27a1a7 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -3291,8 +3291,8 @@ init_decl_processing ()
builtin_function ("__builtin_unwind_init",
build_function_type (void_type_node, endlink),
BUILT_IN_UNWIND_INIT, NULL_PTR);
- builtin_function ("__builtin_fp", ptr_ftype_void, BUILT_IN_FP, NULL_PTR);
- builtin_function ("__builtin_sp", ptr_ftype_void, BUILT_IN_SP, NULL_PTR);
+ builtin_function ("__builtin_dwarf_cfa", ptr_ftype_void,
+ BUILT_IN_DWARF_CFA, NULL_PTR);
builtin_function ("__builtin_dwarf_fp_regnum",
build_function_type (unsigned_type_node, endlink),
BUILT_IN_DWARF_FP_REGNUM, NULL_PTR);
@@ -3302,24 +3302,16 @@ init_decl_processing ()
BUILT_IN_FROB_RETURN_ADDR, NULL_PTR);
builtin_function ("__builtin_extract_return_addr", ptr_ftype_ptr,
BUILT_IN_EXTRACT_RETURN_ADDR, NULL_PTR);
- builtin_function ("__builtin_set_return_addr_reg",
- build_function_type (void_type_node,
- tree_cons (NULL_TREE,
- ptr_type_node,
- endlink)),
- BUILT_IN_SET_RETURN_ADDR_REG, NULL_PTR);
- builtin_function ("__builtin_eh_stub_old", ptr_ftype_void,
- BUILT_IN_EH_STUB_OLD, NULL_PTR);
- builtin_function ("__builtin_eh_stub", ptr_ftype_void,
- BUILT_IN_EH_STUB, NULL_PTR);
builtin_function
- ("__builtin_set_eh_regs",
+ ("__builtin_eh_return",
build_function_type (void_type_node,
tree_cons (NULL_TREE, ptr_type_node,
tree_cons (NULL_TREE,
type_for_mode (ptr_mode, 0),
- endlink))),
- BUILT_IN_SET_EH_REGS, NULL_PTR);
+ tree_cons (NULL_TREE,
+ ptr_type_node,
+ endlink)))),
+ BUILT_IN_EH_RETURN, NULL_PTR);
builtin_function ("__builtin_alloca",
build_function_type (ptr_type_node,
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index f0795f3fa54..2b2971452a7 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -79,6 +79,10 @@ char *alpha_mlat_string; /* -mmemory-latency= */
rtx alpha_compare_op0, alpha_compare_op1;
int alpha_compare_fp_p;
+/* Define the information needed to modify the epilogue for EH. */
+
+rtx alpha_eh_epilogue_sp_ofs;
+
/* Non-zero if inside of a function, because the Alpha asm can't
handle .files inside of functions. */
@@ -2431,6 +2435,7 @@ void
alpha_init_expanders ()
{
alpha_return_addr_rtx = NULL_RTX;
+ alpha_eh_epilogue_sp_ofs = NULL_RTX;
/* Arrange to save and restore machine status around nested functions. */
save_machine_status = alpha_save_machine_status;
@@ -3731,9 +3736,13 @@ alpha_expand_epilogue ()
/* Restore registers in order, excepting a true frame pointer. */
- FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA),
- gen_rtx_MEM (DImode, plus_constant(sa_reg,
- reg_offset))));
+ if (! alpha_eh_epilogue_sp_ofs)
+ {
+ FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA),
+ gen_rtx_MEM (DImode,
+ plus_constant(sa_reg,
+ reg_offset))));
+ }
reg_offset += 8;
imask &= ~(1L << REG_RA);
@@ -3763,21 +3772,28 @@ alpha_expand_epilogue ()
}
}
- if (frame_size)
+ if (frame_size || alpha_eh_epilogue_sp_ofs)
{
+ sp_adj1 = stack_pointer_rtx;
+
+ if (alpha_eh_epilogue_sp_ofs)
+ {
+ sp_adj1 = gen_rtx_REG (DImode, 23);
+ emit_move_insn (sp_adj1,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ alpha_eh_epilogue_sp_ofs));
+ }
+
/* If the stack size is large, begin computation into a temporary
register so as not to interfere with a potential fp restore,
which must be consecutive with an SP restore. */
if (frame_size < 32768)
- {
- sp_adj1 = stack_pointer_rtx;
- sp_adj2 = GEN_INT (frame_size);
- }
+ sp_adj2 = GEN_INT (frame_size);
else if (frame_size < 0x40007fffL)
{
int low = ((frame_size & 0xffff) ^ 0x8000) - 0x8000;
- sp_adj2 = plus_constant (stack_pointer_rtx, frame_size - low);
+ sp_adj2 = plus_constant (sp_adj1, frame_size - low);
if (sa_reg_exp && rtx_equal_p (sa_reg_exp, sp_adj2))
sp_adj1 = sa_reg;
else
@@ -3789,21 +3805,20 @@ alpha_expand_epilogue ()
}
else
{
- sp_adj2 = gen_rtx_REG (DImode, 23);
- FRP (sp_adj1 = alpha_emit_set_const (sp_adj2, DImode, frame_size, 3));
- if (!sp_adj1)
+ rtx tmp = gen_rtx_REG (DImode, 23);
+ FRP (sp_adj2 = alpha_emit_set_const (tmp, DImode, frame_size, 3));
+ if (!sp_adj2)
{
/* We can't drop new things to memory this late, afaik,
so build it up by pieces. */
#if HOST_BITS_PER_WIDE_INT == 64
- FRP (sp_adj1 = alpha_emit_set_long_const (sp_adj2, frame_size));
- if (!sp_adj1)
+ FRP (sp_adj2 = alpha_emit_set_long_const (tmp, frame_size));
+ if (!sp_adj2)
abort ();
#else
abort ();
#endif
}
- sp_adj2 = stack_pointer_rtx;
}
/* From now on, things must be in order. So emit blockages. */
diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h
index 2021e677895..0a99e07a556 100644
--- a/gcc/config/alpha/alpha.h
+++ b/gcc/config/alpha/alpha.h
@@ -1180,6 +1180,10 @@ extern struct rtx_def *alpha_builtin_saveregs ();
extern struct rtx_def *alpha_compare_op0, *alpha_compare_op1;
extern int alpha_compare_fp_p;
+/* Define the information needed to modify the epilogue for EH. */
+
+extern struct rtx_def *alpha_eh_epilogue_sp_ofs;
+
/* Make (or fake) .linkage entry for function call.
IS_LOCAL is 0 if name is used in call, 1 if name is used in definition. */
extern void alpha_need_linkage ();
diff --git a/gcc/config/alpha/alpha.md b/gcc/config/alpha/alpha.md
index 232fb01def1..a214cc487c1 100644
--- a/gcc/config/alpha/alpha.md
+++ b/gcc/config/alpha/alpha.md
@@ -5144,6 +5144,22 @@
""
"alpha_expand_epilogue (); DONE;")
+(define_expand "eh_epilogue"
+ [(use (match_operand:DI 0 "register_operand" "r"))
+ (use (match_operand:DI 1 "register_operand" "r"))
+ (use (match_operand:DI 2 "register_operand" "r"))]
+ "! TARGET_OPEN_VMS"
+ "
+{
+ alpha_eh_epilogue_sp_ofs = operands[1];
+ if (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != 26)
+ {
+ rtx ra = gen_rtx_REG (Pmode, 26);
+ emit_move_insn (ra, operands[2]);
+ operands[2] = ra;
+ }
+}")
+
(define_expand "builtin_longjmp"
[(unspec_volatile [(match_operand 0 "register_operand" "r")] 3)]
"! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT"
diff --git a/gcc/config/m68k/m68k.h b/gcc/config/m68k/m68k.h
index 1c17e28e4ce..a4bfef9a638 100644
--- a/gcc/config/m68k/m68k.h
+++ b/gcc/config/m68k/m68k.h
@@ -858,6 +858,9 @@ extern enum reg_class regno_reg_class[];
/* Offset of first parameter from the argument pointer register value. */
#define FIRST_PARM_OFFSET(FNDECL) 8
+/* Offset of the CFA from the argument pointer register value. */
+#define ARG_POINTER_CFA_OFFSET 8
+
/* Value is the number of byte of arguments automatically
popped when returning from a subroutine call.
FUNDECL is the declaration node of the function (as a tree),
diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h
index c68c3d02916..d5812d0dbdd 100644
--- a/gcc/config/sparc/sparc.h
+++ b/gcc/config/sparc/sparc.h
@@ -1478,6 +1478,10 @@ extern char leaf_reg_remap[];
(TARGET_ARCH64 ? (SPARC_STACK_BIAS + 16 * UNITS_PER_WORD) \
: (STRUCT_VALUE_OFFSET + UNITS_PER_WORD))
+/* Offset from the argument pointer register value to the CFA. */
+
+#define ARG_POINTER_CFA_OFFSET SPARC_STACK_BIAS
+
/* When a parameter is passed in a register, stack space is still
allocated for it.
!v9: All 6 possible integer registers have backing store allocated.
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index d1d68ac821b..f1af3744c39 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,7 @@
+1998-09-16 Richard Henderson <rth@cygnus.com>
+
+ * decl.c (init_decl_processing): Kill __builtin_fp and __builtin_sp.
+
1998-09-15 Alexandre Oliva <oliva@dcc.unicamp.br>
* call.c (build_field_call): handle static data members too
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 98f933607b7..ee094e5d419 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5891,10 +5891,6 @@ init_decl_processing ()
builtin_function ("__builtin_frame_address", ptr_ftype_unsigned,
BUILT_IN_FRAME_ADDRESS, NULL_PTR);
- ptr_ftype_void = build_function_type (ptr_type_node, endlink);
- builtin_function ("__builtin_fp", ptr_ftype_void, BUILT_IN_FP, NULL_PTR);
- builtin_function ("__builtin_sp", ptr_ftype_void, BUILT_IN_SP, NULL_PTR);
-
builtin_function ("__builtin_alloca", ptr_ftype_sizetype,
BUILT_IN_ALLOCA, "alloca");
builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR);
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index a59437b4103..e5510a6dbeb 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -103,6 +103,7 @@ struct _global_rtl global_rtl =
{REG}, /* virtual_stack_vars_rtx */
{REG}, /* virtual_stack_dynamic_rtx */
{REG}, /* virtual_outgoing_args_rtx */
+ {REG}, /* virtual_cfa_rtx */
};
/* We record floating-point CONST_DOUBLEs in each floating-point mode for
@@ -3342,6 +3343,7 @@ init_emit ()
regno_reg_rtx[VIRTUAL_STACK_VARS_REGNUM] = virtual_stack_vars_rtx;
regno_reg_rtx[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx;
regno_reg_rtx[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx;
+ regno_reg_rtx[VIRTUAL_CFA_REGNUM] = virtual_cfa_rtx;
/* Indicate that the virtual registers and stack locations are
all pointers. */
@@ -3354,6 +3356,7 @@ init_emit ()
REGNO_POINTER_FLAG (VIRTUAL_STACK_VARS_REGNUM) = 1;
REGNO_POINTER_FLAG (VIRTUAL_STACK_DYNAMIC_REGNUM) = 1;
REGNO_POINTER_FLAG (VIRTUAL_OUTGOING_ARGS_REGNUM) = 1;
+ REGNO_POINTER_FLAG (VIRTUAL_CFA_REGNUM) = 1;
#ifdef STACK_BOUNDARY
REGNO_POINTER_ALIGN (STACK_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
@@ -3370,6 +3373,7 @@ init_emit ()
= STACK_BOUNDARY / BITS_PER_UNIT;
REGNO_POINTER_ALIGN (VIRTUAL_OUTGOING_ARGS_REGNUM)
= STACK_BOUNDARY / BITS_PER_UNIT;
+ REGNO_POINTER_ALIGN (VIRTUAL_CFA_REGNUM) = UNITS_PER_WORD;
#endif
#ifdef INIT_EXPANDERS
@@ -3504,6 +3508,8 @@ init_emit_once (line_numbers)
PUT_MODE (virtual_stack_dynamic_rtx, Pmode);
REGNO (virtual_outgoing_args_rtx) = VIRTUAL_OUTGOING_ARGS_REGNUM;
PUT_MODE (virtual_outgoing_args_rtx, Pmode);
+ REGNO (virtual_cfa_rtx) = VIRTUAL_CFA_REGNUM;
+ PUT_MODE (virtual_cfa_rtx, Pmode);
#ifdef RETURN_ADDRESS_POINTER_REGNUM
return_address_pointer_rtx
diff --git a/gcc/except.c b/gcc/except.c
index f0d00094f85..d1e82208d42 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -431,12 +431,6 @@ rtx exception_handler_labels;
rtx current_function_ehc;
-/* The labels generated by expand_builtin_eh_stub and
- expand_builtin_eh_stub_old. */
-
-rtx current_function_eh_stub_label;
-rtx current_function_eh_old_stub_label;
-
/* A stack used for keeping track of the currently active exception
handling region. As each exception region is started, an entry
describing the region is pushed onto this stack. The current
@@ -496,6 +490,20 @@ struct label_node *outer_context_label_stack = NULL;
struct label_node *false_label_stack = NULL;
+/* Pseudos used to hold exception return data in the interim between
+ __builtin_eh_return and the end of the function. */
+
+static rtx eh_return_context;
+static rtx eh_return_stack_adjust;
+static rtx eh_return_handler;
+
+/* Used to mark the eh return stub for flow, so that the Right Thing
+ happens with the values for the hardregs therin. */
+
+rtx eh_return_stub_label;
+
+/* Prototypes for local functions. */
+
static void push_eh_entry PROTO((struct eh_stack *));
static struct eh_entry * pop_eh_entry PROTO((struct eh_stack *));
static void enqueue_eh_entry PROTO((struct eh_queue *, struct eh_entry *));
@@ -507,13 +515,12 @@ static void expand_rethrow PROTO((rtx));
static void output_exception_table_entry PROTO((FILE *, int));
static int can_throw PROTO((rtx));
static rtx scan_region PROTO((rtx, int, int *));
-static void eh_regs PROTO((rtx *, rtx *, int));
+static void eh_regs PROTO((rtx *, rtx *, rtx *, int));
static void set_insn_eh_region PROTO((rtx *, int));
#ifdef DONT_USE_BUILTIN_SETJMP
static void jumpif_rtx PROTO((rtx, rtx));
#endif
-
rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
/* Various support routines to manipulate the various data structures
@@ -2203,8 +2210,10 @@ init_eh_for_function ()
caught_return_label_stack = 0;
protect_list = NULL_TREE;
current_function_ehc = NULL_RTX;
- current_function_eh_stub_label = NULL_RTX;
- current_function_eh_old_stub_label = NULL_RTX;
+ eh_return_context = NULL_RTX;
+ eh_return_stack_adjust = NULL_RTX;
+ eh_return_handler = NULL_RTX;
+ eh_return_stub_label = NULL_RTX;
}
/* Save some of the per-function EH info into the save area denoted by
@@ -2227,8 +2236,6 @@ save_eh_status (p)
p->caught_return_label_stack = caught_return_label_stack;
p->protect_list = protect_list;
p->ehc = current_function_ehc;
- p->eh_stub_label = current_function_eh_stub_label;
- p->eh_old_stub_label = current_function_eh_old_stub_label;
init_eh_for_function ();
}
@@ -2252,8 +2259,6 @@ restore_eh_status (p)
ehstack = p->ehstack;
catchstack = p->catchstack;
current_function_ehc = p->ehc;
- current_function_eh_stub_label = p->eh_stub_label;
- current_function_eh_old_stub_label = p->eh_old_stub_label;
}
/* This section is for the exception handling specific optimization
@@ -2465,79 +2470,72 @@ expand_builtin_frob_return_addr (addr_tree)
return addr;
}
-/* Given an actual address in addr_tree, set the return address register up
- so the epilogue will return to that address. If the return address is
- not in a register, do nothing. */
+/* Choose three registers for communication between the main body of
+ __throw and the epilogue (or eh stub) and the exception handler.
+ We must do this with hard registers because the epilogue itself
+ will be generated after reload, at which point we may not reference
+ pseudos at all.
-void
-expand_builtin_set_return_addr_reg (addr_tree)
- tree addr_tree;
-{
- rtx tmp;
- rtx ra = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
- 0, hard_frame_pointer_rtx);
-
- if (GET_CODE (ra) != REG || REGNO (ra) >= FIRST_PSEUDO_REGISTER)
- return;
-
- tmp = force_operand (expand_builtin_frob_return_addr (addr_tree), ra);
- if (tmp != ra)
- emit_move_insn (ra, tmp);
-}
+ The first passes the exception context to the handler. For this
+ we use the return value register for a void*.
-/* Choose two registers for communication between the main body of
- __throw and the stub for adjusting the stack pointer. The first register
- is used to pass the address of the exception handler; the second register
- is used to pass the stack pointer offset.
+ The second holds the stack pointer value to be restored. For
+ this we use the static chain register if it exists and is different
+ from the previous, otherwise some arbitrary call-clobbered register.
- For register 1 we use the return value register for a void *.
- For register 2 we use the static chain register if it exists and is
- different from register 1, otherwise some arbitrary call-clobbered
- register. */
+ The third holds the address of the handler itself. Here we use
+ some arbitrary call-clobbered register. */
static void
-eh_regs (r1, r2, outgoing)
- rtx *r1, *r2;
+eh_regs (pcontext, psp, pra, outgoing)
+ rtx *pcontext, *psp, *pra;
int outgoing;
{
- rtx reg1, reg2;
+ rtx rcontext, rsp, rra;
+ int i;
#ifdef FUNCTION_OUTGOING_VALUE
if (outgoing)
- reg1 = FUNCTION_OUTGOING_VALUE (build_pointer_type (void_type_node),
- current_function_decl);
+ rcontext = FUNCTION_OUTGOING_VALUE (build_pointer_type (void_type_node),
+ current_function_decl);
else
#endif
- reg1 = FUNCTION_VALUE (build_pointer_type (void_type_node),
- current_function_decl);
+ rcontext = FUNCTION_VALUE (build_pointer_type (void_type_node),
+ current_function_decl);
#ifdef STATIC_CHAIN_REGNUM
if (outgoing)
- reg2 = static_chain_incoming_rtx;
+ rsp = static_chain_incoming_rtx;
else
- reg2 = static_chain_rtx;
- if (REGNO (reg2) == REGNO (reg1))
+ rsp = static_chain_rtx;
+ if (REGNO (rsp) == REGNO (rcontext))
#endif /* STATIC_CHAIN_REGNUM */
- reg2 = NULL_RTX;
+ rsp = NULL_RTX;
- if (reg2 == NULL_RTX)
+ if (rsp == NULL_RTX)
{
- int i;
for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
- if (call_used_regs[i] && ! fixed_regs[i] && i != REGNO (reg1))
- {
- reg2 = gen_rtx_REG (Pmode, i);
- break;
- }
+ if (call_used_regs[i] && ! fixed_regs[i] && i != REGNO (rcontext))
+ break;
+ if (i == FIRST_PSEUDO_REGISTER)
+ abort();
- if (reg2 == NULL_RTX)
- abort ();
+ rsp = gen_rtx_REG (Pmode, i);
}
- *r1 = reg1;
- *r2 = reg2;
-}
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+ if (call_used_regs[i] && ! fixed_regs[i]
+ && i != REGNO (rcontext) && i != REGNO (rsp))
+ break;
+ if (i == FIRST_PSEUDO_REGISTER)
+ abort();
+
+ rra = gen_rtx_REG (Pmode, i);
+ *pcontext = rcontext;
+ *psp = rsp;
+ *pra = rra;
+}
/* Retrieve the register which contains the pointer to the eh_context
structure set the __throw. */
@@ -2551,83 +2549,85 @@ get_reg_for_handler ()
return reg1;
}
+/* Set up the epilogue with the magic bits we'll need to return to the
+ exception handler. */
-/* Emit inside of __throw a stub which adjusts the stack pointer and jumps
- to the exception handler. __throw will set up the necessary values
- and then return to the stub. */
-
-rtx
-expand_builtin_eh_stub_old ()
+void
+expand_builtin_eh_return (context, stack, handler)
+ tree context, stack, handler;
{
- rtx stub_start = gen_label_rtx ();
- rtx after_stub = gen_label_rtx ();
- rtx handler, offset;
+ if (eh_return_context)
+ error("Duplicate call to __builtin_eh_return");
- current_function_eh_old_stub_label = stub_start;
-
- emit_jump (after_stub);
- emit_label (stub_start);
-
- eh_regs (&handler, &offset, 0);
-
- adjust_stack (offset);
- emit_indirect_jump (handler);
- emit_label (after_stub);
- return gen_rtx_LABEL_REF (Pmode, stub_start);
+ eh_return_context
+ = copy_to_reg (expand_expr (context, NULL_RTX, VOIDmode, 0));
+ eh_return_stack_adjust
+ = copy_to_reg (expand_expr (stack, NULL_RTX, VOIDmode, 0));
+ eh_return_handler
+ = copy_to_reg (expand_expr (handler, NULL_RTX, VOIDmode, 0));
}
-rtx
-expand_builtin_eh_stub ()
+void
+expand_eh_return ()
{
- rtx stub_start = gen_label_rtx ();
- rtx after_stub = gen_label_rtx ();
- rtx handler, offset;
- rtx temp;
-
- current_function_eh_stub_label = stub_start;
-
- emit_jump (after_stub);
- emit_label (stub_start);
+ rtx reg1, reg2, reg3;
+ rtx stub_start, after_stub;
+ rtx ra, tmp;
- eh_regs (&handler, &offset, 0);
+ if (!eh_return_context)
+ return;
- adjust_stack (offset);
+ eh_regs (&reg1, &reg2, &reg3, 1);
+ emit_move_insn (reg1, eh_return_context);
+ emit_move_insn (reg2, eh_return_stack_adjust);
+ emit_move_insn (reg3, eh_return_handler);
- /* Handler is in fact a pointer to the _eh_context structure, we need
- to pick out the handler field (first element), and jump to there,
- leaving the pointer to _eh_conext in the same hardware register. */
+ /* Talk directly to the target's epilogue code when possible. */
- temp = gen_rtx_MEM (Pmode, handler);
- MEM_IN_STRUCT_P (temp) = 1;
- RTX_UNCHANGING_P (temp) = 1;
- emit_move_insn (offset, temp);
- emit_insn (gen_rtx_USE (Pmode, handler));
+#ifdef HAVE_eh_epilogue
+ if (HAVE_eh_epilogue)
+ {
+ emit_insn (gen_eh_epilogue (reg1, reg2, reg3));
+ return;
+ }
+#endif
- emit_indirect_jump (offset);
-
- emit_label (after_stub);
- return gen_rtx_LABEL_REF (Pmode, stub_start);
-}
+ /* Otherwise, use the same stub technique we had before. */
-/* Set up the registers for passing the handler address and stack offset
- to the stub above. */
+ eh_return_stub_label = stub_start = gen_label_rtx ();
+ after_stub = gen_label_rtx ();
-void
-expand_builtin_set_eh_regs (handler, offset)
- tree handler, offset;
-{
- rtx reg1, reg2;
+ /* Set the return address to the stub label. */
- eh_regs (&reg1, &reg2, 1);
+ ra = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
+ 0, hard_frame_pointer_rtx);
+ if (GET_CODE (ra) == REG && REGNO (ra) >= FIRST_PSEUDO_REGISTER)
+ abort();
- store_expr (offset, reg2, 0);
- store_expr (handler, reg1, 0);
+ tmp = memory_address (Pmode, gen_rtx_LABEL_REF (Pmode, stub_start));
+#ifdef RETURN_ADDR_OFFSET
+ tmp = plus_constant (tmp, -RETURN_ADDR_OFFSET);
+#endif
+ emit_move_insn (ra, tmp);
- /* These will be used by the stub. */
+ /* Indicate that the registers are in fact used. */
emit_insn (gen_rtx_USE (VOIDmode, reg1));
emit_insn (gen_rtx_USE (VOIDmode, reg2));
-}
+ emit_insn (gen_rtx_USE (VOIDmode, reg3));
+ if (GET_CODE (ra) == REG)
+ emit_insn (gen_rtx_USE (VOIDmode, ra));
+ /* Generate the stub. */
+
+ emit_jump (after_stub);
+ emit_label (stub_start);
+
+ eh_regs (&reg1, &reg2, &reg3, 0);
+ adjust_stack (reg2);
+ emit_indirect_jump (reg3);
+
+ emit_label (after_stub);
+}
/* This contains the code required to verify whether arbitrary instructions
diff --git a/gcc/except.h b/gcc/except.h
index 5416e598760..540044bde02 100644
--- a/gcc/except.h
+++ b/gcc/except.h
@@ -24,11 +24,9 @@ typedef struct rtx_def *_except_rtx;
#define rtx _except_rtx
#endif
-/* The labels generated by expand_builtin_eh_stub and
- expand_builtin_eh_stub_old. */
+/* The label generated by expand_builtin_eh_return. */
-extern rtx current_function_eh_stub_label;
-extern rtx current_function_eh_old_stub_label;
+extern rtx eh_return_stub_label;
#ifdef TREE_CODE
@@ -377,15 +375,13 @@ extern void expand_fixup_region_end PROTO((tree));
void expand_builtin_unwind_init PROTO((void));
rtx expand_builtin_dwarf_fp_regnum PROTO((void));
-rtx expand_builtin_eh_stub PROTO((void));
-rtx expand_builtin_eh_stub_old PROTO((void));
#ifdef TREE_CODE
rtx expand_builtin_frob_return_addr PROTO((tree));
rtx expand_builtin_extract_return_addr PROTO((tree));
-void expand_builtin_set_return_addr_reg PROTO((tree));
-void expand_builtin_set_eh_regs PROTO((tree, tree));
rtx expand_builtin_dwarf_reg_size PROTO((tree, rtx));
+void expand_builtin_eh_return PROTO((tree, tree, tree));
#endif
+void expand_eh_return PROTO((void));
/* Checking whether 2 instructions are within the same exception region. */
diff --git a/gcc/expr.c b/gcc/expr.c
index dbf19ff102d..028f9b21cfd 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -9370,10 +9370,8 @@ expand_builtin (exp, target, subtarget, mode, ignore)
case BUILT_IN_UNWIND_INIT:
expand_builtin_unwind_init ();
return const0_rtx;
- case BUILT_IN_FP:
- return frame_pointer_rtx;
- case BUILT_IN_SP:
- return stack_pointer_rtx;
+ case BUILT_IN_DWARF_CFA:
+ return virtual_cfa_rtx;
#ifdef DWARF2_UNWIND_INFO
case BUILT_IN_DWARF_FP_REGNUM:
return expand_builtin_dwarf_fp_regnum ();
@@ -9384,16 +9382,10 @@ expand_builtin (exp, target, subtarget, mode, ignore)
return expand_builtin_frob_return_addr (TREE_VALUE (arglist));
case BUILT_IN_EXTRACT_RETURN_ADDR:
return expand_builtin_extract_return_addr (TREE_VALUE (arglist));
- case BUILT_IN_SET_RETURN_ADDR_REG:
- expand_builtin_set_return_addr_reg (TREE_VALUE (arglist));
- return const0_rtx;
- case BUILT_IN_EH_STUB_OLD:
- return expand_builtin_eh_stub_old ();
- case BUILT_IN_EH_STUB:
- return expand_builtin_eh_stub ();
- case BUILT_IN_SET_EH_REGS:
- expand_builtin_set_eh_regs (TREE_VALUE (arglist),
- TREE_VALUE (TREE_CHAIN (arglist)));
+ case BUILT_IN_EH_RETURN:
+ expand_builtin_eh_return (TREE_VALUE (arglist),
+ TREE_VALUE (TREE_CHAIN (arglist)),
+ TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))));
return const0_rtx;
default: /* just do library call, if unknown builtin */
diff --git a/gcc/flow.c b/gcc/flow.c
index a7ce4a367e0..fb309be735a 100644
--- a/gcc/flow.c
+++ b/gcc/flow.c
@@ -485,8 +485,7 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
/* Make a list of all labels referred to other than by jumps. */
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_LABEL
- && XEXP (note, 0) != current_function_eh_stub_label
- && XEXP (note, 0) != current_function_eh_old_stub_label)
+ && XEXP (note, 0) != eh_return_stub_label)
label_value_list = gen_rtx_EXPR_LIST (VOIDmode, XEXP (note, 0),
label_value_list);
}
@@ -619,8 +618,7 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
note = XEXP (note, 1))
{
if (REG_NOTE_KIND (note) == REG_LABEL
- && XEXP (note, 0) != current_function_eh_stub_label
- && XEXP (note, 0) != current_function_eh_old_stub_label)
+ && XEXP (note, 0) != eh_return_stub_label)
{
x = XEXP (note, 0);
block_live[BLOCK_NUM (x)] = 1;
@@ -708,13 +706,10 @@ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
within it. So we have to make additional edges in the
flow graph. */
if (i + 1 == n_basic_blocks
- && current_function_eh_stub_label != 0)
+ && eh_return_stub_label != 0)
{
mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
- current_function_eh_stub_label),
- basic_block_end[i], 0);
- mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
- current_function_eh_old_stub_label),
+ eh_return_stub_label),
basic_block_end[i], 0);
}
}
diff --git a/gcc/function.c b/gcc/function.c
index 5bd012fc135..a5f8f0591c1 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -2688,6 +2688,7 @@ static int in_arg_offset;
static int var_offset;
static int dynamic_offset;
static int out_arg_offset;
+static int cfa_offset;
/* In most machines, the stack pointer register is equivalent to the bottom
of the stack. */
@@ -2726,6 +2727,13 @@ static int out_arg_offset;
#endif
#endif
+/* On a few machines, the CFA coincides with the arg pointer. */
+
+#ifndef ARG_POINTER_CFA_OFFSET
+#define ARG_POINTER_CFA_OFFSET 0
+#endif
+
+
/* Build up a (MEM (ADDRESSOF (REG))) rtx for a register REG that just had
its address taken. DECL is the decl for the object stored in the
register, for later use if we do need to force REG into the stack.
@@ -2910,6 +2918,7 @@ instantiate_virtual_regs (fndecl, insns)
var_offset = STARTING_FRAME_OFFSET;
dynamic_offset = STACK_DYNAMIC_OFFSET (fndecl);
out_arg_offset = STACK_POINTER_OFFSET;
+ cfa_offset = ARG_POINTER_CFA_OFFSET;
/* Scan all variables and parameters of this function. For each that is
in memory, instantiate all virtual registers if the result is a valid
@@ -3143,6 +3152,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
new = stack_pointer_rtx, offset = - dynamic_offset;
else if (SET_DEST (x) == virtual_outgoing_args_rtx)
new = stack_pointer_rtx, offset = - out_arg_offset;
+ else if (SET_DEST (x) == virtual_cfa_rtx)
+ new = arg_pointer_rtx, offset = - cfa_offset;
if (new)
{
@@ -3194,6 +3205,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
new = stack_pointer_rtx, offset = dynamic_offset;
else if (inner == virtual_outgoing_args_rtx)
new = stack_pointer_rtx, offset = out_arg_offset;
+ else if (inner == virtual_cfa_rtx)
+ new = arg_pointer_rtx, offset = cfa_offset;
else
{
loc = &XEXP (x, 0);
@@ -3213,6 +3226,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
new = stack_pointer_rtx, offset = dynamic_offset;
else if (XEXP (x, 0) == virtual_outgoing_args_rtx)
new = stack_pointer_rtx, offset = out_arg_offset;
+ else if (XEXP (x, 0) == virtual_cfa_rtx)
+ new = arg_pointer_rtx, offset = cfa_offset;
else
{
/* We know the second operand is a constant. Unless the
@@ -3420,6 +3435,8 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
new = stack_pointer_rtx, offset = dynamic_offset;
else if (x == virtual_outgoing_args_rtx)
new = stack_pointer_rtx, offset = out_arg_offset;
+ else if (x == virtual_cfa_rtx)
+ new = arg_pointer_rtx, offset = cfa_offset;
if (new)
{
@@ -5981,6 +5998,10 @@ expand_function_end (filename, line, end_bindings)
use_variable (outgoing);
}
+ /* If this is an implementation of __throw, do what's necessary to
+ communicate between __builtin_eh_return and the epilogue. */
+ expand_eh_return ();
+
/* Output a return insn if we are using one.
Otherwise, let the rtl chain end here, to drop through
into the epilogue. */
diff --git a/gcc/function.h b/gcc/function.h
index 786e062a487..06e90dc88aa 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -142,8 +142,6 @@ struct function
rtx catch_clauses;
struct label_node *false_label_stack;
struct label_node *caught_return_label_stack;
- rtx eh_stub_label;
- rtx eh_old_stub_label;
tree protect_list;
rtx ehc;
diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c
index 6f2fcfd9796..821387b3960 100644
--- a/gcc/libgcc2.c
+++ b/gcc/libgcc2.c
@@ -3492,31 +3492,71 @@ find_exception_handler (void *pc, exception_descriptor *table, void *eh_info)
typedef int ptr_type __attribute__ ((mode (pointer)));
-/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
+#ifdef INCOMING_REGNO
+/* Is the saved value for register REG in frame UDATA stored in a register
+ window in the previous frame? */
+
+/* ??? The Sparc INCOMING_REGNO references TARGET_FLAT. This allows us
+ to use the macro here. One wonders, though, that perhaps TARGET_FLAT
+ compiled functions won't work with the frame-unwind stuff here.
+ Perhaps the entireity of in_reg_window should be conditional on having
+ seen a DW_CFA_GNU_window_save? */
+#define target_flags 0
+
+static int
+in_reg_window (int reg, frame_state *udata)
+{
+ if (udata->saved[reg] == REG_SAVED_REG)
+ return INCOMING_REGNO (reg) == reg;
+ if (udata->saved[reg] != REG_SAVED_OFFSET)
+ return 0;
+
+#ifdef STACK_GROWS_DOWNWARD
+ return udata->reg_or_offset[reg] > 0;
+#else
+ return udata->reg_or_offset[reg] < 0;
+#endif
+}
+#else
+static inline int in_reg_window (int reg, frame_state *udata) { return 0; }
+#endif /* INCOMING_REGNO */
+
+/* Get the address of register REG as saved in UDATA, where SUB_UDATA is a
frame called by UDATA or 0. */
-static void*
-get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
+static word_type *
+get_reg_addr (unsigned reg, frame_state *udata, frame_state *sub_udata)
{
+ while (udata->saved[reg] == REG_SAVED_REG)
+ {
+ reg = udata->reg_or_offset[reg];
+ if (in_reg_window (reg, udata))
+ {
+ udata = sub_udata;
+ sub_udata = NULL;
+ }
+ }
if (udata->saved[reg] == REG_SAVED_OFFSET)
- return (void *)(ptr_type)
- *(word_type *)(udata->cfa + udata->reg_or_offset[reg]);
- else if (udata->saved[reg] == REG_SAVED_REG && sub_udata)
- return get_reg (udata->reg_or_offset[reg], sub_udata, 0);
+ return (word_type *)(udata->cfa + udata->reg_or_offset[reg]);
else
abort ();
}
+/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
+ frame called by UDATA or 0. */
+
+static inline void *
+get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
+{
+ return (void *)(ptr_type) *get_reg_addr (reg, udata, sub_udata);
+}
+
/* Overwrite the saved value for register REG in frame UDATA with VAL. */
-static void
+static inline void
put_reg (unsigned reg, void *val, frame_state *udata)
{
- if (udata->saved[reg] == REG_SAVED_OFFSET)
- *(word_type *)(udata->cfa + udata->reg_or_offset[reg])
- = (word_type)(ptr_type) val;
- else
- abort ();
+ *get_reg_addr (reg, udata, NULL) = (word_type)(ptr_type) val;
}
/* Copy the saved value for register REG from frame UDATA to frame
@@ -3526,17 +3566,13 @@ put_reg (unsigned reg, void *val, frame_state *udata)
static void
copy_reg (unsigned reg, frame_state *udata, frame_state *target_udata)
{
- if (udata->saved[reg] == REG_SAVED_OFFSET
- && target_udata->saved[reg] == REG_SAVED_OFFSET)
- memcpy (target_udata->cfa + target_udata->reg_or_offset[reg],
- udata->cfa + udata->reg_or_offset[reg],
- __builtin_dwarf_reg_size (reg));
- else
- abort ();
+ word_type *preg = get_reg_addr (reg, udata, NULL);
+ word_type *ptreg = get_reg_addr (reg, target_udata, NULL);
+
+ memcpy (ptreg, preg, __builtin_dwarf_reg_size (reg));
}
-/* Retrieve the return address for frame UDATA, where SUB_UDATA is a
- frame called by UDATA or 0. */
+/* Retrieve the return address for frame UDATA. */
static inline void *
get_return_addr (frame_state *udata, frame_state *sub_udata)
@@ -3576,24 +3612,6 @@ next_stack_level (void *pc, frame_state *udata, frame_state *caller_udata)
return caller_udata;
}
-#ifdef INCOMING_REGNO
-/* Is the saved value for register REG in frame UDATA stored in a register
- window in the previous frame? */
-
-static int
-in_reg_window (int reg, frame_state *udata)
-{
- if (udata->saved[reg] != REG_SAVED_OFFSET)
- return 0;
-
-#ifdef STACK_GROWS_DOWNWARD
- return udata->reg_or_offset[reg] > 0;
-#else
- return udata->reg_or_offset[reg] < 0;
-#endif
-}
-#endif /* INCOMING_REGNO */
-
/* We first search for an exception handler, and if we don't find
it, we call __terminate on the current stack frame so that we may
use the debugger to walk the stack and understand why no handler
@@ -3606,7 +3624,7 @@ void
__throw ()
{
struct eh_context *eh = (*get_eh_context) ();
- void *saved_pc, *pc, *handler, *retaddr;
+ void *saved_pc, *pc, *handler;
frame_state ustruct, ustruct2;
frame_state *udata = &ustruct;
frame_state *sub_udata = &ustruct2;
@@ -3626,14 +3644,8 @@ label:
if (! udata)
__terminate ();
- /* We need to get the value from the CFA register. At this point in
- compiling __throw we don't know whether or not we will use the frame
- pointer register for the CFA, so we check our unwind info. */
- if (udata->cfa_reg == __builtin_dwarf_fp_regnum ())
- udata->cfa = __builtin_fp ();
- else
- udata->cfa = __builtin_sp ();
- udata->cfa += udata->cfa_offset;
+ /* We need to get the value from the CFA register. */
+ udata->cfa = __builtin_dwarf_cfa ();
memcpy (my_udata, udata, sizeof (*udata));
@@ -3712,7 +3724,6 @@ label:
for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
if (i != udata->retaddr_column && udata->saved[i])
{
-#ifdef INCOMING_REGNO
/* If you modify the saved value of the return address
register on the SPARC, you modify the return address for
your caller's frame. Don't do that here, as it will
@@ -3721,14 +3732,12 @@ label:
&& udata->saved[udata->retaddr_column] == REG_SAVED_REG
&& udata->reg_or_offset[udata->retaddr_column] == i)
continue;
-#endif
copy_reg (i, udata, my_udata);
}
pc = get_return_addr (udata, sub_udata) - 1;
}
-#ifdef INCOMING_REGNO
/* But we do need to update the saved return address register from
the last frame we unwind, or the handler frame will have the wrong
return address. */
@@ -3738,42 +3747,17 @@ label:
if (in_reg_window (i, udata))
copy_reg (i, udata, my_udata);
}
-#endif
}
- /* udata now refers to the frame called by the handler frame. */
- /* Emit the stub to adjust sp and jump to the handler. */
- if (new_exception_model)
- retaddr = __builtin_eh_stub ();
- else
- retaddr = __builtin_eh_stub_old ();
-
- /* And then set our return address to point to the stub. */
- if (my_udata->saved[my_udata->retaddr_column] == REG_SAVED_OFFSET)
- put_return_addr (retaddr, my_udata);
- else
- __builtin_set_return_addr_reg (retaddr);
-
- /* Set up the registers we use to communicate with the stub.
- We check STACK_GROWS_DOWNWARD so the stub can use adjust_stack. */
-
- if (new_exception_model)
- __builtin_set_eh_regs ((void *)eh,
-#ifdef STACK_GROWS_DOWNWARD
- udata->cfa - my_udata->cfa
-#else
- my_udata->cfa - udata->cfa
-#endif
- + args_size);
- else
- __builtin_set_eh_regs (handler,
+ /* Now go! */
+ __builtin_eh_return ((void *)eh,
#ifdef STACK_GROWS_DOWNWARD
- udata->cfa - my_udata->cfa
+ udata->cfa - my_udata->cfa,
#else
- my_udata->cfa - udata->cfa
+ my_udata->cfa - udata->cfa,
#endif
- + args_size);
+ handler);
/* Epilogue: restore the handler frame's register values and return
to the stub. */
diff --git a/gcc/rtl.h b/gcc/rtl.h
index eac66714e45..e72fd602596 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -1055,6 +1055,7 @@ extern struct _global_rtl
struct rtx_def virtual_stack_vars_val;
struct rtx_def virtual_stack_dynamic_val;
struct rtx_def virtual_outgoing_args_val;
+ struct rtx_def virtual_cfa_val;
} global_rtl;
/* All references to certain hard regs, except those created
@@ -1159,7 +1160,17 @@ extern rtx gen_rtx_MEM PROTO((enum machine_mode, rtx));
#define VIRTUAL_OUTGOING_ARGS_REGNUM ((FIRST_VIRTUAL_REGISTER) + 3)
-#define LAST_VIRTUAL_REGISTER ((FIRST_VIRTUAL_REGISTER) + 3)
+/* This points to the Canonical Frame Address of the function. This
+ should corrospond to the CFA produced by INCOMING_FRAME_SP_OFFSET,
+ but is calculated relative to the arg pointer for simplicity; the
+ frame pointer nor stack pointer are necessarily fixed relative to
+ the CFA until after reload. */
+
+#define virtual_cfa_rtx (&global_rtl.virtual_cfa_val)
+
+#define VIRTUAL_CFA_REGNUM ((FIRST_VIRTUAL_REGISTER) + 4)
+
+#define LAST_VIRTUAL_REGISTER ((FIRST_VIRTUAL_REGISTER) + 4)
extern rtx find_next_ref PROTO((rtx, rtx));
extern rtx *find_single_use PROTO((rtx, rtx, rtx *));
diff --git a/gcc/tm.texi b/gcc/tm.texi
index bf6fdd155b1..ea3e8b3110a 100644
--- a/gcc/tm.texi
+++ b/gcc/tm.texi
@@ -2277,6 +2277,17 @@ previous frame, just before the call instruction.
You only need to define this macro if you want to support call frame
debugging information like that provided by DWARF 2.
+
+@findex ARG_POINTER_CFA_OFFSET
+@item ARG_POINTER_CFA_OFFSET
+A C expression whose value is an integer giving the offset, in bytes,
+from the argument pointer to the canonical frame address (cfa). The
+final value should coincide with that calculated by
+@code{INCOMING_FRAME_SP_OFFSET}. Which is unfortunately not usable
+during virtual register instantiation.
+
+You only need to define this macro if you want to support call frame
+debugging information like that provided by DWARF 2.
@end table
@node Stack Checking
diff --git a/gcc/tree.h b/gcc/tree.h
index aee712fc97f..58293e49d5e 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -101,7 +101,6 @@ enum built_in_function
BUILT_IN_FRAME_ADDRESS,
BUILT_IN_RETURN_ADDRESS,
BUILT_IN_AGGREGATE_INCOMING_ADDRESS,
- BUILT_IN_CALLER_RETURN_ADDRESS,
BUILT_IN_APPLY_ARGS,
BUILT_IN_APPLY,
BUILT_IN_RETURN,
@@ -110,16 +109,13 @@ enum built_in_function
BUILT_IN_TRAP,
/* Various hooks for the DWARF 2 __throw routine. */
- BUILT_IN_FP, BUILT_IN_SP,
BUILT_IN_UNWIND_INIT,
+ BUILT_IN_DWARF_CFA,
BUILT_IN_DWARF_FP_REGNUM,
BUILT_IN_DWARF_REG_SIZE,
BUILT_IN_FROB_RETURN_ADDR,
BUILT_IN_EXTRACT_RETURN_ADDR,
- BUILT_IN_SET_RETURN_ADDR_REG,
- BUILT_IN_EH_STUB_OLD,
- BUILT_IN_EH_STUB,
- BUILT_IN_SET_EH_REGS,
+ BUILT_IN_EH_RETURN,
/* C++ extensions */
BUILT_IN_NEW,
OpenPOWER on IntegriCloud