/* Implements exception handling.
- Copyright (C) 1989-2014 Free Software Foundation, Inc.
+ Copyright (C) 1989-2015 Free Software Foundation, Inc.
Contributed by Mike Stump <mrs@cygnus.com>.
This file is part of GCC.
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
#include "stringpool.h"
#include "stor-layout.h"
#include "flags.h"
+#include "hard-reg-set.h"
#include "function.h"
+#include "insn-codes.h"
+#include "optabs.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
#include "expr.h"
#include "libfuncs.h"
-#include "insn-config.h"
#include "except.h"
-#include "hard-reg-set.h"
#include "output.h"
#include "dwarf2asm.h"
#include "dwarf2out.h"
#include "dwarf2.h"
#include "toplev.h"
-#include "hash-table.h"
#include "intl.h"
#include "tm_p.h"
#include "target.h"
#include "common/common-target.h"
#include "langhooks.h"
+#include "predict.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "basic-block.h"
#include "cgraph.h"
#include "diagnostic.h"
#include "tree-pretty-print.h"
#include "tree-pass.h"
#include "cfgloop.h"
#include "builtins.h"
-
-/* Provide defaults for stuff that may not be defined when using
- sjlj exceptions. */
-#ifndef EH_RETURN_DATA_REGNO
-#define EH_RETURN_DATA_REGNO(N) INVALID_REGNUM
-#endif
+#include "tree-hash-traits.h"
static GTY(()) int call_site_base;
-struct tree_hash_traits : default_hashmap_traits
-{
- static hashval_t hash (tree t) { return TREE_HASH (t); }
-};
-
-static GTY (()) hash_map<tree, tree, tree_hash_traits> *type_to_runtime_map;
+static GTY (()) hash_map<tree_hash, tree> *type_to_runtime_map;
/* Describe the SjLj_Function_Context structure. */
static GTY(()) tree sjlj_fc_type_node;
/* Hashtable helpers. */
-struct action_record_hasher : typed_free_remove <action_record>
+struct action_record_hasher : free_ptr_hash <action_record>
{
- typedef action_record value_type;
- typedef action_record compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
+ static inline hashval_t hash (const action_record *);
+ static inline bool equal (const action_record *, const action_record *);
};
inline hashval_t
-action_record_hasher::hash (const value_type *entry)
+action_record_hasher::hash (const action_record *entry)
{
return entry->next * 1009 + entry->filter;
}
inline bool
-action_record_hasher::equal (const value_type *entry, const compare_type *data)
+action_record_hasher::equal (const action_record *entry,
+ const action_record *data)
{
return entry->filter == data->filter && entry->next == data->next;
}
if (! flag_exceptions)
return;
- type_to_runtime_map
- = hash_map<tree, tree, tree_hash_traits>::create_ggc (31);
+ type_to_runtime_map = hash_map<tree_hash, tree>::create_ggc (31);
/* Create the SjLj_Function_Context structure. This should match
the definition in unwind-sjlj.c. */
data.label_map_data = map_data;
data.eh_map = new hash_map<void *, void *>;
- outer_region = get_eh_region_from_lp_number (outer_lp);
+ outer_region = get_eh_region_from_lp_number_fn (cfun, outer_lp);
/* Copy all the regions in the subtree. */
if (copy_region)
/* Helper for ttypes_filter hashing. */
-struct ttypes_filter_hasher : typed_free_remove <ttypes_filter>
+struct ttypes_filter_hasher : free_ptr_hash <ttypes_filter>
{
- typedef ttypes_filter value_type;
- typedef tree_node compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
+ typedef tree_node *compare_type;
+ static inline hashval_t hash (const ttypes_filter *);
+ static inline bool equal (const ttypes_filter *, const tree_node *);
};
/* Compare ENTRY (a ttypes_filter entry in the hash table) with DATA
(a tree) for a @TTypes type node we are thinking about adding. */
inline bool
-ttypes_filter_hasher::equal (const value_type *entry, const compare_type *data)
+ttypes_filter_hasher::equal (const ttypes_filter *entry, const tree_node *data)
{
return entry->t == data;
}
inline hashval_t
-ttypes_filter_hasher::hash (const value_type *entry)
+ttypes_filter_hasher::hash (const ttypes_filter *entry)
{
return TREE_HASH (entry->t);
}
/* Helper for ehspec hashing. */
-struct ehspec_hasher : typed_free_remove <ttypes_filter>
+struct ehspec_hasher : free_ptr_hash <ttypes_filter>
{
- typedef ttypes_filter value_type;
- typedef ttypes_filter compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
+ static inline hashval_t hash (const ttypes_filter *);
+ static inline bool equal (const ttypes_filter *, const ttypes_filter *);
};
/* Compare ENTRY with DATA (both struct ttypes_filter) for a @TTypes
should put these in some canonical order. */
inline bool
-ehspec_hasher::equal (const value_type *entry, const compare_type *data)
+ehspec_hasher::equal (const ttypes_filter *entry, const ttypes_filter *data)
{
return type_list_equal (entry->t, data->t);
}
/* Hash function for exception specification lists. */
inline hashval_t
-ehspec_hasher::hash (const value_type *entry)
+ehspec_hasher::hash (const ttypes_filter *entry)
{
hashval_t h = 0;
tree list;
if (LABEL_P (insn))
last_call_site = -2;
+ /* If the function allocates dynamic stack space, the context must
+ be updated after every allocation/deallocation accordingly. */
+ if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_UPDATE_SJLJ_CONTEXT)
+ {
+ rtx buf_addr;
+
+ start_sequence ();
+ buf_addr = plus_constant (Pmode, XEXP (crtl->eh.sjlj_fc, 0),
+ sjlj_fc_jbuf_ofs);
+ expand_builtin_update_setjmp_buf (buf_addr);
+ p = get_insns ();
+ end_sequence ();
+ emit_insn_before (p, insn);
+ }
+
if (! INSN_P (insn))
continue;
static void
sjlj_emit_dispatch_table (rtx_code_label *dispatch_label, int num_dispatch)
{
- enum machine_mode unwind_word_mode = targetm.unwind_word_mode ();
- enum machine_mode filter_mode = targetm.eh_return_filter_mode ();
+ machine_mode unwind_word_mode = targetm.unwind_word_mode ();
+ machine_mode filter_mode = targetm.eh_return_filter_mode ();
eh_landing_pad lp;
- rtx mem, fc, before, exc_ptr_reg, filter_reg;
+ rtx mem, fc, exc_ptr_reg, filter_reg;
rtx_insn *seq;
- rtx first_reachable_label;
basic_block bb;
eh_region r;
edge e;
/* Jump to one of the directly reachable regions. */
disp_index = 0;
- first_reachable_label = NULL;
+ rtx_code_label *first_reachable_label = NULL;
/* If there's exactly one call site in the function, don't bother
generating a switch statement. */
if (lp && lp->post_landing_pad)
{
rtx_insn *seq2;
- rtx label;
+ rtx_code_label *label;
start_sequence ();
t = build_int_cst (integer_type_node, disp_index);
case_elt = build_case_label (t, NULL, t_label);
dispatch_labels.quick_push (case_elt);
- label = label_rtx (t_label);
+ label = jump_target_rtx (t_label);
}
else
label = gen_label_rtx ();
seq2 = get_insns ();
end_sequence ();
- before = label_rtx (lp->post_landing_pad);
+ rtx_insn *before = label_rtx (lp->post_landing_pad);
bb = emit_to_new_bb_before (seq2, before);
e = make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
e->count = bb->count;
{
for (loop = bb->loop_father;
loop_outer (loop); loop = loop_outer (loop))
- {
- loop->header = NULL;
- loop->latch = NULL;
- }
+ mark_loop_for_removal (loop);
}
}
sjlj_lp_call_site_index.release ();
}
+/* Update the sjlj function context. This function should be called
+ whenever we allocate or deallocate dynamic stack space. */
+
+void
+update_sjlj_context (void)
+{
+ if (!flag_exceptions)
+ return;
+
+ emit_note (NOTE_INSN_UPDATE_SJLJ_CONTEXT);
+}
+
/* After initial rtl generation, call back to finish generating
exception support code. */
{
if (lp)
{
- rtx lab = lp->landing_pad;
+ rtx_code_label *lab = lp->landing_pad;
if (lab && LABEL_P (lab))
(*callback) (lab);
}
direct call cases) and just pull the data out of the trees. */
void
-make_reg_eh_region_note (rtx insn, int ecf_flags, int lp_nr)
+make_reg_eh_region_note (rtx_insn *insn, int ecf_flags, int lp_nr)
{
rtx value;
if (ecf_flags & ECF_NOTHROW)
already exists. */
void
-make_reg_eh_region_note_nothrow_nononlocal (rtx insn)
+make_reg_eh_region_note_nothrow_nononlocal (rtx_insn *insn)
{
rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
rtx intmin = GEN_INT (INT_MIN);
/* ??? This test is here in this file because it (ab)uses REG_EH_REGION. */
bool
-can_nonlocal_goto (const_rtx insn)
+can_nonlocal_goto (const rtx_insn *insn)
{
if (nonlocal_goto_handler_labels && CALL_P (insn))
{
= expand_builtin_eh_common (CALL_EXPR_ARG (exp, 0));
eh_region src
= expand_builtin_eh_common (CALL_EXPR_ARG (exp, 1));
- enum machine_mode fmode = targetm.eh_return_filter_mode ();
+ machine_mode fmode = targetm.eh_return_filter_mode ();
if (dst->exc_ptr_reg == NULL)
dst->exc_ptr_reg = gen_reg_rtx (ptr_mode);
}
/* First mask out any unwanted bits. */
-#ifdef MASK_RETURN_ADDR
- expand_and (Pmode, addr, MASK_RETURN_ADDR, addr);
-#endif
+ rtx mask = MASK_RETURN_ADDR;
+ if (mask)
+ expand_and (Pmode, addr, mask, addr);
/* Then adjust to find the real return address. */
-#if defined (RETURN_ADDR_OFFSET)
- addr = plus_constant (Pmode, addr, RETURN_ADDR_OFFSET);
-#endif
+ if (RETURN_ADDR_OFFSET)
+ addr = plus_constant (Pmode, addr, RETURN_ADDR_OFFSET);
return addr;
}
addr = convert_memory_address (Pmode, addr);
-#ifdef RETURN_ADDR_OFFSET
- addr = force_reg (Pmode, addr);
- addr = plus_constant (Pmode, addr, -RETURN_ADDR_OFFSET);
-#endif
+ if (RETURN_ADDR_OFFSET)
+ {
+ addr = force_reg (Pmode, addr);
+ addr = plus_constant (Pmode, addr, -RETURN_ADDR_OFFSET);
+ }
return addr;
}
rtx_insn *first_no_action_insn = NULL;
int call_site = 0;
int cur_sec = 0;
- rtx section_switch_note = NULL_RTX;
+ rtx_insn *section_switch_note = NULL;
rtx_insn *first_no_action_insn_before_switch = NULL;
rtx_insn *last_no_action_insn_before_switch = NULL;
int saved_call_site_base = call_site_base;
eh_region region;
bool nothrow;
int this_action;
- rtx this_landing_pad;
+ rtx_code_label *this_landing_pad;
insn = iter;
if (NONJUMP_INSN_P (insn)
if (this_action >= 0)
this_landing_pad = lp->landing_pad;
else
- this_landing_pad = NULL_RTX;
+ this_landing_pad = NULL;
/* Differing actions or landing pads implies a change in call-site
info, which implies some EH_REGION note should be emitted. */
fprintf (out, "(nil),");
if (lp->post_landing_pad)
{
- rtx lab = label_rtx (lp->post_landing_pad);
+ rtx_insn *lab = label_rtx (lp->post_landing_pad);
fprintf (out, "%i%s}", INSN_UID (lab),
NOTE_P (lab) ? "(del)" : "");
}