/* Implements exception handling.
Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
Contributed by Mike Stump <mrs@cygnus.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* An exception is an event that can be signaled from within a
*n = *old;
n->outer = outer;
+ n->next_peer = NULL;
gcc_assert (!old->aka);
n->region_number += eh_offset;
for (prev_try = VEC_index (eh_region, cfun->eh->region_array, outer_region);
prev_try && prev_try->type != ERT_TRY;
prev_try = prev_try->outer)
- ;
+ if (prev_try->type == ERT_MUST_NOT_THROW)
+ {
+ prev_try = NULL;
+ break;
+ }
/* Remap all of the internal catch and cleanup linkages. Since we
duplicate entire subtrees, all of the referenced regions will have
static int
t2r_eq (const void *pentry, const void *pdata)
{
- tree entry = (tree) pentry;
- tree data = (tree) pdata;
+ const_tree const entry = (const_tree) pentry;
+ const_tree const data = (const_tree) pdata;
return TREE_PURPOSE (entry) == data;
}
static hashval_t
t2r_hash (const void *pentry)
{
- tree entry = (tree) pentry;
+ const_tree const entry = (const_tree) pentry;
return TREE_HASH (TREE_PURPOSE (entry));
}
static int
ttypes_filter_eq (const void *pentry, const void *pdata)
{
- const struct ttypes_filter *entry = (const struct ttypes_filter *) pentry;
- tree data = (tree) pdata;
+ const struct ttypes_filter *const entry
+ = (const struct ttypes_filter *) pentry;
+ const_tree const data = (const_tree) pdata;
return entry->t == data;
}
dw2_build_landing_pads (void)
{
int i;
- unsigned int j;
for (i = cfun->eh->last_region_number; i > 0; --i)
{
struct eh_region *region;
rtx seq;
basic_block bb;
- bool clobbers_hard_regs = false;
edge e;
region = VEC_index (eh_region, cfun->eh->region_array, i);
#endif
{ /* Nothing */ }
- /* If the eh_return data registers are call-saved, then we
- won't have considered them clobbered from the call that
- threw. Kill them now. */
- for (j = 0; ; ++j)
- {
- unsigned r = EH_RETURN_DATA_REGNO (j);
- if (r == INVALID_REGNUM)
- break;
- if (! call_used_regs[r])
- {
- emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, r)));
- clobbers_hard_regs = true;
- }
- }
-
- if (clobbers_hard_regs)
- {
- /* @@@ This is a kludge. Not all machine descriptions define a
- blockage insn, but we must not allow the code we just generated
- to be reordered by scheduling. So emit an ASM_INPUT to act as
- blockage insn. */
- emit_insn (gen_rtx_ASM_INPUT (VOIDmode, ""));
- }
-
emit_move_insn (cfun->eh->exc_ptr,
gen_rtx_REG (ptr_mode, EH_RETURN_DATA_REGNO (0)));
emit_move_insn (cfun->eh->filter,
#ifdef DONT_USE_BUILTIN_SETJMP
{
- rtx x, note;
+ rtx x;
x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_RETURNS_TWICE,
TYPE_MODE (integer_type_node), 1,
plus_constant (XEXP (fc, 0),
sjlj_fc_jbuf_ofs), Pmode);
- note = emit_note (NOTE_INSN_EXPECTED_VALUE);
- NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, x, const0_rtx);
-
emit_cmp_and_jump_insns (x, const0_rtx, NE, 0,
TYPE_MODE (integer_type_node), 0, dispatch_label);
+ add_reg_br_prob_note (get_insns (), REG_BR_PROB_BASE/100);
}
#else
expand_builtin_setjmp_setup (plus_constant (XEXP (fc, 0), sjlj_fc_jbuf_ofs),
for (fn_begin = get_insns (); ; fn_begin = NEXT_INSN (fn_begin))
if (NOTE_P (fn_begin))
{
- if (NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG)
+ if (NOTE_KIND (fn_begin) == NOTE_INSN_FUNCTION_BEG)
break;
- else if (NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_BASIC_BLOCK)
+ else if (NOTE_INSN_BASIC_BLOCK_P (fn_begin))
fn_begin_outside_block = false;
}
/* We've totally changed the CFG. Start over. */
find_exception_handler_labels ();
break_superblocks ();
- if (USING_SJLJ_EXCEPTIONS)
+ if (USING_SJLJ_EXCEPTIONS
+ /* Kludge for Alpha/Tru64 (see alpha_gp_save_rtx). */
+ || single_succ_edge (ENTRY_BLOCK_PTR)->insns.r)
commit_edge_insertions ();
FOR_EACH_BB (bb)
{
static hashval_t
ehl_hash (const void *pentry)
{
- struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry;
+ const struct ehl_map_entry *const entry
+ = (const struct ehl_map_entry *) pentry;
/* 2^32 * ((sqrt(5) - 1) / 2) */
const hashval_t scaled_golden_ratio = 0x9e3779b9;
static int
ehl_eq (const void *pentry, const void *pdata)
{
- struct ehl_map_entry *entry = (struct ehl_map_entry *) pentry;
- struct ehl_map_entry *data = (struct ehl_map_entry *) pdata;
+ const struct ehl_map_entry *const entry
+ = (const struct ehl_map_entry *) pentry;
+ const struct ehl_map_entry *const data
+ = (const struct ehl_map_entry *) pdata;
return entry->label == data->label;
}
}
bool
-can_throw_internal (rtx insn)
+can_throw_internal (const_rtx insn)
{
rtx note;
}
bool
-can_throw_external (rtx insn)
+can_throw_external (const_rtx insn)
{
rtx note;
{
rtx insn;
+ /* If we don't know that this implementation of the function will
+ actually be used, then we must not set TREE_NOTHROW, since
+ callers must not assume that this function does not throw. */
+ if (DECL_REPLACEABLE_P (current_function_decl))
+ return 0;
+
TREE_NOTHROW (current_function_decl) = 1;
/* Assume cfun->all_throwers_are_sibcalls until we encounter
{
/* Set this so all the registers get saved in our frame; we need to be
able to copy the saved values for any registers from frames we unwind. */
- current_function_has_nonlocal_label = 1;
+ current_function_saves_all_registers = 1;
#ifdef SETUP_FRAME_ADDRESSES
SETUP_FRAME_ADDRESSES ();
}
rtx
-expand_builtin_eh_return_data_regno (tree arglist)
+expand_builtin_eh_return_data_regno (tree exp)
{
- tree which = TREE_VALUE (arglist);
+ tree which = CALL_EXPR_ARG (exp, 0);
unsigned HOST_WIDE_INT iwhich;
if (TREE_CODE (which) != INTEGER_CST)
rtx
expand_builtin_extract_return_addr (tree addr_tree)
{
- rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
+ rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
if (GET_MODE (addr) != Pmode
&& GET_MODE (addr) != VOIDmode)
rtx
expand_builtin_frob_return_addr (tree addr_tree)
{
- rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, 0);
+ rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, EXPAND_NORMAL);
addr = convert_memory_address (Pmode, addr);
rtx tmp;
#ifdef EH_RETURN_STACKADJ_RTX
- tmp = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj, VOIDmode, 0);
+ tmp = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj,
+ VOIDmode, EXPAND_NORMAL);
tmp = convert_memory_address (Pmode, tmp);
if (!cfun->eh->ehr_stackadj)
cfun->eh->ehr_stackadj = copy_to_reg (tmp);
emit_move_insn (cfun->eh->ehr_stackadj, tmp);
#endif
- tmp = expand_expr (handler_tree, cfun->eh->ehr_handler, VOIDmode, 0);
+ tmp = expand_expr (handler_tree, cfun->eh->ehr_handler,
+ VOIDmode, EXPAND_NORMAL);
tmp = convert_memory_address (Pmode, tmp);
if (!cfun->eh->ehr_handler)
cfun->eh->ehr_handler = copy_to_reg (tmp);
rtx
expand_builtin_extend_pointer (tree addr_tree)
{
- rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, 0);
+ rtx addr = expand_expr (addr_tree, NULL_RTX, ptr_mode, EXPAND_NORMAL);
int extend;
#ifdef POINTERS_EXTEND_UNSIGNED
/* Switch to the section that should be used for exception tables. */
static void
-switch_to_exception_section (void)
+switch_to_exception_section (const char * ARG_UNUSED (fnname))
{
- if (exception_section == 0)
+ section *s;
+
+ if (exception_section)
+ s = exception_section;
+ else
{
+ /* Compute the section and cache it into exception_section,
+ unless it depends on the function name. */
if (targetm.have_named_sections)
{
int flags;
}
else
flags = SECTION_WRITE;
- exception_section = get_section (".gcc_except_table", flags, NULL);
+
+#ifdef HAVE_LD_EH_GC_SECTIONS
+ if (flag_function_sections)
+ {
+ char *section_name = xmalloc (strlen (fnname) + 32);
+ sprintf (section_name, ".gcc_except_table.%s", fnname);
+ s = get_section (section_name, flags, NULL);
+ free (section_name);
+ }
+ else
+#endif
+ exception_section
+ = s = get_section (".gcc_except_table", flags, NULL);
}
else
- exception_section = flag_pic ? data_section : readonly_data_section;
+ exception_section
+ = s = flag_pic ? data_section : readonly_data_section;
}
- switch_to_section (exception_section);
+
+ switch_to_section (s);
}
#endif
value = const0_rtx;
else
{
- struct cgraph_varpool_node *node;
+ struct varpool_node *node;
type = lookup_type_for_runtime (type);
value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
type = TREE_OPERAND (type, 0);
if (TREE_CODE (type) == VAR_DECL)
{
- node = cgraph_varpool_node (type);
+ node = varpool_node (type);
if (node)
- cgraph_varpool_mark_needed_node (node);
+ varpool_mark_needed_node (node);
public = TREE_PUBLIC (type);
}
}
}
void
-output_function_exception_table (void)
+output_function_exception_table (const char * ARG_UNUSED (fnname))
{
int tt_format, cs_format, lp_format, i, n;
#ifdef HAVE_AS_LEB128
int have_tt_data;
int tt_format_size = 0;
- if (eh_personality_libfunc)
- assemble_external_libcall (eh_personality_libfunc);
-
/* Not all functions need anything. */
if (! cfun->uses_eh_lsda)
return;
+ if (eh_personality_libfunc)
+ assemble_external_libcall (eh_personality_libfunc);
+
#ifdef TARGET_UNWIND_INFO
/* TODO: Move this into target file. */
fputs ("\t.personality\t", asm_out_file);
/* Note that varasm still thinks we're in the function's code section.
The ".endp" directive that will immediately follow will take us back. */
#else
- switch_to_exception_section ();
+ switch_to_exception_section (fnname);
#endif
/* If the target wants a label to begin the table, emit it here. */