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, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
/* An exception is an event that can be signaled from within a
#include "langhooks.h"
#include "cgraph.h"
#include "diagnostic.h"
+#include "tree-pass.h"
+#include "timevar.h"
/* Provide defaults for stuff that may not be defined when using
sjlj exceptions. */
ERT_CATCH,
ERT_ALLOWED_EXCEPTIONS,
ERT_MUST_NOT_THROW,
- ERT_THROW,
- ERT_FIXUP
+ ERT_THROW
} type;
/* Holds the action to perform based on the preceding type. */
struct eh_region_u_try {
struct eh_region *catch;
struct eh_region *last_catch;
- struct eh_region *prev_try;
- rtx continue_label;
} GTY ((tag ("ERT_TRY"))) try;
/* The list through the catch handlers, the list of type objects
struct eh_region_u_cleanup {
struct eh_region *prev_try;
} GTY ((tag ("ERT_CLEANUP"))) cleanup;
-
- /* The real region (by expression and by pointer) that fixup code
- should live in. */
- struct eh_region_u_fixup {
- struct eh_region *real_region;
- bool resolved;
- } GTY ((tag ("ERT_FIXUP"))) fixup;
} GTY ((desc ("%0.type"))) u;
/* Entry point for this region's handler before landing pads are built. */
unsigned may_contain_throw : 1;
};
+typedef struct eh_region *eh_region;
+
struct call_site_record GTY(())
{
rtx landing_pad;
int action;
};
+DEF_VEC_P(eh_region);
+DEF_VEC_ALLOC_P(eh_region, gc);
+
/* Used to save exception status for each function. */
struct eh_status GTY(())
{
struct eh_region *region_tree;
/* The same information as an indexable array. */
- struct eh_region ** GTY ((length ("%h.last_region_number"))) region_array;
+ VEC(eh_region,gc) *region_array;
/* The most recently open region. */
struct eh_region *cur_region;
expand_resx_expr (tree exp)
{
int region_nr = TREE_INT_CST_LOW (TREE_OPERAND (exp, 0));
- struct eh_region *reg = cfun->eh->region_array[region_nr];
+ struct eh_region *reg = VEC_index (eh_region,
+ cfun->eh->region_array, region_nr);
+ gcc_assert (!reg->resume);
reg->resume = emit_jump_insn (gen_rtx_RESX (VOIDmode, region_nr));
emit_barrier ();
}
void
collect_eh_region_array (void)
{
- struct eh_region **array, *i;
+ struct eh_region *i;
i = cfun->eh->region_tree;
if (! i)
return;
- array = ggc_alloc_cleared ((cfun->eh->last_region_number + 1)
- * sizeof (*array));
- cfun->eh->region_array = array;
+ VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
+ cfun->eh->last_region_number + 1);
+ VEC_replace (eh_region, cfun->eh->region_array, 0, 0);
while (1)
{
- array[i->region_number] = i;
+ VEC_replace (eh_region, cfun->eh->region_array, i->region_number, i);
/* If there are sub-regions, process them. */
if (i->inner)
for (i = cfun->eh->last_region_number; i > 0; --i)
{
- r = cfun->eh->region_array[i];
+ r = VEC_index (eh_region, cfun->eh->region_array, i);
if (!r || r->region_number != i)
continue;
for (i = cfun->eh->last_region_number; i > 0; --i)
{
- r = cfun->eh->region_array[i];
+ r = VEC_index (eh_region, cfun->eh->region_array, i);
if (r && r->region_number == i && !reachable[i])
{
bool kill_it = true;
we allocated earlier. */
for (i = 1; i <= n; ++i)
{
- struct eh_region *region = cfun->eh->region_array[i];
+ struct eh_region *region;
+
+ region = VEC_index (eh_region, cfun->eh->region_array, i);
if (region && region->tree_label)
region->label = DECL_RTL_IF_SET (region->tree_label);
}
for (i = cfun->eh->last_region_number; i > 0; --i)
{
- struct eh_region *region = cfun->eh->region_array[i];
+ struct eh_region *region;
rtx lab;
+ region = VEC_index (eh_region, cfun->eh->region_array, i);
if (! region || region->region_number != i)
continue;
if (cfun->eh->built_landing_pads)
add_ehl_entry (return_label, NULL);
}
+/* Returns true if the current function has exception handling regions. */
+
bool
current_function_has_exception_handlers (void)
{
for (i = cfun->eh->last_region_number; i > 0; --i)
{
- struct eh_region *region = cfun->eh->region_array[i];
+ struct eh_region *region;
- if (! region || region->region_number != i)
- continue;
- if (region->type != ERT_THROW)
+ region = VEC_index (eh_region, cfun->eh->region_array, i);
+ if (region
+ && region->region_number == i
+ && region->type != ERT_THROW)
return true;
}
return false;
}
\f
+static struct eh_region *
+duplicate_eh_region_1 (struct eh_region *o)
+{
+ struct eh_region *n = ggc_alloc_cleared (sizeof (struct eh_region));
+
+ *n = *o;
+
+ n->region_number = o->region_number + cfun->eh->last_region_number;
+ VEC_replace (eh_region, cfun->eh->region_array, n->region_number, n);
+ gcc_assert (!o->aka);
+
+ return n;
+}
+
+static void
+duplicate_eh_region_2 (struct eh_region *o, struct eh_region **n_array,
+ struct eh_region *prev_try)
+{
+ struct eh_region *n = n_array[o->region_number];
+
+ switch (n->type)
+ {
+ case ERT_TRY:
+ if (o->u.try.catch)
+ n->u.try.catch = n_array[o->u.try.catch->region_number];
+ if (o->u.try.last_catch)
+ n->u.try.last_catch = n_array[o->u.try.last_catch->region_number];
+ break;
+
+ case ERT_CATCH:
+ if (o->u.catch.next_catch)
+ n->u.catch.next_catch = n_array[o->u.catch.next_catch->region_number];
+ if (o->u.catch.prev_catch)
+ n->u.catch.prev_catch = n_array[o->u.catch.prev_catch->region_number];
+ break;
+
+ case ERT_CLEANUP:
+ if (o->u.cleanup.prev_try)
+ n->u.cleanup.prev_try = n_array[o->u.cleanup.prev_try->region_number];
+ else
+ n->u.cleanup.prev_try = prev_try;
+ break;
+
+ default:
+ break;
+ }
+
+ if (o->outer)
+ n->outer = n_array[o->outer->region_number];
+ if (o->inner)
+ n->inner = n_array[o->inner->region_number];
+ if (o->next_peer)
+ n->next_peer = n_array[o->next_peer->region_number];
+}
+
+/* Duplicate the EH regions of IFUN into current function, root the tree in
+ OUTER_REGION and remap labels using MAP callback. */
+int
+duplicate_eh_regions (struct function *ifun, duplicate_eh_regions_map map,
+ void *data, int outer_region)
+{
+ int ifun_last_region_number = ifun->eh->last_region_number;
+ struct eh_region **n_array, *root, *cur, *prev_try;
+ int i;
+
+ if (ifun_last_region_number == 0 || !ifun->eh->region_tree)
+ return 0;
+
+ n_array = xcalloc (ifun_last_region_number + 1, sizeof (*n_array));
+ VEC_safe_grow (eh_region, gc, cfun->eh->region_array,
+ cfun->eh->last_region_number + 1 + ifun_last_region_number);
+
+ /* We might've created new cfun->eh->region_array so zero out nonexisting region 0. */
+ VEC_replace (eh_region, cfun->eh->region_array, 0, 0);
+
+ for (i = cfun->eh->last_region_number + 1;
+ i < cfun->eh->last_region_number + 1 + ifun_last_region_number; i++)
+ VEC_replace (eh_region, cfun->eh->region_array, i, 0);
+
+ /* Search for the containing ERT_TRY region to fix up
+ the prev_try short-cuts for ERT_CLEANUP regions. */
+ prev_try = NULL;
+ if (outer_region > 0)
+ 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)
+ ;
+
+ for (i = 1; i <= ifun_last_region_number; ++i)
+ {
+ cur = VEC_index (eh_region, ifun->eh->region_array, i);
+ if (!cur || cur->region_number != i)
+ continue;
+ n_array[i] = duplicate_eh_region_1 (cur);
+ if (cur->tree_label)
+ {
+ tree newlabel = map (cur->tree_label, data);
+ n_array[i]->tree_label = newlabel;
+ }
+ else
+ n_array[i]->tree_label = NULL;
+ }
+ for (i = 1; i <= ifun_last_region_number; ++i)
+ {
+ cur = VEC_index (eh_region, ifun->eh->region_array, i);
+ if (!cur || cur->region_number != i)
+ continue;
+ duplicate_eh_region_2 (cur, n_array, prev_try);
+ }
+
+ root = n_array[ifun->eh->region_tree->region_number];
+ gcc_assert (root->outer == NULL);
+ if (outer_region > 0)
+ {
+ struct eh_region *cur
+ = VEC_index (eh_region, cfun->eh->region_array, outer_region);
+ struct eh_region *p = cur->inner;
+
+ if (p)
+ {
+ while (p->next_peer)
+ p = p->next_peer;
+ p->next_peer = root;
+ }
+ else
+ cur->inner = root;
+ for (i = 1; i <= ifun_last_region_number; ++i)
+ if (n_array[i] && n_array[i]->outer == NULL)
+ n_array[i]->outer = cur;
+ }
+ else
+ {
+ struct eh_region *p = cfun->eh->region_tree;
+ if (p)
+ {
+ while (p->next_peer)
+ p = p->next_peer;
+ p->next_peer = root;
+ }
+ else
+ cfun->eh->region_tree = root;
+ }
+
+ free (n_array);
+
+ i = cfun->eh->last_region_number;
+ cfun->eh->last_region_number = i + ifun_last_region_number;
+
+ return i;
+}
+\f
static int
t2r_eq (const void *pentry, const void *pdata)
{
n->filter = -(VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) + 1);
*slot = n;
- /* Look up each type in the list and encode its filter
- value as a uleb128. Terminate the list with 0. */
+ /* Generate a 0 terminated list of filter values. */
for (; list ; list = TREE_CHAIN (list))
- push_uleb128 (&cfun->eh->ehspec_data,
- add_ttypes_entry (ttypes_hash, TREE_VALUE (list)));
- VARRAY_PUSH_UCHAR (cfun->eh->ehspec_data, 0);
+ {
+ if (targetm.arm_eabi_unwinder)
+ VARRAY_PUSH_TREE (cfun->eh->ehspec_data, TREE_VALUE (list));
+ else
+ {
+ /* Look up each type in the list and encode its filter
+ value as a uleb128. */
+ push_uleb128 (&cfun->eh->ehspec_data,
+ add_ttypes_entry (ttypes_hash, TREE_VALUE (list)));
+ }
+ }
+ if (targetm.arm_eabi_unwinder)
+ VARRAY_PUSH_TREE (cfun->eh->ehspec_data, NULL_TREE);
+ else
+ VARRAY_PUSH_UCHAR (cfun->eh->ehspec_data, 0);
}
return n->filter;
htab_t ttypes, ehspec;
cfun->eh->ttype_data = VEC_alloc (tree, gc, 16);
- VARRAY_UCHAR_INIT (cfun->eh->ehspec_data, 64, "ehspec_data");
+ if (targetm.arm_eabi_unwinder)
+ VARRAY_TREE_INIT (cfun->eh->ehspec_data, 64, "ehspec_data");
+ else
+ VARRAY_UCHAR_INIT (cfun->eh->ehspec_data, 64, "ehspec_data");
ttypes = htab_create (31, ttypes_filter_hash, ttypes_filter_eq, free);
ehspec = htab_create (31, ehspec_filter_hash, ehspec_filter_eq, free);
for (i = cfun->eh->last_region_number; i > 0; --i)
{
- struct eh_region *r = cfun->eh->region_array[i];
+ struct eh_region *r;
+
+ r = VEC_index (eh_region, cfun->eh->region_array, i);
/* Mind we don't process a region more than once. */
if (!r || r->region_number != i)
for (i = cfun->eh->last_region_number; i > 0; --i)
{
- struct eh_region *region = cfun->eh->region_array[i];
+ struct eh_region *region;
rtx seq;
+ region = VEC_index (eh_region, cfun->eh->region_array, i);
/* Mind we don't process a region more than once. */
if (!region || region->region_number != i)
continue;
for (i = cfun->eh->last_region_number; i > 0; --i)
{
- struct eh_region *region = cfun->eh->region_array[i];
+ struct eh_region *region;
struct eh_region *outer;
rtx seq;
rtx barrier;
+ region = VEC_index (eh_region, cfun->eh->region_array, i);
/* Mind we don't process a region more than once. */
if (!region || region->region_number != i)
continue;
for (i = cfun->eh->last_region_number; i > 0; --i)
{
- struct eh_region *region = cfun->eh->region_array[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);
/* Mind we don't process a region more than once. */
if (!region || region->region_number != i)
continue;
if (!note || INTVAL (XEXP (note, 0)) <= 0)
continue;
- region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
+ region = VEC_index (eh_region, cfun->eh->region_array, INTVAL (XEXP (note, 0)));
type_thrown = NULL_TREE;
if (region->type == ERT_THROW)
for (i = cfun->eh->last_region_number; i > 0; --i)
if (lp_info[i].directly_reachable)
{
- struct eh_region *r = cfun->eh->region_array[i];
+ struct eh_region *r = VEC_index (eh_region, cfun->eh->region_array, i);
+
r->landing_pad = dispatch_label;
lp_info[i].action_index = collect_one_action_chain (ar_hash, r);
if (lp_info[i].action_index != -1)
if (INTVAL (XEXP (note, 0)) <= 0)
continue;
- region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
+ region = VEC_index (eh_region, cfun->eh->region_array, INTVAL (XEXP (note, 0)));
this_call_site = lp_info[region->region_number].call_site_index;
}
sjlj_emit_function_enter (rtx dispatch_label)
{
rtx fn_begin, fc, mem, seq;
+ bool fn_begin_outside_block;
fc = cfun->eh->sjlj_fc;
do this in a block that is at loop level 0 and dominates all
can_throw_internal instructions. */
+ fn_begin_outside_block = true;
for (fn_begin = get_insns (); ; fn_begin = NEXT_INSN (fn_begin))
- if (NOTE_P (fn_begin)
- && (NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG
- || NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_BASIC_BLOCK))
- break;
- if (NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG)
+ if (NOTE_P (fn_begin))
+ {
+ if (NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG)
+ break;
+ else if (NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_BASIC_BLOCK)
+ fn_begin_outside_block = false;
+ }
+
+ if (fn_begin_outside_block)
insert_insn_on_edge (seq, single_succ_edge (ENTRY_BLOCK_PTR));
else
- {
- rtx last = BB_END (single_succ (ENTRY_BLOCK_PTR));
- for (; ; fn_begin = NEXT_INSN (fn_begin))
- if ((NOTE_P (fn_begin)
- && NOTE_LINE_NUMBER (fn_begin) == NOTE_INSN_FUNCTION_BEG)
- || fn_begin == last)
- break;
- emit_insn_after (seq, fn_begin);
- }
+ emit_insn_after (seq, fn_begin);
}
/* Call back from expand_function_end to know where we should put
emit_cmp_and_jump_insns (dispatch, GEN_INT (lp_info[i].dispatch_index),
EQ, NULL_RTX, TYPE_MODE (integer_type_node), 0,
- cfun->eh->region_array[i]->post_landing_pad);
+ ((struct eh_region *)VEC_index (eh_region, cfun->eh->region_array, i))
+ ->post_landing_pad);
}
seq = get_insns ();
end_sequence ();
- before = cfun->eh->region_array[first_reachable]->post_landing_pad;
+ before = (((struct eh_region *)VEC_index (eh_region, cfun->eh->region_array, first_reachable))
+ ->post_landing_pad);
bb = emit_to_new_bb_before (seq, before);
e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
list of alternate numbers by which we are known. */
outer = region->outer;
- cfun->eh->region_array[region->region_number] = outer;
+ VEC_replace (eh_region, cfun->eh->region_array, region->region_number, outer);
if (region->aka)
{
unsigned i;
EXECUTE_IF_SET_IN_BITMAP (region->aka, 0, i, bi)
{
- cfun->eh->region_array[i] = outer;
+ VEC_replace (eh_region, cfun->eh->region_array, i, outer);
}
}
int i, n = cfun->eh->last_region_number;
for (i = 1; i <= n; ++i)
{
- struct eh_region *region = cfun->eh->region_array[i];
+ struct eh_region *region;
+
+ region = VEC_index (eh_region, cfun->eh->region_array, i);
if (region)
(*callback) (region);
}
/* Here we end our search, since no exceptions may propagate.
If we've touched down at some landing pad previous, then the
explicit function call we generated may be used. Otherwise
- the call is made by the runtime. */
- if (info && info->saw_any_handlers)
+ the call is made by the runtime.
+
+ Before inlining, do not perform this optimization. We may
+ inline a subroutine that contains handlers, and that will
+ change the value of saw_any_handlers. */
+
+ if ((info && info->saw_any_handlers) || !cfun->after_inlining)
{
add_reachable_handler (info, region, region);
return RNL_CAUGHT;
return RNL_BLOCKED;
case ERT_THROW:
- case ERT_FIXUP:
case ERT_UNKNOWN:
/* Shouldn't see these here. */
gcc_unreachable ();
info.callback = callback;
info.callback_data = callback_data;
- region = cfun->eh->region_array[region_number];
+ region = VEC_index (eh_region, cfun->eh->region_array, region_number);
type_thrown = NULL_TREE;
if (is_resx)
within the function. */
bool
-can_throw_internal_1 (int region_number)
+can_throw_internal_1 (int region_number, bool is_resx)
{
struct eh_region *region;
tree type_thrown;
- region = cfun->eh->region_array[region_number];
+ region = VEC_index (eh_region, cfun->eh->region_array, region_number);
type_thrown = NULL_TREE;
- if (region->type == ERT_THROW)
+ if (is_resx)
+ region = region->outer;
+ else if (region->type == ERT_THROW)
{
type_thrown = region->u.throw.type;
region = region->outer;
if (JUMP_P (insn)
&& GET_CODE (PATTERN (insn)) == RESX
&& XINT (PATTERN (insn), 0) > 0)
- return can_throw_internal_1 (XINT (PATTERN (insn), 0));
+ return can_throw_internal_1 (XINT (PATTERN (insn), 0), true);
if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
if (!note || INTVAL (XEXP (note, 0)) <= 0)
return false;
- return can_throw_internal_1 (INTVAL (XEXP (note, 0)));
+ return can_throw_internal_1 (INTVAL (XEXP (note, 0)), false);
}
/* Determine if the given INSN can throw an exception that is
visible outside the function. */
bool
-can_throw_external_1 (int region_number)
+can_throw_external_1 (int region_number, bool is_resx)
{
struct eh_region *region;
tree type_thrown;
- region = cfun->eh->region_array[region_number];
+ region = VEC_index (eh_region, cfun->eh->region_array, region_number);
type_thrown = NULL_TREE;
- if (region->type == ERT_THROW)
+ if (is_resx)
+ region = region->outer;
+ else if (region->type == ERT_THROW)
{
type_thrown = region->u.throw.type;
region = region->outer;
if (! INSN_P (insn))
return false;
+ if (JUMP_P (insn)
+ && GET_CODE (PATTERN (insn)) == RESX
+ && XINT (PATTERN (insn), 0) > 0)
+ return can_throw_external_1 (XINT (PATTERN (insn), 0), true);
+
if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SEQUENCE)
insn = XVECEXP (PATTERN (insn), 0, 0);
if (INTVAL (XEXP (note, 0)) <= 0)
return false;
- return can_throw_external_1 (INTVAL (XEXP (note, 0)));
+ return can_throw_external_1 (INTVAL (XEXP (note, 0)), false);
}
/* Set TREE_NOTHROW and cfun->all_throwers_are_sibcalls. */
}
}
+struct tree_opt_pass pass_set_nothrow_function_flags =
+{
+ NULL, /* name */
+ NULL, /* gate */
+ set_nothrow_function_flags, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+ 0 /* letter */
+};
+
\f
/* Various hooks for unwind library. */
{
if (INTVAL (XEXP (note, 0)) <= 0)
continue;
- region = cfun->eh->region_array[INTVAL (XEXP (note, 0))];
+ region = VEC_index (eh_region, cfun->eh->region_array, INTVAL (XEXP (note, 0)));
this_action = collect_one_action_chain (ar_hash, region);
}
htab_delete (ar_hash);
}
+struct tree_opt_pass pass_convert_to_eh_region_ranges =
+{
+ "eh-ranges", /* name */
+ NULL, /* gate */
+ convert_to_eh_region_ranges, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ 0, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func, /* todo_flags_finish */
+ 0 /* letter */
+};
+
\f
static void
push_uleb128 (varray_type *data_area, unsigned int value)
readonly_data_section ();
}
+
+/* Output a reference from an exception table to the type_info object TYPE.
+ TT_FORMAT and TT_FORMAT_SIZE descibe the DWARF encoding method used for
+ the value. */
+
+static void
+output_ttype (tree type, int tt_format, int tt_format_size)
+{
+ rtx value;
+ bool public = true;
+
+ if (type == NULL_TREE)
+ value = const0_rtx;
+ else
+ {
+ struct cgraph_varpool_node *node;
+
+ type = lookup_type_for_runtime (type);
+ value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
+
+ /* Let cgraph know that the rtti decl is used. Not all of the
+ paths below go through assemble_integer, which would take
+ care of this for us. */
+ STRIP_NOPS (type);
+ if (TREE_CODE (type) == ADDR_EXPR)
+ {
+ type = TREE_OPERAND (type, 0);
+ if (TREE_CODE (type) == VAR_DECL)
+ {
+ node = cgraph_varpool_node (type);
+ if (node)
+ cgraph_varpool_mark_needed_node (node);
+ public = TREE_PUBLIC (type);
+ }
+ }
+ else if (TREE_CODE (type) != INTEGER_CST)
+ abort ();
+ }
+
+ /* Allow the target to override the type table entry format. */
+ if (targetm.asm_out.ttype (value))
+ return;
+
+ if (tt_format == DW_EH_PE_absptr || tt_format == DW_EH_PE_aligned)
+ assemble_integer (value, tt_format_size,
+ tt_format_size * BITS_PER_UNIT, 1);
+ else
+ dw2_asm_output_encoded_addr_rtx (tt_format, value, public, NULL);
+}
+
void
output_function_exception_table (void)
{
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;
#ifdef TARGET_UNWIND_INFO
/* TODO: Move this into target file. */
- assemble_external_libcall (eh_personality_libfunc);
fputs ("\t.personality\t", asm_out_file);
output_addr_const (asm_out_file, eh_personality_libfunc);
fputs ("\n\t.handlerdata\n", asm_out_file);
while (i-- > 0)
{
tree type = VEC_index (tree, cfun->eh->ttype_data, i);
- rtx value;
-
- if (type == NULL_TREE)
- value = const0_rtx;
- else
- {
- struct cgraph_varpool_node *node;
-
- type = lookup_type_for_runtime (type);
- value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
-
- /* Let cgraph know that the rtti decl is used. Not all of the
- paths below go through assemble_integer, which would take
- care of this for us. */
- STRIP_NOPS (type);
- if (TREE_CODE (type) == ADDR_EXPR)
- {
- type = TREE_OPERAND (type, 0);
- if (TREE_CODE (type) == VAR_DECL)
- {
- node = cgraph_varpool_node (type);
- if (node)
- cgraph_varpool_mark_needed_node (node);
- }
- }
- else
- gcc_assert (TREE_CODE (type) == INTEGER_CST);
- }
-
- if (tt_format == DW_EH_PE_absptr || tt_format == DW_EH_PE_aligned)
- assemble_integer (value, tt_format_size,
- tt_format_size * BITS_PER_UNIT, 1);
- else
- dw2_asm_output_encoded_addr_rtx (tt_format, value, NULL);
+ output_ttype (type, tt_format, tt_format_size);
}
#ifdef HAVE_AS_LEB128
/* ??? Decode and interpret the data for flag_debug_asm. */
n = VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data);
for (i = 0; i < n; ++i)
- dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->ehspec_data, i),
- (i ? NULL : "Exception specification table"));
+ {
+ if (targetm.arm_eabi_unwinder)
+ {
+ tree type = VARRAY_TREE (cfun->eh->ehspec_data, i);
+ output_ttype (type, tt_format, tt_format_size);
+ }
+ else
+ dw2_asm_output_data (1, VARRAY_UCHAR (cfun->eh->ehspec_data, i),
+ (i ? NULL : "Exception specification table"));
+ }
current_function_section (current_function_decl);
}
int depth = 0;
static const char * const type_name[] = {"unknown", "cleanup", "try", "catch",
"allowed_exceptions", "must_not_throw",
- "throw", "fixup"};
+ "throw"};
i = fun->eh->region_tree;
if (! i)
if (! i)
return;
for (j = fun->eh->last_region_number; j > 0; --j)
- if (fun->eh->region_array[j])
+ if ((i = VEC_index (eh_region, cfun->eh->region_array, j)))
{
count++;
- if (fun->eh->region_array[j]->region_number != j)
+ if (i->region_number != j)
{
error ("region_array is corrupted for region %i", i->region_number);
err = true;
while (1)
{
- if (fun->eh->region_array[i->region_number] != i)
+ if (VEC_index (eh_region, cfun->eh->region_array, i->region_number) != i)
{
error ("region_array is corrupted for region %i", i->region_number);
err = true;
{
if (depth != -1)
{
- error ("Tree list ends on depth %i", depth + 1);
+ error ("tree list ends on depth %i", depth + 1);
err = true;
}
if (count != nvisited)
if (err)
{
dump_eh_tree (stderr, fun);
- internal_error ("verify_eh_tree failed.");
+ internal_error ("verify_eh_tree failed");
}
return;
}
}
}
}
+
+/* Initialize unwind_resume_libfunc. */
+
+void
+default_init_unwind_resume_libfunc (void)
+{
+ /* The default c++ routines aren't actually c++ specific, so use those. */
+ unwind_resume_libfunc =
+ init_one_libfunc ( USING_SJLJ_EXCEPTIONS ? "_Unwind_SjLj_Resume"
+ : "_Unwind_Resume");
+}
+
+\f
+static bool
+gate_handle_eh (void)
+{
+ return doing_eh (0);
+}
+
+/* Complete generation of exception handling code. */
+static void
+rest_of_handle_eh (void)
+{
+ cleanup_cfg (CLEANUP_PRE_LOOP | CLEANUP_NO_INSN_DEL);
+ finish_eh_generation ();
+ cleanup_cfg (CLEANUP_PRE_LOOP | CLEANUP_NO_INSN_DEL);
+}
+
+struct tree_opt_pass pass_rtl_eh =
+{
+ "eh", /* name */
+ gate_handle_eh, /* gate */
+ rest_of_handle_eh, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_JUMP, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func, /* todo_flags_finish */
+ 'h' /* letter */
+};
+
#include "gt-except.h"