#include "flags.h"
#include "function.h"
#include "expr.h"
+#include "libfuncs.h"
#include "insn-config.h"
#include "except.h"
#include "integrate.h"
#include "output.h"
#include "dwarf2asm.h"
#include "dwarf2out.h"
+#include "dwarf2.h"
#include "toplev.h"
#include "hashtab.h"
#include "intl.h"
/* Protect cleanup actions with must-not-throw regions, with a call
to the given failure handler. */
-tree protect_cleanup_actions;
+tree (*lang_protect_cleanup_actions) PARAMS ((void));
/* Return true if type A catches type B. */
int (*lang_eh_type_covers) PARAMS ((tree a, tree b));
rtx exception_handler_labels;
static int call_site_base;
-static int sjlj_funcdef_number;
+static unsigned int sjlj_funcdef_number;
static htab_t type_to_runtime_map;
/* Describe the SjLj_Function_Context structure. */
} fixup;
} u;
- /* The region of code generated, or contained within, the region. */
- rtx label, last;
+ /* Entry point for this region's handler before landing pads are built. */
+ rtx label;
- /* Entry point for this region from the runtime eh library. */
+ /* Entry point for this region's handler from the runtime eh library. */
rtx landing_pad;
- /* Entry point for this region from an inner region. */
+ /* Entry point for this region's handler from an inner region. */
rtx post_landing_pad;
+
+ /* The RESX insn for handing off control to the next outermost handler,
+ if appropriate. */
+ rtx resume;
};
/* Used to save exception status for each function. */
static struct eh_region *expand_eh_region_end PARAMS ((void));
+static rtx get_exception_filter PARAMS ((struct function *));
+
static void collect_eh_region_array PARAMS ((void));
static void resolve_fixup_regions PARAMS ((void));
static void remove_fixup_regions PARAMS ((void));
static void push_uleb128 PARAMS ((varray_type *,
unsigned int));
static void push_sleb128 PARAMS ((varray_type *, int));
-static const char *eh_data_format_name PARAMS ((int));
#ifndef HAVE_AS_LEB128
static int dw2_size_of_call_site_table PARAMS ((void));
static int sjlj_size_of_call_site_table PARAMS ((void));
init_eh ()
{
ggc_add_rtx_root (&exception_handler_labels, 1);
- ggc_add_tree_root (&protect_cleanup_actions, 1);
if (! flag_exceptions)
return;
}
ggc_mark_rtx (region->label);
- ggc_mark_rtx (region->last);
+ ggc_mark_rtx (region->resume);
ggc_mark_rtx (region->landing_pad);
ggc_mark_rtx (region->post_landing_pad);
}
if (! doing_eh (0))
return;
- /* We need a new block to record the start and end of the dynamic
- handler chain. We also want to prevent jumping into a try block. */
- expand_start_bindings (2);
-
- /* But we don't need or want a new temporary level. */
- pop_temp_slots ();
-
- /* Mark this block as created by expand_eh_region_start. This is so
- that we can pop the block with expand_end_bindings automatically. */
- mark_block_as_eh_region ();
-
/* Insert a new blank region as a leaf in the tree. */
new_region = (struct eh_region *) xcalloc (1, sizeof (*new_region));
cur_region = cfun->eh->cur_region;
/* Create a note marking the start of this region. */
new_region->region_number = ++cfun->eh->last_region_number;
- note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_BEG);
+ note = emit_note (NULL, NOTE_INSN_EH_REGION_BEG);
NOTE_EH_HANDLER (note) = new_region->region_number;
}
rtx note;
/* Create a nute marking the end of this region. */
- note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
+ note = emit_note (NULL, NOTE_INSN_EH_REGION_END);
NOTE_EH_HANDLER (note) = cur_region->region_number;
/* Pop. */
cfun->eh->cur_region = cur_region->outer;
- /* If we have already started ending the bindings, don't recurse. */
- if (is_eh_region ())
- {
- /* Because we don't need or want a new temporary level and
- because we didn't create one in expand_eh_region_start,
- create a fake one now to avoid removing one in
- expand_end_bindings. */
- push_temp_slots ();
-
- mark_block_as_not_eh_region ();
-
- expand_end_bindings (NULL_TREE, 0, 0);
- }
-
return cur_region;
}
tree handler;
{
struct eh_region *region;
+ tree protect_cleanup_actions;
rtx around_label;
+ rtx data_save[2];
if (! doing_eh (0))
return;
emit_label (region->label);
+ /* Give the language a chance to specify an action to be taken if an
+ exception is thrown that would propogate out of the HANDLER. */
+ protect_cleanup_actions
+ = (lang_protect_cleanup_actions
+ ? (*lang_protect_cleanup_actions) ()
+ : NULL_TREE);
+
if (protect_cleanup_actions)
expand_eh_region_start ();
+ /* In case this cleanup involves an inline destructor with a try block in
+ it, we need to save the EH return data registers around it. */
+ data_save[0] = gen_reg_rtx (Pmode);
+ emit_move_insn (data_save[0], get_exception_pointer (cfun));
+ data_save[1] = gen_reg_rtx (word_mode);
+ emit_move_insn (data_save[1], get_exception_filter (cfun));
+
expand_expr (handler, const0_rtx, VOIDmode, 0);
+ emit_move_insn (cfun->eh->exc_ptr, data_save[0]);
+ emit_move_insn (cfun->eh->filter, data_save[1]);
+
if (protect_cleanup_actions)
expand_eh_region_end_must_not_throw (protect_cleanup_actions);
+ /* We need any stack adjustment complete before the around_label. */
+ do_pending_stack_adjust ();
+
/* We delay the generation of the _Unwind_Resume until we generate
landing pads. We emit a marker here so as to get good control
flow data in the meantime. */
- emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
+ region->resume
+ = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
emit_barrier ();
- region->last = get_last_insn ();
-
emit_label (around_label);
}
try_region = cfun->eh->try_region;
emit_jump (try_region->u.try.continue_label);
-
- catch_region->last = get_last_insn ();
}
/* End a sequence of catch handlers for a try block. */
/* End an exception region for an exception type filter. ALLOWED is a
TREE_LIST of types to be matched by the runtime. FAILURE is an
- expression to invoke if a mismatch ocurrs. */
+ expression to invoke if a mismatch ocurrs.
+
+ ??? We could use these semantics for calls to rethrow, too; if we can
+ see the surrounding catch clause, we know that the exception we're
+ rethrowing satisfies the "filter" of the catch type. */
void
expand_eh_region_end_allowed (allowed, failure)
emit_label (region->label);
expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
- region->last = get_last_insn ();
+ /* We must adjust the stack before we reach the AROUND_LABEL because
+ the call to FAILURE does not occur on all paths to the
+ AROUND_LABEL. */
+ do_pending_stack_adjust ();
emit_label (around_label);
}
emit_label (region->label);
expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL);
- region->last = get_last_insn ();
-
emit_label (around_label);
}
fixup->u.fixup.cleanup_exp = handler;
}
-/* Return a tree expression for a pointer to the exception object
+/* Return an rtl expression for a pointer to the exception object
within a handler. */
rtx
-get_exception_pointer ()
+get_exception_pointer (fun)
+ struct function *fun;
{
- rtx exc_ptr = cfun->eh->exc_ptr;
- if (! exc_ptr)
+ rtx exc_ptr = fun->eh->exc_ptr;
+ if (fun == cfun && ! exc_ptr)
{
exc_ptr = gen_reg_rtx (Pmode);
- cfun->eh->exc_ptr = exc_ptr;
+ fun->eh->exc_ptr = exc_ptr;
}
return exc_ptr;
}
+/* Return an rtl expression for the exception dispatch filter
+ within a handler. */
+
+static rtx
+get_exception_filter (fun)
+ struct function *fun;
+{
+ rtx filter = fun->eh->filter;
+ if (fun == cfun && ! filter)
+ {
+ filter = gen_reg_rtx (word_mode);
+ fun->eh->filter = filter;
+ }
+ return filter;
+}
\f
/* Begin a region that will contain entries created with
add_partial_entry. */
for (i = 1; i <= n; ++i)
{
struct eh_region *fixup = cfun->eh->region_array[i];
- struct eh_region *cleanup;
+ struct eh_region *cleanup = 0;
if (! fixup || fixup->type != ERT_FIXUP)
continue;
remove_fixup_regions ()
{
int i;
+ rtx insn, note;
+ struct eh_region *fixup;
+
+ /* Walk the insn chain and adjust the REG_EH_REGION numbers
+ for instructions referencing fixup regions. This is only
+ strictly necessary for fixup regions with no parent, but
+ doesn't hurt to do it for all regions. */
+ for (insn = get_insns(); insn ; insn = NEXT_INSN (insn))
+ if (INSN_P (insn)
+ && (note = find_reg_note (insn, REG_EH_REGION, NULL))
+ && INTVAL (XEXP (note, 0)) > 0
+ && (fixup = cfun->eh->region_array[INTVAL (XEXP (note, 0))])
+ && fixup->type == ERT_FIXUP)
+ {
+ if (fixup->u.fixup.real_region)
+ XEXP (note, 0) = GEN_INT (fixup->u.fixup.real_region->region_number);
+ else
+ remove_note (insn, note);
+ }
+ /* Remove the fixup regions from the tree. */
for (i = cfun->eh->last_region_number; i > 0; --i)
{
- struct eh_region *fixup = cfun->eh->region_array[i];
-
+ fixup = cfun->eh->region_array[i];
if (! fixup)
continue;
/* If we wanted exceptions for non-call insns, then
any may_trap_p instruction could throw. */
|| (flag_non_call_exceptions
+ && GET_CODE (PATTERN (insn)) != CLOBBER
+ && GET_CODE (PATTERN (insn)) != USE
&& may_trap_p (PATTERN (insn)))))
{
REG_NOTES (insn) = alloc_EXPR_LIST (REG_EH_REGION, GEN_INT (cur),
if (o->label)
n->label = get_label_from_map (map, CODE_LABEL_NUMBER (o->label));
- if (o->last)
+ if (o->resume)
{
- n->last = map->insn_map[INSN_UID (o->last)];
- if (n->last == NULL)
+ n->resume = map->insn_map[INSN_UID (o->resume)];
+ if (n->resume == NULL)
abort ();
}
cur->inner = root;
for (i = 1; i <= ifun_last_region_number; ++i)
- if (n_array[i]->outer == NULL)
+ if (n_array[i] && n_array[i]->outer == NULL)
n_array[i]->outer = cur;
}
else
}
\f
-/* ??? Move from tree.c to tree.h. */
-#define TYPE_HASH(TYPE) ((HOST_WIDE_INT) (TYPE) & 0777777)
-
static int
t2r_eq (pentry, pdata)
const PTR pentry;
}
}
+ /* We delay the generation of the _Unwind_Resume until we generate
+ landing pads. We emit a marker here so as to get good control
+ flow data in the meantime. */
+ region->resume
+ = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
+ emit_barrier ();
+
seq = get_insns ();
end_sequence ();
- region->last = emit_insns_before (seq, region->u.try.catch->label);
+ emit_insns_before (seq, region->u.try.catch->label);
break;
case ERT_ALLOWED_EXCEPTIONS:
EQ, NULL_RTX, word_mode, 0, 0,
region->label);
+ /* We delay the generation of the _Unwind_Resume until we generate
+ landing pads. We emit a marker here so as to get good control
+ flow data in the meantime. */
+ region->resume
+ = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
+ emit_barrier ();
+
seq = get_insns ();
end_sequence ();
- region->last = emit_insns_before (seq, region->label);
+ emit_insns_before (seq, region->label);
break;
case ERT_CLEANUP:
}
}
+/* Replace RESX patterns with jumps to the next handler if any, or calls to
+ _Unwind_Resume otherwise. */
+
static void
connect_post_landing_pads ()
{
{
struct eh_region *region = cfun->eh->region_array[i];
struct eh_region *outer;
- rtx before = NULL_RTX, after = NULL_RTX, seq;
+ rtx seq;
/* Mind we don't process a region more than once. */
if (!region || region->region_number != i)
continue;
- switch (region->type)
- {
- case ERT_CLEANUP:
- after = region->last;
- if (GET_CODE (after) == BARRIER
- && GET_CODE (PREV_INSN (after)) == JUMP_INSN
- && GET_CODE (PATTERN (PREV_INSN (after))) == RESX)
- {
- before = PREV_INSN (after);
- after = NULL_RTX;
- }
- break;
-
- case ERT_TRY:
- after = region->last;
- break;
-
- case ERT_ALLOWED_EXCEPTIONS:
- before = region->label;
- break;
-
- case ERT_MUST_NOT_THROW:
- case ERT_CATCH:
- case ERT_THROW:
- continue;
-
- default:
- abort ();
- }
-
- /* If there's no fallthru, no need to add branches. */
- if (after && GET_CODE (after) == BARRIER)
+ /* If there is no RESX, or it has been deleted by flow, there's
+ nothing to fix up. */
+ if (! region->resume || INSN_DELETED_P (region->resume))
continue;
/* Search for another landing pad in this function. */
seq = get_insns ();
end_sequence ();
- if (before)
- emit_insns_before (seq, before);
- else
- emit_insns_after (seq, after);
+ emit_insns_before (seq, region->resume);
+ flow_delete_insn (region->resume);
}
}
static void
dw2_build_landing_pads ()
{
- int i, j;
+ int i;
+ unsigned int j;
for (i = cfun->eh->last_region_number; i > 0; --i)
{
emit_move_insn (cfun->eh->exc_ptr,
gen_rtx_REG (Pmode, EH_RETURN_DATA_REGNO (0)));
emit_move_insn (cfun->eh->filter,
- gen_rtx_REG (Pmode, EH_RETURN_DATA_REGNO (1)));
+ gen_rtx_REG (word_mode, EH_RETURN_DATA_REGNO (1)));
seq = get_insns ();
end_sequence ();
int last_call_site = -2;
rtx insn, mem;
- mem = change_address (cfun->eh->sjlj_fc, TYPE_MODE (integer_type_node),
- plus_constant (XEXP (cfun->eh->sjlj_fc, 0),
- sjlj_fc_call_site_ofs));
+ mem = adjust_address (cfun->eh->sjlj_fc, TYPE_MODE (integer_type_node),
+ sjlj_fc_call_site_ofs);
for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
{
/* Don't separate a call from it's argument loads. */
before = insn;
if (GET_CODE (insn) == CALL_INSN)
- {
- HARD_REG_SET parm_regs;
- int nparm_regs;
-
- /* Since different machines initialize their parameter registers
- in different orders, assume nothing. Collect the set of all
- parameter registers. */
- CLEAR_HARD_REG_SET (parm_regs);
- nparm_regs = 0;
- for (p = CALL_INSN_FUNCTION_USAGE (insn); p ; p = XEXP (p, 1))
- if (GET_CODE (XEXP (p, 0)) == USE
- && GET_CODE (XEXP (XEXP (p, 0), 0)) == REG)
- {
- if (REGNO (XEXP (XEXP (p, 0), 0)) >= FIRST_PSEUDO_REGISTER)
- abort ();
-
- SET_HARD_REG_BIT (parm_regs, REGNO (XEXP (XEXP (p, 0), 0)));
- nparm_regs++;
- }
-
- /* Search backward for the first set of a register in this set. */
- while (nparm_regs)
- {
- before = PREV_INSN (before);
-
- /* Given that we've done no other optimizations yet,
- the arguments should be immediately available. */
- if (GET_CODE (before) == CODE_LABEL)
- abort ();
-
- p = single_set (before);
- if (p && GET_CODE (SET_DEST (p)) == REG
- && REGNO (SET_DEST (p)) < FIRST_PSEUDO_REGISTER
- && TEST_HARD_REG_BIT (parm_regs, REGNO (SET_DEST (p))))
- {
- CLEAR_HARD_REG_BIT (parm_regs, REGNO (SET_DEST (p)));
- nparm_regs--;
- }
- }
- }
+ before = find_first_parameter_load (insn, NULL_RTX);
start_sequence ();
emit_move_insn (mem, GEN_INT (this_call_site));
start_sequence ();
- mem = change_address (fc, Pmode,
- plus_constant (XEXP (fc, 0), sjlj_fc_personality_ofs));
+ /* We're storing this libcall's address into memory instead of
+ calling it directly. Thus, we must call assemble_external_libcall
+ here, as we can not depend on emit_library_call to do it for us. */
+ assemble_external_libcall (eh_personality_libfunc);
+ mem = adjust_address (fc, Pmode, sjlj_fc_personality_ofs);
emit_move_insn (mem, eh_personality_libfunc);
- mem = change_address (fc, Pmode,
- plus_constant (XEXP (fc, 0), sjlj_fc_lsda_ofs));
+ mem = adjust_address (fc, Pmode, sjlj_fc_lsda_ofs);
if (cfun->uses_eh_lsda)
{
char buf[20];
/* Load up dispatch index, exc_ptr and filter values from the
function context. */
- mem = change_address (fc, TYPE_MODE (integer_type_node),
- plus_constant (XEXP (fc, 0), sjlj_fc_call_site_ofs));
+ mem = adjust_address (fc, TYPE_MODE (integer_type_node),
+ sjlj_fc_call_site_ofs);
dispatch = copy_to_reg (mem);
- mem = change_address (fc, word_mode,
- plus_constant (XEXP (fc, 0), sjlj_fc_data_ofs));
+ mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs);
if (word_mode != Pmode)
{
#ifdef POINTERS_EXTEND_UNSIGNED
}
emit_move_insn (cfun->eh->exc_ptr, mem);
- mem = change_address (fc, word_mode,
- plus_constant (XEXP (fc, 0),
- sjlj_fc_data_ofs + UNITS_PER_WORD));
+ mem = adjust_address (fc, word_mode, sjlj_fc_data_ofs + UNITS_PER_WORD);
emit_move_insn (cfun->eh->filter, mem);
/* Jump to one of the directly reachable regions. */
connect many of the handlers, and then type information will not
be effective. Still, this is a win over previous implementations. */
- jump_optimize_minimal (get_insns ());
+ rebuild_jump_labels (get_insns ());
find_basic_blocks (get_insns (), max_reg_num (), 0);
- cleanup_cfg ();
+ cleanup_cfg (CLEANUP_PRE_LOOP);
/* These registers are used by the landing pads. Make sure they
have been generated. */
- get_exception_pointer ();
- cfun->eh->filter = gen_reg_rtx (word_mode);
+ get_exception_pointer (cfun);
+ get_exception_filter (cfun);
/* Construct the landing pads. */
/* We've totally changed the CFG. Start over. */
find_exception_handler_labels ();
- jump_optimize_minimal (get_insns ());
+ rebuild_jump_labels (get_insns ());
find_basic_blocks (get_insns (), max_reg_num (), 0);
- cleanup_cfg ();
+ cleanup_cfg (CLEANUP_PRE_LOOP);
}
\f
/* This section handles removing dead code for flow. */
region = cfun->eh->region_array[region_number];
type_thrown = NULL_TREE;
- if (region->type == ERT_THROW)
+ if (GET_CODE (insn) == JUMP_INSN
+ && GET_CODE (PATTERN (insn)) == RESX)
+ {
+ /* A RESX leaves a region instead of entering it. Thus the
+ region itself may have been deleted out from under us. */
+ if (region == NULL)
+ return NULL;
+ region = region->outer;
+ }
+ else if (region->type == ERT_THROW)
{
type_thrown = region->u.throw.type;
region = region->outer;
expand_builtin_unwind_init ()
{
/* 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. */
+ able to copy the saved values for any registers from frames we unwind. */
current_function_has_nonlocal_label = 1;
#ifdef SETUP_FRAME_ADDRESSES
{
rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
+#ifdef POINTERS_EXTEND_UNSIGNED
+ addr = convert_memory_address (Pmode, addr);
+#endif
+
#ifdef RETURN_ADDR_OFFSET
addr = force_reg (Pmode, addr);
addr = plus_constant (addr, -RETURN_ADDR_OFFSET);
stackadj = expand_expr (stackadj_tree, cfun->eh->ehr_stackadj, VOIDmode, 0);
handler = expand_expr (handler_tree, cfun->eh->ehr_handler, VOIDmode, 0);
+#ifdef POINTERS_EXTEND_UNSIGNED
+ stackadj = convert_memory_address (Pmode, stackadj);
+ handler = convert_memory_address (Pmode, handler);
+#endif
+
if (! cfun->eh->ehr_label)
{
cfun->eh->ehr_stackadj = copy_to_reg (stackadj);
emit_label (around_label);
}
\f
+/* In the following functions, we represent entries in the action table
+ as 1-based indicies. Special cases are:
+
+ 0: null action record, non-null landing pad; implies cleanups
+ -1: null action record, null landing pad; implies no action
+ -2: no call-site entry; implies must_not_throw
+ -3: we have yet to process outer regions
+
+ Further, no special cases apply to the "next" field of the record.
+ For next, 0 means end of list. */
+
struct action_record
{
int offset;
if (next == -3)
{
next = collect_one_action_chain (ar_hash, region->outer);
- if (next < 0)
+
+ /* If there is no next action, terminate the chain. */
+ if (next == -1)
next = 0;
+ /* If all outer actions are cleanups or must_not_throw,
+ we'll have no action record for it, since we had wanted
+ to encode these states in the call-site record directly.
+ Add a cleanup action to the chain to catch these. */
+ else if (next <= 0)
+ next = add_action_record (ar_hash, 0, 0);
}
next = add_action_record (ar_hash, c->u.catch.filter, next);
}
rtx last_action_insn = NULL_RTX;
rtx last_landing_pad = NULL_RTX;
rtx first_no_action_insn = NULL_RTX;
- int call_site;
+ int call_site = 0;
if (USING_SJLJ_EXCEPTIONS || cfun->eh->region_tree == NULL)
return;
}
\f
-#define DW_EH_PE_absptr 0x00
-#define DW_EH_PE_omit 0xff
-
-#define DW_EH_PE_uleb128 0x01
-#define DW_EH_PE_udata2 0x02
-#define DW_EH_PE_udata4 0x03
-#define DW_EH_PE_udata8 0x04
-#define DW_EH_PE_sleb128 0x09
-#define DW_EH_PE_sdata2 0x0A
-#define DW_EH_PE_sdata4 0x0B
-#define DW_EH_PE_sdata8 0x0C
-#define DW_EH_PE_signed 0x08
-
-#define DW_EH_PE_pcrel 0x10
-#define DW_EH_PE_textrel 0x20
-#define DW_EH_PE_datarel 0x30
-#define DW_EH_PE_funcrel 0x40
-
-static const char *
-eh_data_format_name (format)
- int format;
-{
- switch (format)
- {
- case DW_EH_PE_absptr: return "absolute";
- case DW_EH_PE_omit: return "omit";
-
- case DW_EH_PE_uleb128: return "uleb128";
- case DW_EH_PE_udata2: return "udata2";
- case DW_EH_PE_udata4: return "udata4";
- case DW_EH_PE_udata8: return "udata8";
- case DW_EH_PE_sleb128: return "sleb128";
- case DW_EH_PE_sdata2: return "sdata2";
- case DW_EH_PE_sdata4: return "sdata4";
- case DW_EH_PE_sdata8: return "sdata8";
-
- case DW_EH_PE_uleb128 | DW_EH_PE_pcrel: return "pcrel uleb128";
- case DW_EH_PE_udata2 | DW_EH_PE_pcrel: return "pcrel udata2";
- case DW_EH_PE_udata4 | DW_EH_PE_pcrel: return "pcrel udata4";
- case DW_EH_PE_udata8 | DW_EH_PE_pcrel: return "pcrel udata8";
- case DW_EH_PE_sleb128 | DW_EH_PE_pcrel: return "pcrel sleb128";
- case DW_EH_PE_sdata2 | DW_EH_PE_pcrel: return "pcrel sdata2";
- case DW_EH_PE_sdata4 | DW_EH_PE_pcrel: return "pcrel sdata4";
- case DW_EH_PE_sdata8 | DW_EH_PE_pcrel: return "pcrel sdata8";
-
- case DW_EH_PE_uleb128 | DW_EH_PE_textrel: return "textrel uleb128";
- case DW_EH_PE_udata2 | DW_EH_PE_textrel: return "textrel udata2";
- case DW_EH_PE_udata4 | DW_EH_PE_textrel: return "textrel udata4";
- case DW_EH_PE_udata8 | DW_EH_PE_textrel: return "textrel udata8";
- case DW_EH_PE_sleb128 | DW_EH_PE_textrel: return "textrel sleb128";
- case DW_EH_PE_sdata2 | DW_EH_PE_textrel: return "textrel sdata2";
- case DW_EH_PE_sdata4 | DW_EH_PE_textrel: return "textrel sdata4";
- case DW_EH_PE_sdata8 | DW_EH_PE_textrel: return "textrel sdata8";
-
- case DW_EH_PE_uleb128 | DW_EH_PE_datarel: return "datarel uleb128";
- case DW_EH_PE_udata2 | DW_EH_PE_datarel: return "datarel udata2";
- case DW_EH_PE_udata4 | DW_EH_PE_datarel: return "datarel udata4";
- case DW_EH_PE_udata8 | DW_EH_PE_datarel: return "datarel udata8";
- case DW_EH_PE_sleb128 | DW_EH_PE_datarel: return "datarel sleb128";
- case DW_EH_PE_sdata2 | DW_EH_PE_datarel: return "datarel sdata2";
- case DW_EH_PE_sdata4 | DW_EH_PE_datarel: return "datarel sdata4";
- case DW_EH_PE_sdata8 | DW_EH_PE_datarel: return "datarel sdata8";
-
- case DW_EH_PE_uleb128 | DW_EH_PE_funcrel: return "funcrel uleb128";
- case DW_EH_PE_udata2 | DW_EH_PE_funcrel: return "funcrel udata2";
- case DW_EH_PE_udata4 | DW_EH_PE_funcrel: return "funcrel udata4";
- case DW_EH_PE_udata8 | DW_EH_PE_funcrel: return "funcrel udata8";
- case DW_EH_PE_sleb128 | DW_EH_PE_funcrel: return "funcrel sleb128";
- case DW_EH_PE_sdata2 | DW_EH_PE_funcrel: return "funcrel sdata2";
- case DW_EH_PE_sdata4 | DW_EH_PE_funcrel: return "funcrel sdata4";
- case DW_EH_PE_sdata8 | DW_EH_PE_funcrel: return "funcrel sdata8";
-
- default:
- abort ();
- }
-}
-
#ifndef HAVE_AS_LEB128
static int
dw2_size_of_call_site_table ()
void
output_function_exception_table ()
{
- int format, i, n;
+ int tt_format, cs_format, lp_format, i, n;
#ifdef HAVE_AS_LEB128
char ttype_label[32];
char cs_after_size_label[32];
#endif
int have_tt_data;
int funcdef_number;
+ int tt_format_size = 0;
/* Not all functions need anything. */
if (! cfun->uses_eh_lsda)
? sjlj_funcdef_number
: current_funcdef_number);
+#ifdef IA64_UNWIND_INFO
+ fputs ("\t.personality\t", asm_out_file);
+ output_addr_const (asm_out_file, eh_personality_libfunc);
+ fputs ("\n\t.handlerdata\n", 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
exception_section ();
+#endif
have_tt_data = (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) > 0
|| VARRAY_ACTIVE_SIZE (cfun->eh->ehspec_data) > 0);
- if (have_tt_data)
- assemble_eh_align (GET_MODE_ALIGNMENT (ptr_mode));
+ /* Indicate the format of the @TType entries. */
+ if (! have_tt_data)
+ tt_format = DW_EH_PE_omit;
+ else
+ {
+ tt_format = ASM_PREFERRED_EH_DATA_FORMAT (/*code=*/0, /*global=*/1);
+#ifdef HAVE_AS_LEB128
+ ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT", funcdef_number);
+#endif
+ tt_format_size = size_of_encoded_value (tt_format);
+
+ assemble_align (tt_format_size * BITS_PER_UNIT);
+ }
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LLSDA", funcdef_number);
be most useful in moving the landing pads completely out of
line to another section, but it could also be used to minimize
the size of uleb128 landing pad offsets. */
- format = DW_EH_PE_omit;
- dw2_asm_output_data (1, format, "@LPStart format (%s)",
- eh_data_format_name (format));
+ lp_format = DW_EH_PE_omit;
+ dw2_asm_output_data (1, lp_format, "@LPStart format (%s)",
+ eh_data_format_name (lp_format));
/* @LPStart pointer would go here. */
- /* Indicate the format of the @TType entries. */
- if (! have_tt_data)
- format = DW_EH_PE_omit;
- else
- {
- /* ??? Define a ASM_PREFERRED_DATA_FORMAT to say what
- sort of dynamic-relocation-free reference to emit. */
- format = 0;
-#ifdef HAVE_AS_LEB128
- ASM_GENERATE_INTERNAL_LABEL (ttype_label, "LLSDATT", funcdef_number);
-#endif
- }
- dw2_asm_output_data (1, format, "@TType format (%s)",
- eh_data_format_name (format));
+ dw2_asm_output_data (1, tt_format, "@TType format (%s)",
+ eh_data_format_name (tt_format));
#ifndef HAVE_AS_LEB128
if (USING_SJLJ_EXCEPTIONS)
ASM_OUTPUT_LABEL (asm_out_file, ttype_after_disp_label);
#else
/* Ug. Alignment queers things. */
- unsigned int before_disp, after_disp, last_disp, disp, align;
+ unsigned int before_disp, after_disp, last_disp, disp;
- align = POINTER_SIZE / BITS_PER_UNIT;
before_disp = 1 + 1;
after_disp = (1 + size_of_uleb128 (call_site_len)
+ call_site_len
+ VARRAY_ACTIVE_SIZE (cfun->eh->action_record_data)
- + VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data) * align);
+ + (VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data)
+ * tt_format_size));
disp = after_disp;
do
last_disp = disp;
disp_size = size_of_uleb128 (disp);
pad = before_disp + disp_size + after_disp;
- if (pad % align)
- pad = align - (pad % align);
+ if (pad % tt_format_size)
+ pad = tt_format_size - (pad % tt_format_size);
else
pad = 0;
disp = after_disp + pad;
/* Indicate the format of the call-site offsets. */
#ifdef HAVE_AS_LEB128
- format = DW_EH_PE_uleb128;
+ cs_format = DW_EH_PE_uleb128;
#else
- format = DW_EH_PE_udata4;
+ cs_format = DW_EH_PE_udata4;
#endif
- dw2_asm_output_data (1, format, "call-site format (%s)",
- eh_data_format_name (format));
+ dw2_asm_output_data (1, cs_format, "call-site format (%s)",
+ eh_data_format_name (cs_format));
#ifdef HAVE_AS_LEB128
ASM_GENERATE_INTERNAL_LABEL (cs_after_size_label, "LLSDACSB",
(i ? NULL : "Action record table"));
if (have_tt_data)
- assemble_eh_align (GET_MODE_ALIGNMENT (ptr_mode));
+ assemble_align (tt_format_size * BITS_PER_UNIT);
i = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data);
while (i-- > 0)
else
type = lookup_type_for_runtime (type);
- /* ??? Handle ASM_PREFERRED_DATA_FORMAT. */
- output_constant (type, GET_MODE_SIZE (ptr_mode));
+ dw2_asm_output_encoded_addr_rtx (tt_format,
+ expand_expr (type, NULL_RTX, VOIDmode,
+ EXPAND_INITIALIZER),
+ NULL);
}
#ifdef HAVE_AS_LEB128