From: Jason Merrill Date: Wed, 11 Feb 1998 10:21:23 +0000 (-0500) Subject: flow.c (find_basic_blocks): Don't create a new basic block for calls in a LIBCALL... X-Git-Tag: prereleases/egcs-1.0.2-prerelease~48 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ddb0137cdcda0f4e0ab44c71a01b78ae3a6f7f8f;p=thirdparty%2Fgcc.git flow.c (find_basic_blocks): Don't create a new basic block for calls in a LIBCALL block. * flow.c (find_basic_blocks): Don't create a new basic block for calls in a LIBCALL block. * flow.c (flow_analysis): Be consistent with find_basic_blocks in determining when a new basic block starts. * flow.c (find_basic_blocks): A CALL_INSN that can throw starts a new basic block. (find_basic_blocks_1): Likewise. * except.c (get_dynamic_handler_chain): Only make the call once per function. * 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. * except.c (get_dynamic_handler_chain): Build up a FUNCTION_DECL. * optabs.c (init_optabs): Lose get_dynamic_handler_chain_libfunc. * expr.h: Likewise. cp/: * decl.c (copy_args_p): Handle copy elision for types with virtual bases. * call.c (build_over_call): Likewise. * 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. From-SVN: r17856 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1f8d2de1d254..b75d4fdff739 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,37 @@ +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 + + * 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 + + * 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 + + * except.c (get_dynamic_handler_chain): Only make the call once per + function. + +Wed Dec 3 12:01:56 1997 Jason Merrill + + * 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 + + * 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 * stor-layout.c (layout_type): Do upper - lower in the native type, diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 87e72a1401e8..e57e66bfc9d2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +Mon Dec 8 23:17:13 1997 Jason Merrill + + * 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 + + * 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 * method.c (make_thunk): Avoid name buffer overflow. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 4e66a307e934..dc983b3c2687 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -5498,7 +5498,10 @@ build_over_call (fn, convs, args, flags) && 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; diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index fad7cfa5e8ae..2d7e72cfa3db 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10267,6 +10267,9 @@ copy_args_p (d) 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)) diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 65eaf8ae52d4..341ded8388db 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -474,8 +474,7 @@ build_eh_type (exp) 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"); @@ -490,9 +489,7 @@ do_pop_exception (handler) 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; @@ -505,8 +502,7 @@ do_pop_exception (handler) /* 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; } @@ -515,17 +511,15 @@ do_pop_exception (handler) 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 @@ -695,9 +689,6 @@ expand_end_catch_block () 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); diff --git a/gcc/cp/exception.cc b/gcc/cp/exception.cc index caaf58922826..57423ac06588 100644 --- a/gcc/cp/exception.cc +++ b/gcc/cp/exception.cc @@ -125,17 +125,20 @@ __cp_push_exception (void *value, void *type, void (*cleanup)(void *, int)) /* 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)) diff --git a/gcc/except.c b/gcc/except.c index 3336471bd86d..1924b10f9c87 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -729,38 +729,53 @@ add_partial_entry (handler) 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 @@ -993,6 +1008,7 @@ expand_eh_region_start_tree (decl, cleanup) } expand_eh_region_start_for_decl (decl); + ehstack.top->entry->finalization = cleanup; return 0; } @@ -1118,6 +1134,57 @@ expand_eh_region_end (handler) } } +/* 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. diff --git a/gcc/expr.h b/gcc/expr.h index fa7b7edd81c6..cd4cef0919fe 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -416,7 +416,6 @@ extern rtx sjpopnthrow_libfunc; 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; diff --git a/gcc/flow.c b/gcc/flow.c index 66374163e8bf..986d74aa90e2 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -282,6 +282,7 @@ flow_analysis (f, nregs, file) 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; @@ -304,11 +305,18 @@ flow_analysis (f, nregs, file) { 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); @@ -316,7 +324,8 @@ flow_analysis (f, nregs, file) || (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++; @@ -325,6 +334,14 @@ flow_analysis (f, nregs, file) 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; } } @@ -381,6 +398,7 @@ find_basic_blocks (f, nonlocal_label_list) 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)); @@ -404,6 +422,12 @@ find_basic_blocks (f, nonlocal_label_list) 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) { @@ -418,8 +442,8 @@ find_basic_blocks (f, nonlocal_label_list) || (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; @@ -482,13 +506,17 @@ find_basic_blocks (f, nonlocal_label_list) && (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. diff --git a/gcc/optabs.c b/gcc/optabs.c index a5f2e7ed0643..746713553455 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -124,7 +124,6 @@ rtx sjpopnthrow_libfunc; rtx terminate_libfunc; rtx setjmp_libfunc; rtx longjmp_libfunc; -rtx get_dynamic_handler_chain_libfunc; rtx eqhf2_libfunc; rtx nehf2_libfunc; @@ -4289,7 +4288,6 @@ init_optabs () 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"); diff --git a/gcc/stmt.c b/gcc/stmt.c index 573a3f19c3d6..65e376028d24 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -4229,7 +4229,14 @@ expand_cleanups (list, dont_do, in_fixup, reachable) 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 (); } }