1999, 2000, 2001 Free Software Foundation, Inc.
Contributed by Mike Stump <mrs@cygnus.com>.
-This file is part of GNU CC.
+This file is part of GCC.
-GNU CC 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 version.
+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
+version.
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+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. */
/* An exception is an event that can be signaled from within a
#include "flags.h"
#include "function.h"
#include "expr.h"
+#include "libfuncs.h"
#include "insn-config.h"
#include "except.h"
#include "integrate.h"
/* 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)
&& fixup->type == ERT_FIXUP)
{
if (fixup->u.fixup.real_region)
- XEXP (note, 1) = GEN_INT (fixup->u.fixup.real_region->region_number);
+ XEXP (note, 0) = GEN_INT (fixup->u.fixup.real_region->region_number);
else
remove_note (insn, note);
}
/* 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),
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;
seq = get_insns ();
end_sequence ();
emit_insns_before (seq, region->resume);
-
- /* Leave the RESX to be deleted by flow. */
+ delete_insn (region->resume);
}
}
{
struct eh_region *region = cfun->eh->region_array[i];
rtx seq;
+ bool clobbers_hard_regs = false;
/* Mind we don't process a region more than once. */
if (!region || region->region_number != i)
if (r == INVALID_REGNUM)
break;
if (! call_used_regs[r])
- emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 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,
int last_call_site = -2;
rtx insn, mem;
- 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))
{
struct eh_region *region;
/* 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 ();
-
- /* We only care about registers which can hold function
- arguments. */
- if (! FUNCTION_ARG_REGNO_P (REGNO (XEXP (XEXP (p, 0), 0))))
- continue;
-
- 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 ();
+ mem = adjust_address (cfun->eh->sjlj_fc, TYPE_MODE (integer_type_node),
+ sjlj_fc_call_site_ofs);
emit_move_insn (mem, GEN_INT (this_call_site));
p = get_insns ();
end_sequence ();
#ifdef DONT_USE_BUILTIN_SETJMP
{
rtx x, note;
- x = emit_library_call_value (setjmp_libfunc, NULL_RTX, LCT_NORMAL,
+ 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);
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. */
/* 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;
}
- else if (GET_CODE (insn) == JUMP_INSN
- && GET_CODE (PATTERN (insn)) == RESX)
- region = region->outer;
for (; region; region = region->outer)
if (reachable_next_level (region, type_thrown, &info) >= RNL_CAUGHT)
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
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);
}
static void
dw2_output_call_site_table ()
{
- const char *function_start_lab
+ const char *const function_start_lab
= IDENTIFIER_POINTER (current_function_func_begin_label);
int n = cfun->eh->call_site_data_used;
int i;
#endif
tt_format_size = size_of_encoded_value (tt_format);
- assemble_eh_align (tt_format_size * BITS_PER_UNIT);
+ assemble_align (tt_format_size * BITS_PER_UNIT);
}
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LLSDA", funcdef_number);
(i ? NULL : "Action record table"));
if (have_tt_data)
- assemble_eh_align (tt_format_size * BITS_PER_UNIT);
+ assemble_align (tt_format_size * BITS_PER_UNIT);
i = VARRAY_ACTIVE_SIZE (cfun->eh->ttype_data);
while (i-- > 0)
{
tree type = VARRAY_TREE (cfun->eh->ttype_data, i);
+ rtx value;
if (type == NULL_TREE)
type = integer_zero_node;
else
type = lookup_type_for_runtime (type);
- dw2_asm_output_encoded_addr_rtx (tt_format,
- expand_expr (type, NULL_RTX, VOIDmode,
- EXPAND_INITIALIZER),
- NULL);
+ value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER);
+ 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);
}
#ifdef HAVE_AS_LEB128