+Sun Dec 28 00:32:16 1997 Jeffrey A Law (law@cygnus.com)
+
+ * flow.c (find_basic_blocks): Don't create a new basic block
+ for calls in a LIBCALL block.
+
+Fri Dec 12 01:19:48 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * flow.c (flow_analysis): Be consistent with find_basic_blocks in
+ determining when a new basic block starts.
+
+Thu Dec 11 22:02:10 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * flow.c (find_basic_blocks): A CALL_INSN that can throw starts
+ a new basic block.
+ (find_basic_blocks_1): Likewise.
+
+Thu Dec 4 11:51:00 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * except.c (get_dynamic_handler_chain): Only make the call once per
+ function.
+
+Wed Dec 3 12:01:56 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * except.c (expand_fixup_region_end): New fn.
+ (expand_fixup_region_start): Likewise.
+ (expand_eh_region_start_tree): Store cleanup into finalization here.
+ * stmt.c (expand_cleanups): Use them to protect fixups.
+
+Mon Nov 24 22:41:55 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * except.c (get_dynamic_handler_chain): Build up a FUNCTION_DECL.
+ * optabs.c (init_optabs): Lose get_dynamic_handler_chain_libfunc.
+ * expr.h: Likewise.
+
Wed Feb 11 01:39:47 1998 Richard Henderson <rth@cygnus.com>
* stor-layout.c (layout_type): Do upper - lower in the native type,
+Mon Dec 8 23:17:13 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * decl.c (copy_args_p): Handle copy elision for types with virtual
+ bases.
+ * call.c (build_over_call): Likewise.
+
+Tue Dec 2 01:37:19 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * exception.cc (__cp_pop_exception): Lose handler arg.
+ * except.c (do_pop_exception): Likewise.
+ (push_eh_cleanup): Let the cleanup mechanism supply the handler.
+ (expand_end_catch_block): Likewise.
+
Sun Feb 8 23:59:04 1998 scott snyder <sss@d0linux01.fnal.gov>
* method.c (make_thunk): Avoid name buffer overflow.
&& copy_args_p (fn))
{
tree targ;
- arg = TREE_VALUE (TREE_CHAIN (converted_args));
+ arg = TREE_CHAIN (converted_args);
+ if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
+ arg = TREE_CHAIN (arg);
+ arg = TREE_VALUE (arg);
/* Pull out the real argument, disregarding const-correctness. */
targ = arg;
tree d;
{
tree t = FUNCTION_ARG_CHAIN (d);
+ if (DECL_CONSTRUCTOR_P (d)
+ && TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (d)))
+ t = TREE_CHAIN (t);
if (t && TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
&& (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (t)))
== DECL_CLASS_CONTEXT (d))
if it is, it avoids destroying the object on rethrow. */
static tree
-do_pop_exception (handler)
- tree handler;
+do_pop_exception ()
{
tree fn, cleanup;
fn = get_identifier ("__cp_pop_exception");
fn = build_lang_decl
(FUNCTION_DECL, fn,
build_function_type (void_type_node, tree_cons
- (NULL_TREE, ptr_type_node, tree_cons
- (NULL_TREE, boolean_type_node,
- void_list_node))));
+ (NULL_TREE, ptr_type_node, void_list_node)));
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
/* Arrange to do a dynamically scoped cleanup upon exit from this region. */
cleanup = lookup_name (get_identifier ("__exception_info"), 0);
cleanup = build_function_call (fn, expr_tree_cons
- (NULL_TREE, cleanup, expr_tree_cons
- (NULL_TREE, handler, NULL_TREE)));
+ (NULL_TREE, cleanup, NULL_TREE));
return cleanup;
}
static void
push_eh_cleanup ()
{
- /* All cleanups must last longer than normal. */
- int yes = suspend_momentary ();
- expand_decl_cleanup_no_eh (NULL_TREE, do_pop_exception (boolean_false_node));
- resume_momentary (yes);
+ int yes;
expand_expr (build_unary_op (PREINCREMENT_EXPR, get_eh_handlers (), 1),
const0_rtx, VOIDmode, EXPAND_NORMAL);
- /* We don't destroy the exception object on rethrow, so we can't use
- the normal cleanup mechanism for it. */
- expand_eh_region_start ();
+ yes = suspend_momentary ();
+ /* All cleanups must last longer than normal. */
+ expand_decl_cleanup (NULL_TREE, do_pop_exception ());
+ resume_momentary (yes);
}
/* call this to start a catch block. Typename is the typename, and identifier
expand_end_bindings (getdecls (), kept_level_p (), 0);
poplevel (kept_level_p (), 1, 0);
- /* Matches push_eh_cleanup. */
- expand_eh_region_end (do_pop_exception (boolean_true_node));
-
/* Cleanup the EH object. */
expand_end_bindings (getdecls (), kept_level_p (), 0);
poplevel (kept_level_p (), 1, 0);
/* Compiler hook to pop an exception that has been finalized. Used by
push_eh_cleanup(). P is the info for the exception caught by the
- current catch block, and HANDLER determines if we've been called from
- an exception handler; if so, we avoid destroying the object on rethrow. */
+ current catch block. */
extern "C" void
-__cp_pop_exception (cp_eh_info *p, bool handler)
+__cp_pop_exception (cp_eh_info *p)
{
cp_eh_info **q = &__eh_info;
--p->handlers;
- if (p->handlers > 0 || (handler && p == *q))
+ /* Don't really pop if there are still active handlers for our exception,
+ or if our exception is being rethrown (i.e. if the active exception is
+ our exception and it is uncaught). */
+ if (p->handlers != 0
+ || (p == *q && !p->caught))
return;
for (; *q; q = &((*q)->next))
This routine is here to facilitate the porting of this code to
systems with threads. One can either replace the routine we emit a
call for here in libgcc2.c, or one can modify this routine to work
- with their thread system. */
+ with their thread system.
+
+ Ideally, we really only want one per real function, not one
+ per inlined function. */
rtx
get_dynamic_handler_chain ()
{
-#if 0
- /* Do this once we figure out how to get this to the front of the
- function, and we really only want one per real function, not one
- per inlined function. */
- if (current_function_dhc == 0)
+ static tree fn;
+ tree expr;
+ rtx insns;
+
+ if (current_function_dhc)
+ return current_function_dhc;
+
+ if (fn == NULL_TREE)
{
- rtx dhc, insns;
- start_sequence ();
-
- dhc = emit_library_call_value (get_dynamic_handler_chain_libfunc,
- NULL_RTX, 1,
- Pmode, 0);
- current_function_dhc = copy_to_reg (dhc);
- insns = get_insns ();
- end_sequence ();
- emit_insns_before (insns, get_first_nonparm_insn ());
+ tree fntype;
+ fn = get_identifier ("__get_dynamic_handler_chain");
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ fntype = build_pointer_type (build_pointer_type
+ (build_pointer_type (void_type_node)));
+ fntype = build_function_type (fntype, NULL_TREE);
+ fn = build_decl (FUNCTION_DECL, fn, fntype);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ TREE_READONLY (fn) = 1;
+ make_decl_rtl (fn, NULL_PTR, 1);
+ assemble_external (fn);
+ pop_obstacks ();
}
-#else
- rtx dhc;
- dhc = emit_library_call_value (get_dynamic_handler_chain_libfunc,
- NULL_RTX, 1,
- Pmode, 0);
- current_function_dhc = copy_to_reg (dhc);
-#endif
- /* We don't want a copy of the dhc, but rather, the single dhc. */
- return gen_rtx (MEM, Pmode, current_function_dhc);
+ expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+ expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ expr, NULL_TREE, NULL_TREE);
+ TREE_SIDE_EFFECTS (expr) = 1;
+ expr = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (expr)), expr);
+
+ start_sequence ();
+ current_function_dhc = expand_expr (expr, NULL_RTX, VOIDmode, 0);
+ insns = get_insns ();
+ end_sequence ();
+ emit_insns_before (insns, get_first_nonparm_insn ());
+
+ return current_function_dhc;
}
/* Get a reference to the dynamic cleanup chain. It points to the
}
expand_eh_region_start_for_decl (decl);
+ ehstack.top->entry->finalization = cleanup;
return 0;
}
}
}
+/* End the EH region for a goto fixup. We only need them in the region-based
+ EH scheme. */
+
+void
+expand_fixup_region_start ()
+{
+ if (! doing_eh (0) || exceptions_via_longjmp)
+ return;
+
+ expand_eh_region_start ();
+}
+
+/* End the EH region for a goto fixup. CLEANUP is the cleanup we just
+ expanded; to avoid running it twice if it throws, we look through the
+ ehqueue for a matching region and rethrow from its outer_context. */
+
+void
+expand_fixup_region_end (cleanup)
+ tree cleanup;
+{
+ tree t;
+ struct eh_node *node;
+ int yes;
+
+ if (! doing_eh (0) || exceptions_via_longjmp)
+ return;
+
+ for (node = ehstack.top; node && node->entry->finalization != cleanup; )
+ node = node->chain;
+ if (node == 0)
+ for (node = ehqueue.head; node && node->entry->finalization != cleanup; )
+ node = node->chain;
+ if (node == 0)
+ abort ();
+
+ yes = suspend_momentary ();
+
+ t = build (RTL_EXPR, void_type_node, NULL_RTX, const0_rtx);
+ TREE_SIDE_EFFECTS (t) = 1;
+ do_pending_stack_adjust ();
+ start_sequence_for_rtl_expr (t);
+ expand_internal_throw (node->entry->outer_context);
+ do_pending_stack_adjust ();
+ RTL_EXPR_SEQUENCE (t) = get_insns ();
+ end_sequence ();
+
+ resume_momentary (yes);
+
+ expand_eh_region_end (t);
+}
+
/* If we are using the setjmp/longjmp EH codegen method, we emit a
call to __sjthrow.
extern rtx terminate_libfunc;
extern rtx setjmp_libfunc;
extern rtx longjmp_libfunc;
-extern rtx get_dynamic_handler_chain_libfunc;
extern rtx eqhf2_libfunc;
extern rtx nehf2_libfunc;
register rtx insn;
register int i;
rtx nonlocal_label_list = nonlocal_label_rtx_list ();
+ int in_libcall_block = 0;
#ifdef ELIMINABLE_REGS
static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
{
register RTX_CODE prev_code = JUMP_INSN;
register RTX_CODE code;
+ int eh_region = 0;
max_uid_for_flow = 0;
for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
{
+
+ /* Track when we are inside in LIBCALL block. */
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+ in_libcall_block = 1;
+
code = GET_CODE (insn);
if (INSN_UID (insn) > max_uid_for_flow)
max_uid_for_flow = INSN_UID (insn);
|| (GET_RTX_CLASS (code) == 'i'
&& (prev_code == JUMP_INSN
|| (prev_code == CALL_INSN
- && nonlocal_label_list != 0)
+ && (nonlocal_label_list != 0 || eh_region)
+ && ! in_libcall_block)
|| prev_code == BARRIER)))
i++;
if (code != NOTE)
prev_code = code;
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+ ++eh_region;
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
+ --eh_region;
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ in_libcall_block = 0;
}
}
rtx x, note, eh_note;
enum rtx_code prev_code, code;
int depth, pass;
+ int in_libcall_block = 0;
pass = 1;
active_eh_handler = (rtx *) alloca ((max_uid_for_flow + 1) * sizeof (rtx));
for (eh_note = NULL_RTX, insn = f, i = -1, prev_code = JUMP_INSN, depth = 1;
insn; insn = NEXT_INSN (insn))
{
+
+ /* Track when we are inside in LIBCALL block. */
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+ in_libcall_block = 1;
+
code = GET_CODE (insn);
if (code == NOTE)
{
|| (GET_RTX_CLASS (code) == 'i'
&& (prev_code == JUMP_INSN
|| (prev_code == CALL_INSN
- && nonlocal_label_list != 0
- && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ && (nonlocal_label_list != 0 || eh_note)
+ && ! in_libcall_block)
|| prev_code == BARRIER)))
{
basic_block_head[++i] = insn;
&& (asynchronous_exceptions
|| code == CODE_LABEL
|| (GET_CODE (insn) == CALL_INSN
- && ! find_reg_note (insn, REG_RETVAL, NULL_RTX))))
+ && ! in_libcall_block)))
active_eh_handler[INSN_UID (insn)] = XEXP (eh_note, 0);
BLOCK_NUM (insn) = i;
if (code != NOTE)
prev_code = code;
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ in_libcall_block = 0;
}
/* During the second pass, `n_basic_blocks' is only an upper bound.
rtx terminate_libfunc;
rtx setjmp_libfunc;
rtx longjmp_libfunc;
-rtx get_dynamic_handler_chain_libfunc;
rtx eqhf2_libfunc;
rtx nehf2_libfunc;
setjmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "setjmp");
longjmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "longjmp");
#endif
- get_dynamic_handler_chain_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__get_dynamic_handler_chain");
eqhf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqhf2");
nehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nehf2");
the target. Though the cleanups are expanded multiple
times, the control paths are non-overlapping so the
cleanups will not be executed twice. */
+
+ /* We may need to protect fixups with rethrow regions. */
+ int protect = (in_fixup && ! TREE_ADDRESSABLE (tail));
+ if (protect)
+ expand_fixup_region_start ();
expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
+ if (protect)
+ expand_fixup_region_end (TREE_VALUE (tail));
free_temp_slots ();
}
}