This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Remove rtl-level exception handling
- From: Richard Henderson <rth at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 8 Jul 2004 00:49:03 -0700
- Subject: Remove rtl-level exception handling
Yaye. All of this is redundant with tree-eh.c.
Tested on i686-linux.
r~
* except.c (expand_eh_region_start, expand_eh_region_end,
expand_eh_handler, expand_eh_region_end_cleanup,
expand_start_all_catch, expand_start_catch, expand_end_catch,
expand_end_all_catch, expand_eh_region_end_allowed,
expand_eh_region_end_must_not_throw, expand_eh_region_end_throw,
expand_eh_region_end_fixup): Remove.
* stmt.c (struct nesting): Remove stack_level, innermost_stack_block,
cleanups, outer_cleanups, label_chain, exception_region.
(struct goto_fixup): Remove stack_level, cleanup_list_list.
(struct label_chain): Remove.
(struct stmt_status): Remove x_stack_block_stack.
(stack_block_stack, expand_goto_internal, expand_fixup, expand_fixups,
fixup_gotos, save_stack_pointer, expand_decl_cleanup,
expand_decl_cleanup_eh, expand_cleanups, start_cleanup_deferral,
end_cleanup_deferral, last_cleanup_this_contour,
containing_blocks_have_cleanups_or_stack_level,
any_pending_cleanups): Remove.
(expand_null_return_1): Take no arguments.
(expand_label, expand_naked_return, expand_return,
expand_start_bindings_and_block, expand_end_bindings, expand_decl,
expand_anon_union_decl, expand_start_case, pushcase, pushcase_range,
expand_end_case_type): Don't use any of them.
* calls.c (expand_call): Likewise.
* dojump.c (do_jump): Likewise.
* function.c (expand_function_end): Likewise.
* expr.c (store_expr, expand_expr_real_1): Likewise.
(safe_from_p): Don't handle WITH_CLEANUP_EXPR, CLEANUP_POINT_EXPR.
(expand_expr_real_1): Don't handle WITH_CLEANUP_EXPR,
CLEANUP_POINT_EXPR, TARGET_EXPR, TRY_CATCH_EXPR, CATCH_EXPR,
EH_FILTER_EXPR, TRY_FINALLY_EXPR, GOTO_SUBROUTINE_EXPR.
* fold-const.c (fold_checksum_tree): Use first_rtl_op.
* gengtype.c (adjust_field_tree_exp): Remove rtl op handling.
* gimplify.c (gimplify_cleanup_point_expr): Renumber operands
for WITH_CLEANUP_EXPR.
(gimple_push_cleanup): Likewise.
* integrate.c (copy_decl_for_inlining): Don't DECL_TOO_LATE.
* print-tree.c (print_node): Likewise.
* tree-pretty-print.c (dump_generic_node): Remove GOTO_SUBROUTINE_EXPR.
* tree.c (first_rtl_op): Always just TREE_CODE_LENGTH.
(has_cleanups): Remove GOTO_SUBROUTINE_EXPR.
* tree.def (WITH_CLEANUP_EXPR): Remove op1 and op2.
(GOTO_SUBROUTINE_EXPR): Remove.
* tree.h (WITH_CLEANUP_EXPR_RTL): Remove.
(DECL_TOO_LATE): Remove.
* except.h, tree.h: Update decls.
ada/
* trans.c (gnat_to_gnu <N_Handled_Sequence_Of_Statements>): Update
commentary.
cp/
* cp-tree.h (expand_eh_spec_block): Remove.
java/
* expr.c (case_identity, get_primitive_array_vtable,
java_expand_expr, emit_init_test_initialization): Remove.
* java-tree.h (java_expand_expr): Remove.
* lang.c (LANG_HOOKS_EXPAND_EXPR): Remove.
Index: gcc/calls.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/calls.c,v
retrieving revision 1.344
diff -c -p -d -r1.344 calls.c
*** gcc/calls.c 8 Jul 2004 05:58:35 -0000 1.344
--- gcc/calls.c 8 Jul 2004 07:19:32 -0000
*************** expand_call (tree exp, rtx target, int i
*** 2263,2269 ****
|| !flag_optimize_sibling_calls
|| !rtx_equal_function_value_matters
|| current_nesting_level () == 0
- || any_pending_cleanups ()
|| args_size.var
|| lookup_stmt_eh_region (exp) >= 0)
try_tail_call = 0;
--- 2263,2268 ----
*************** expand_call (tree exp, rtx target, int i
*** 2343,2352 ****
/* Do the same for the function address if it is an expression. */
if (!fndecl)
addr = fix_unsafe_tree (addr);
- /* Expanding one of those dangerous arguments could have added
- cleanups, but otherwise give it a whirl. */
- if (any_pending_cleanups ())
- try_tail_call = 0;
}
--- 2342,2347 ----
*************** expand_call (tree exp, rtx target, int i
*** 2959,2974 ****
/* If value type not void, return an rtx for the value. */
- /* If there are cleanups to be called, don't use a hard reg as target.
- We need to double check this and see if it matters anymore. */
- if (any_pending_cleanups ())
- {
- if (target && REG_P (target)
- && REGNO (target) < FIRST_PSEUDO_REGISTER)
- target = 0;
- sibcall_failure = 1;
- }
-
if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode
|| ignore)
target = const0_rtx;
--- 2954,2959 ----
*************** expand_call (tree exp, rtx target, int i
*** 3222,3228 ****
clear_pending_stack_adjust ();
emit_insn (gen_rtx_CLOBBER (VOIDmode, stack_pointer_rtx));
emit_move_insn (virtual_stack_dynamic_rtx, stack_pointer_rtx);
- save_stack_pointer ();
}
return target;
--- 3207,3212 ----
Index: gcc/dojump.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/dojump.c,v
retrieving revision 1.22
diff -c -p -d -r1.22 dojump.c
*** gcc/dojump.c 6 Jul 2004 20:01:08 -0000 1.22
--- gcc/dojump.c 8 Jul 2004 07:19:32 -0000
*************** do_jump (tree exp, rtx if_false_label, r
*** 290,307 ****
if (if_false_label == 0)
if_false_label = drop_through_label = gen_label_rtx ();
do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
- start_cleanup_deferral ();
do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
- end_cleanup_deferral ();
break;
case TRUTH_ORIF_EXPR:
if (if_true_label == 0)
if_true_label = drop_through_label = gen_label_rtx ();
do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
- start_cleanup_deferral ();
do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
- end_cleanup_deferral ();
break;
case COMPOUND_EXPR:
--- 290,303 ----
*************** do_jump (tree exp, rtx if_false_label, r
*** 362,368 ****
do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
- start_cleanup_deferral ();
/* Now the THEN-expression. */
do_jump (TREE_OPERAND (exp, 1),
if_false_label ? if_false_label : drop_through_label,
--- 358,363 ----
*************** do_jump (tree exp, rtx if_false_label, r
*** 375,381 ****
do_jump (TREE_OPERAND (exp, 2),
if_false_label ? if_false_label : drop_through_label,
if_true_label ? if_true_label : drop_through_label);
- end_cleanup_deferral ();
}
break;
--- 370,375 ----
Index: gcc/except.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/except.c,v
retrieving revision 1.276
diff -c -p -d -r1.276 except.c
*** gcc/except.c 18 Jun 2004 01:20:51 -0000 1.276
--- gcc/except.c 8 Jul 2004 07:19:32 -0000
*************** static hashval_t t2r_hash (const void *)
*** 260,267 ****
static void add_type_for_runtime (tree);
static tree lookup_type_for_runtime (tree);
- static struct eh_region *expand_eh_region_end (void);
-
static void resolve_fixup_regions (void);
static void remove_fixup_regions (void);
static void remove_unreachable_regions (rtx);
--- 260,265 ----
*************** set_eh_region_tree_label (struct eh_regi
*** 574,714 ****
region->tree_label = lab;
}
- /* Start an exception handling region. All instructions emitted
- after this point are considered to be part of the region until
- expand_eh_region_end is invoked. */
-
- void
- expand_eh_region_start (void)
- {
- struct eh_region *new;
- rtx note;
-
- if (! doing_eh (0))
- return;
-
- new = gen_eh_region (ERT_UNKNOWN, cfun->eh->cur_region);
- cfun->eh->cur_region = new;
-
- /* Create a note marking the start of this region. */
- note = emit_note (NOTE_INSN_EH_REGION_BEG);
- NOTE_EH_HANDLER (note) = new->region_number;
- }
-
- /* Common code to end a region. Returns the region just ended. */
-
- static struct eh_region *
- expand_eh_region_end (void)
- {
- struct eh_region *cur_region = cfun->eh->cur_region;
- rtx note;
-
- /* Create a note marking the end of this region. */
- note = emit_note (NOTE_INSN_EH_REGION_END);
- NOTE_EH_HANDLER (note) = cur_region->region_number;
-
- /* Pop. */
- cfun->eh->cur_region = cur_region->outer;
-
- return cur_region;
- }
-
- /* Expand HANDLER, which is the operand 1 of a TRY_CATCH_EXPR. Catch
- blocks and C++ exception-specifications are handled specially. */
-
- void
- expand_eh_handler (tree handler)
- {
- tree inner = expr_first (handler);
-
- switch (TREE_CODE (inner))
- {
- case CATCH_EXPR:
- expand_start_all_catch ();
- expand_expr (handler, const0_rtx, VOIDmode, 0);
- expand_end_all_catch ();
- break;
-
- case EH_FILTER_EXPR:
- if (EH_FILTER_MUST_NOT_THROW (handler))
- expand_eh_region_end_must_not_throw (EH_FILTER_FAILURE (handler));
- else
- expand_eh_region_end_allowed (EH_FILTER_TYPES (handler),
- EH_FILTER_FAILURE (handler));
- break;
-
- default:
- expand_eh_region_end_cleanup (handler);
- break;
- }
- }
-
- /* End an exception handling region for a cleanup. HANDLER is an
- expression to expand for the cleanup. */
-
- void
- expand_eh_region_end_cleanup (tree handler)
- {
- struct eh_region *region;
- tree protect_cleanup_actions;
- rtx around_label;
- rtx data_save[2];
-
- if (! doing_eh (0))
- return;
-
- region = expand_eh_region_end ();
- region->type = ERT_CLEANUP;
- region->label = gen_label_rtx ();
- region->u.cleanup.exp = handler;
- region->u.cleanup.prev_try = cfun->eh->try_region;
-
- around_label = gen_label_rtx ();
- emit_jump (around_label);
-
- emit_label (region->label);
-
- if (flag_non_call_exceptions || region->may_contain_throw)
- {
- /* Give the language a chance to specify an action to be taken if an
- exception is thrown that would propagate 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 (ptr_mode);
- 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. */
- region->resume
- = emit_jump_insn (gen_rtx_RESX (VOIDmode, region->region_number));
- emit_barrier ();
-
- emit_label (around_label);
- }
-
void
expand_resx_expr (tree exp)
{
--- 572,577 ----
*************** expand_resx_expr (tree exp)
*** 719,915 ****
emit_barrier ();
}
- /* End an exception handling region for a try block, and prepares
- for subsequent calls to expand_start_catch. */
-
- void
- expand_start_all_catch (void)
- {
- struct eh_region *region;
-
- if (! doing_eh (1))
- return;
-
- region = expand_eh_region_end ();
- region->type = ERT_TRY;
- region->u.try.prev_try = cfun->eh->try_region;
- region->u.try.continue_label = gen_label_rtx ();
-
- cfun->eh->try_region = region;
-
- emit_jump (region->u.try.continue_label);
- }
-
- /* Begin a catch clause. TYPE is the type caught, a list of such
- types, (in the case of Java) an ADDR_EXPR which points to the
- runtime type to match, or null if this is a catch-all
- clause. Providing a type list enables to associate the catch region
- with potentially several exception types, which is useful e.g. for
- Ada. */
-
- void
- expand_start_catch (tree type_or_list)
- {
- struct eh_region *c;
- rtx note;
-
- if (! doing_eh (0))
- return;
-
- c = gen_eh_region_catch (cfun->eh->try_region, type_or_list);
- cfun->eh->cur_region = c;
-
- c->label = gen_label_rtx ();
- emit_label (c->label);
-
- note = emit_note (NOTE_INSN_EH_REGION_BEG);
- NOTE_EH_HANDLER (note) = c->region_number;
- }
-
- /* End a catch clause. Control will resume after the try/catch block. */
-
- void
- expand_end_catch (void)
- {
- if (! doing_eh (0))
- return;
-
- expand_eh_region_end ();
- emit_jump (cfun->eh->try_region->u.try.continue_label);
- }
-
- /* End a sequence of catch handlers for a try block. */
-
- void
- expand_end_all_catch (void)
- {
- struct eh_region *try_region;
-
- if (! doing_eh (0))
- return;
-
- try_region = cfun->eh->try_region;
- cfun->eh->try_region = try_region->u.try.prev_try;
-
- emit_label (try_region->u.try.continue_label);
- }
-
- /* 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 occurs.
-
- ??? 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 (tree allowed, tree failure)
- {
- struct eh_region *region;
- rtx around_label;
-
- if (! doing_eh (0))
- return;
-
- region = expand_eh_region_end ();
- region->type = ERT_ALLOWED_EXCEPTIONS;
- region->u.allowed.type_list = allowed;
- region->label = gen_label_rtx ();
-
- for (; allowed ; allowed = TREE_CHAIN (allowed))
- add_type_for_runtime (TREE_VALUE (allowed));
-
- /* We must emit the call to FAILURE here, so that if this function
- throws a different exception, that it will be processed by the
- correct region. */
-
- around_label = gen_label_rtx ();
- emit_jump (around_label);
-
- emit_label (region->label);
- expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL);
- /* 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);
- }
-
- /* End an exception region for a must-not-throw filter. FAILURE is an
- expression invoke if an uncaught exception propagates this far.
-
- This is conceptually identical to expand_eh_region_end_allowed with
- an empty allowed list (if you passed "std::terminate" instead of
- "__cxa_call_unexpected"), but they are represented differently in
- the C++ LSDA. */
-
- void
- expand_eh_region_end_must_not_throw (tree failure)
- {
- struct eh_region *region;
- rtx around_label;
-
- if (! doing_eh (0))
- return;
-
- region = expand_eh_region_end ();
- region->type = ERT_MUST_NOT_THROW;
- region->label = gen_label_rtx ();
-
- /* We must emit the call to FAILURE here, so that if this function
- throws a different exception, that it will be processed by the
- correct region. */
-
- around_label = gen_label_rtx ();
- emit_jump (around_label);
-
- emit_label (region->label);
- expand_expr (failure, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
- emit_label (around_label);
- }
-
- /* End an exception region for a throw. No handling goes on here,
- but it's the easiest way for the front-end to indicate what type
- is being thrown. */
-
- void
- expand_eh_region_end_throw (tree type)
- {
- struct eh_region *region;
-
- if (! doing_eh (0))
- return;
-
- region = expand_eh_region_end ();
- region->type = ERT_THROW;
- region->u.throw.type = type;
- }
-
- /* End a fixup region. Within this region the cleanups for the immediately
- enclosing region are _not_ run. This is used for goto cleanup to avoid
- destroying an object twice.
-
- This would be an extraordinarily simple prospect, were it not for the
- fact that we don't actually know what the immediately enclosing region
- is. This surprising fact is because expand_cleanups is currently
- generating a sequence that it will insert somewhere else. We collect
- the proper notion of "enclosing" in convert_from_eh_region_ranges. */
-
- void
- expand_eh_region_end_fixup (tree handler)
- {
- struct eh_region *fixup;
-
- if (! doing_eh (0))
- return;
-
- fixup = expand_eh_region_end ();
- fixup->type = ERT_FIXUP;
- fixup->u.fixup.cleanup_exp = handler;
- }
-
/* Note that the current EH region (if any) may contain a throw, or a
call to a function which itself may contain a throw. */
--- 582,587 ----
*************** get_exception_filter (struct function *f
*** 962,970 ****
/* This section is for the exception handling specific optimization pass. */
! /* Random access the exception region tree. It's just as simple to
! collect the regions this way as in expand_eh_region_start, but
! without having to realloc memory. */
void
collect_eh_region_array (void)
--- 634,640 ----
/* This section is for the exception handling specific optimization pass. */
! /* Random access the exception region tree. */
void
collect_eh_region_array (void)
Index: gcc/except.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/except.h,v
retrieving revision 1.76
diff -c -p -d -r1.76 except.h
*** gcc/except.h 4 Jun 2004 12:31:26 -0000 1.76
--- gcc/except.h 8 Jul 2004 07:19:32 -0000
*************** struct eh_region;
*** 35,86 ****
/* Test: is exception handling turned on? */
extern int doing_eh (int);
- /* Start an exception handling region. All instructions emitted after
- this point are considered to be part of the region until an
- expand_eh_region_end variant is invoked. */
- extern void expand_eh_region_start (void);
-
- /* End an exception handling region for a cleanup. HANDLER is an
- expression to expand for the cleanup. */
- extern void expand_eh_region_end_cleanup (tree);
-
- /* End an exception handling region for a try block, and prepares
- for subsequent calls to expand_start_catch. */
- extern void expand_start_all_catch (void);
-
- /* Begin a catch clause. TYPE is an object to be matched by the
- runtime, or a list of such objects, or null if this is a catch-all
- clause. */
- extern void expand_start_catch (tree);
-
- /* End a catch clause. Control will resume after the try/catch block. */
- extern void expand_end_catch (void);
-
- /* End a sequence of catch handlers for a try block. */
- extern void expand_end_all_catch (void);
-
- /* End an exception region for an exception type filter. ALLOWED is a
- TREE_LIST of TREE_VALUE objects to be matched by the runtime.
- FAILURE is a function to invoke if a mismatch occurs. */
- extern void expand_eh_region_end_allowed (tree, tree);
-
- /* End an exception region for a must-not-throw filter. FAILURE is a
- function to invoke if an uncaught exception propagates this far. */
- extern void expand_eh_region_end_must_not_throw (tree);
-
- /* End an exception region for a throw. No handling goes on here,
- but it's the easiest way for the front-end to indicate what type
- is being thrown. */
- extern void expand_eh_region_end_throw (tree);
-
- /* End a fixup region. Within this region the cleanups for the immediately
- enclosing region are _not_ run. This is used for goto cleanup to avoid
- destroying an object twice. */
- extern void expand_eh_region_end_fixup (tree);
-
- /* End some sort of EH region, depending on the argument. */
- extern void expand_eh_handler (tree);
-
/* Note that the current EH region (if any) may contain a throw, or a
call to a function which itself may contain a throw. */
extern void note_eh_region_may_contain_throw (struct eh_region *);
--- 35,40 ----
Index: gcc/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.672
diff -c -p -d -r1.672 expr.c
*** gcc/expr.c 7 Jul 2004 21:26:28 -0000 1.672
--- gcc/expr.c 8 Jul 2004 07:19:33 -0000
*************** store_expr (tree exp, rtx target, int wa
*** 4071,4086 ****
do_pending_stack_adjust ();
NO_DEFER_POP;
jumpifnot (TREE_OPERAND (exp, 0), lab1);
- start_cleanup_deferral ();
store_expr (TREE_OPERAND (exp, 1), target, want_value & 2);
- end_cleanup_deferral ();
emit_queue ();
emit_jump_insn (gen_jump (lab2));
emit_barrier ();
emit_label (lab1);
- start_cleanup_deferral ();
store_expr (TREE_OPERAND (exp, 2), target, want_value & 2);
- end_cleanup_deferral ();
emit_queue ();
emit_label (lab2);
OK_DEFER_POP;
--- 4071,4082 ----
*************** safe_from_p (rtx x, tree exp, int top_p)
*** 6042,6051 ****
break;
case WITH_CLEANUP_EXPR:
- exp_rtl = WITH_CLEANUP_EXPR_RTL (exp);
- break;
-
case CLEANUP_POINT_EXPR:
case SAVE_EXPR:
return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
--- 6038,6047 ----
break;
case WITH_CLEANUP_EXPR:
case CLEANUP_POINT_EXPR:
+ /* Lowered by gimplify.c. */
+ abort ();
+
case SAVE_EXPR:
return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
*************** expand_expr_real_1 (tree exp, rtx target
*** 7345,7380 ****
case OBJ_TYPE_REF:
return expand_expr (OBJ_TYPE_REF_EXPR (exp), target, tmode, modifier);
- case WITH_CLEANUP_EXPR:
- if (WITH_CLEANUP_EXPR_RTL (exp) == 0)
- {
- WITH_CLEANUP_EXPR_RTL (exp)
- = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
- expand_decl_cleanup_eh (NULL_TREE, TREE_OPERAND (exp, 1),
- CLEANUP_EH_ONLY (exp));
-
- /* That's it for this cleanup. */
- TREE_OPERAND (exp, 1) = 0;
- }
- return WITH_CLEANUP_EXPR_RTL (exp);
-
- case CLEANUP_POINT_EXPR:
- {
- /* Start a new binding layer that will keep track of all cleanup
- actions to be performed. */
- expand_start_bindings (2);
-
- target_temp_slot_level = temp_slot_level;
-
- op0 = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
- /* If we're going to use this value, load it up now. */
- if (! ignore)
- op0 = force_not_mem (op0);
- preserve_temp_slots (op0);
- expand_end_bindings (NULL_TREE, 0, 0);
- }
- return op0;
-
case CALL_EXPR:
/* Check for a built-in function. */
if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
--- 7341,7346 ----
*************** expand_expr_real_1 (tree exp, rtx target
*** 8180,8194 ****
tree then_ = TREE_OPERAND (exp, 1);
tree else_ = TREE_OPERAND (exp, 2);
! /* If we do not have any pending cleanups or stack_levels
! to restore, and at least one arm of the COND_EXPR is a
! GOTO_EXPR to a local label, then we can emit more efficient
! code by using jumpif/jumpifnot instead of the 'if' machinery. */
! if (! optimize
! || containing_blocks_have_cleanups_or_stack_level ())
! ;
! else if (TREE_CODE (then_) == GOTO_EXPR
! && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
{
jumpif (pred, label_rtx (GOTO_DESTINATION (then_)));
return expand_expr (else_, const0_rtx, VOIDmode, 0);
--- 8146,8153 ----
tree then_ = TREE_OPERAND (exp, 1);
tree else_ = TREE_OPERAND (exp, 2);
! if (TREE_CODE (then_) == GOTO_EXPR
! && TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
{
jumpif (pred, label_rtx (GOTO_DESTINATION (then_)));
return expand_expr (else_, const0_rtx, VOIDmode, 0);
*************** expand_expr_real_1 (tree exp, rtx target
*** 8202,8208 ****
/* Just use the 'if' machinery. */
expand_start_cond (pred, 0);
- start_cleanup_deferral ();
expand_expr (then_, const0_rtx, VOIDmode, 0);
exp = else_;
--- 8161,8166 ----
*************** expand_expr_real_1 (tree exp, rtx target
*** 8225,8231 ****
expand_start_else ();
expand_expr (exp, const0_rtx, VOIDmode, 0);
}
- end_cleanup_deferral ();
expand_end_cond ();
return const0_rtx;
}
--- 8183,8188 ----
*************** expand_expr_real_1 (tree exp, rtx target
*** 8422,8428 ****
else
jumpifnot (TREE_OPERAND (exp, 0), op0);
- start_cleanup_deferral ();
if (binary_op && temp == 0)
/* Just touch the other operand. */
expand_expr (TREE_OPERAND (binary_op, 1),
--- 8379,8384 ----
*************** expand_expr_real_1 (tree exp, rtx target
*** 8458,8464 ****
modifier == EXPAND_STACK_PARM ? 2 : 0);
jumpif (TREE_OPERAND (exp, 0), op0);
- start_cleanup_deferral ();
if (TREE_TYPE (TREE_OPERAND (exp, 2)) != void_type_node)
store_expr (TREE_OPERAND (exp, 2), temp,
modifier == EXPAND_STACK_PARM ? 2 : 0);
--- 8414,8419 ----
*************** expand_expr_real_1 (tree exp, rtx target
*** 8483,8489 ****
modifier == EXPAND_STACK_PARM ? 2 : 0);
jumpifnot (TREE_OPERAND (exp, 0), op0);
- start_cleanup_deferral ();
if (TREE_TYPE (TREE_OPERAND (exp, 1)) != void_type_node)
store_expr (TREE_OPERAND (exp, 1), temp,
modifier == EXPAND_STACK_PARM ? 2 : 0);
--- 8438,8443 ----
*************** expand_expr_real_1 (tree exp, rtx target
*** 8497,8504 ****
op1 = gen_label_rtx ();
jumpifnot (TREE_OPERAND (exp, 0), op0);
- start_cleanup_deferral ();
-
/* One branch of the cond can be void, if it never returns. For
example A ? throw : E */
if (temp != 0
--- 8451,8456 ----
*************** expand_expr_real_1 (tree exp, rtx target
*** 8508,8519 ****
else
expand_expr (TREE_OPERAND (exp, 1),
ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
- end_cleanup_deferral ();
emit_queue ();
emit_jump_insn (gen_jump (op1));
emit_barrier ();
emit_label (op0);
- start_cleanup_deferral ();
if (temp != 0
&& TREE_TYPE (TREE_OPERAND (exp, 2)) != void_type_node)
store_expr (TREE_OPERAND (exp, 2), temp,
--- 8460,8469 ----
*************** expand_expr_real_1 (tree exp, rtx target
*** 8523,8530 ****
ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
}
- end_cleanup_deferral ();
-
emit_queue ();
emit_label (op1);
OK_DEFER_POP;
--- 8473,8478 ----
*************** expand_expr_real_1 (tree exp, rtx target
*** 8532,8629 ****
return temp;
}
- case TARGET_EXPR:
- {
- /* Something needs to be initialized, but we didn't know
- where that thing was when building the tree. For example,
- it could be the return value of a function, or a parameter
- to a function which lays down in the stack, or a temporary
- variable which must be passed by reference.
-
- We guarantee that the expression will either be constructed
- or copied into our original target. */
-
- tree slot = TREE_OPERAND (exp, 0);
- tree cleanups = NULL_TREE;
- tree exp1;
-
- if (TREE_CODE (slot) != VAR_DECL)
- abort ();
-
- if (! ignore)
- target = original_target;
-
- /* Set this here so that if we get a target that refers to a
- register variable that's already been used, put_reg_into_stack
- knows that it should fix up those uses. */
- TREE_USED (slot) = 1;
-
- if (target == 0)
- {
- if (DECL_RTL_SET_P (slot))
- {
- target = DECL_RTL (slot);
- /* If we have already expanded the slot, so don't do
- it again. (mrs) */
- if (TREE_OPERAND (exp, 1) == NULL_TREE)
- return target;
- }
- else
- {
- target = assign_temp (type, 2, 0, 1);
- SET_DECL_RTL (slot, target);
-
- /* Since SLOT is not known to the called function
- to belong to its stack frame, we must build an explicit
- cleanup. This case occurs when we must build up a reference
- to pass the reference as an argument. In this case,
- it is very likely that such a reference need not be
- built here. */
-
- if (TREE_OPERAND (exp, 2) == 0)
- TREE_OPERAND (exp, 2)
- = lang_hooks.maybe_build_cleanup (slot);
- cleanups = TREE_OPERAND (exp, 2);
- }
- }
- else
- {
- /* This case does occur, when expanding a parameter which
- needs to be constructed on the stack. The target
- is the actual stack address that we want to initialize.
- The function we call will perform the cleanup in this case. */
-
- /* If we have already assigned it space, use that space,
- not target that we were passed in, as our target
- parameter is only a hint. */
- if (DECL_RTL_SET_P (slot))
- {
- target = DECL_RTL (slot);
- /* If we have already expanded the slot, so don't do
- it again. (mrs) */
- if (TREE_OPERAND (exp, 1) == NULL_TREE)
- return target;
- }
- else
- SET_DECL_RTL (slot, target);
- }
-
- exp1 = TREE_OPERAND (exp, 3) = TREE_OPERAND (exp, 1);
- /* Mark it as expanded. */
- TREE_OPERAND (exp, 1) = NULL_TREE;
-
- if (VOID_TYPE_P (TREE_TYPE (exp1)))
- /* If the initializer is void, just expand it; it will initialize
- the object directly. */
- expand_expr (exp1, const0_rtx, VOIDmode, 0);
- else
- store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0);
-
- expand_decl_cleanup_eh (NULL_TREE, cleanups, CLEANUP_EH_ONLY (exp));
-
- return target;
- }
-
case INIT_EXPR:
{
tree lhs = TREE_OPERAND (exp, 0);
--- 8480,8485 ----
*************** expand_expr_real_1 (tree exp, rtx target
*** 8927,9020 ****
return const0_rtx;
case TRY_CATCH_EXPR:
- {
- tree handler = TREE_OPERAND (exp, 1);
-
- expand_eh_region_start ();
- op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
- expand_eh_handler (handler);
-
- return op0;
- }
-
case CATCH_EXPR:
- expand_start_catch (CATCH_TYPES (exp));
- expand_expr (CATCH_BODY (exp), const0_rtx, VOIDmode, 0);
- expand_end_catch ();
- return const0_rtx;
-
case EH_FILTER_EXPR:
- /* Should have been handled in expand_eh_handler. */
- abort ();
-
case TRY_FINALLY_EXPR:
! {
! tree try_block = TREE_OPERAND (exp, 0);
! tree finally_block = TREE_OPERAND (exp, 1);
!
! if ((!optimize && lang_protect_cleanup_actions == NULL)
! || unsafe_for_reeval (finally_block) > 1)
! {
! /* In this case, wrapping FINALLY_BLOCK in an UNSAVE_EXPR
! is not sufficient, so we cannot expand the block twice.
! So we play games with GOTO_SUBROUTINE_EXPR to let us
! expand the thing only once. */
! /* When not optimizing, we go ahead with this form since
! (1) user breakpoints operate more predictably without
! code duplication, and
! (2) we're not running any of the global optimizers
! that would explode in time/space with the highly
! connected CFG created by the indirect branching. */
!
! rtx finally_label = gen_label_rtx ();
! rtx done_label = gen_label_rtx ();
! rtx return_link = gen_reg_rtx (Pmode);
! tree cleanup = build (GOTO_SUBROUTINE_EXPR, void_type_node,
! (tree) finally_label, (tree) return_link);
! TREE_SIDE_EFFECTS (cleanup) = 1;
!
! /* Start a new binding layer that will keep track of all cleanup
! actions to be performed. */
! expand_start_bindings (2);
! target_temp_slot_level = temp_slot_level;
!
! expand_decl_cleanup (NULL_TREE, cleanup);
! op0 = expand_expr (try_block, target, tmode, modifier);
!
! preserve_temp_slots (op0);
! expand_end_bindings (NULL_TREE, 0, 0);
! emit_jump (done_label);
! emit_label (finally_label);
! expand_expr (finally_block, const0_rtx, VOIDmode, 0);
! emit_indirect_jump (return_link);
! emit_label (done_label);
! }
! else
! {
! expand_start_bindings (2);
! target_temp_slot_level = temp_slot_level;
!
! expand_decl_cleanup (NULL_TREE, finally_block);
! op0 = expand_expr (try_block, target, tmode, modifier);
!
! preserve_temp_slots (op0);
! expand_end_bindings (NULL_TREE, 0, 0);
! }
!
! return op0;
! }
! case GOTO_SUBROUTINE_EXPR:
! {
! rtx subr = (rtx) TREE_OPERAND (exp, 0);
! rtx return_link = *(rtx *) &TREE_OPERAND (exp, 1);
! rtx return_address = gen_label_rtx ();
! emit_move_insn (return_link,
! gen_rtx_LABEL_REF (Pmode, return_address));
! emit_jump (subr);
! emit_label (return_address);
! return const0_rtx;
! }
case VA_ARG_EXPR:
return expand_builtin_va_arg (TREE_OPERAND (exp, 0), type);
--- 8783,8799 ----
return const0_rtx;
case TRY_CATCH_EXPR:
case CATCH_EXPR:
case EH_FILTER_EXPR:
case TRY_FINALLY_EXPR:
! /* Lowered by tree-eh.c. */
! abort ();
! case WITH_CLEANUP_EXPR:
! case CLEANUP_POINT_EXPR:
! case TARGET_EXPR:
! /* Lowered by gimplify.c. */
! abort ();
case VA_ARG_EXPR:
return expand_builtin_va_arg (TREE_OPERAND (exp, 0), type);
Index: gcc/fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.419
diff -c -p -d -r1.419 fold-const.c
*** gcc/fold-const.c 7 Jul 2004 21:28:01 -0000 1.419
--- gcc/fold-const.c 8 Jul 2004 07:19:33 -0000
*************** fold_checksum_tree (tree expr, struct md
*** 9048,9054 ****
fold_checksum_tree (TREE_TYPE (expr), ctx, ht);
if (TREE_CODE_CLASS (code) != 't' && TREE_CODE_CLASS (code) != 'd')
fold_checksum_tree (TREE_CHAIN (expr), ctx, ht);
- len = TREE_CODE_LENGTH (code);
switch (TREE_CODE_CLASS (code))
{
case 'c':
--- 9048,9053 ----
*************** fold_checksum_tree (tree expr, struct md
*** 9085,9102 ****
}
break;
case 'e':
- switch (code)
- {
- case GOTO_SUBROUTINE_EXPR: len = 0; break;
- case WITH_CLEANUP_EXPR: len = 2; break;
- default: break;
- }
- /* Fall through. */
case 'r':
case '<':
case '1':
case '2':
case 's':
for (i = 0; i < len; ++i)
fold_checksum_tree (TREE_OPERAND (expr, i), ctx, ht);
break;
--- 9084,9095 ----
}
break;
case 'e':
case 'r':
case '<':
case '1':
case '2':
case 's':
+ len = first_rtl_op (code);
for (i = 0; i < len; ++i)
fold_checksum_tree (TREE_OPERAND (expr, i), ctx, ht);
break;
Index: gcc/function.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/function.c,v
retrieving revision 1.548
diff -c -p -d -r1.548 function.c
*** gcc/function.c 7 Jul 2004 23:02:22 -0000 1.548
--- gcc/function.c 8 Jul 2004 07:19:33 -0000
*************** expand_function_end (void)
*** 4554,4568 ****
sh mach_dep_reorg) that still try and compute their own lifetime info
instead of using the general framework. */
use_return_register ();
-
- /* Fix up any gotos that jumped out to the outermost
- binding level of the function.
- Must follow emitting RETURN_LABEL. */
-
- /* If you have any cleanups to do at this point,
- and they need to create temporary variables,
- then you will lose. */
- expand_fixups (get_insns ());
}
rtx
--- 4554,4559 ----
Index: gcc/gengtype.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gengtype.c,v
retrieving revision 1.55
diff -c -p -d -r1.55 gengtype.c
*** gcc/gengtype.c 3 Jul 2004 00:15:43 -0000 1.55
--- gcc/gengtype.c 8 Jul 2004 07:19:33 -0000
*************** adjust_field_tree_exp (type_p t, options
*** 644,658 ****
{
pair_p flds;
options_p nodot;
- size_t i;
- static const struct {
- const char *name;
- int first_rtl;
- int num_rtl;
- } data[] = {
- { "GOTO_SUBROUTINE_EXPR", 0, 2 },
- { "WITH_CLEANUP_EXPR", 2, 1 },
- };
if (t->kind != TYPE_ARRAY)
{
--- 644,649 ----
*************** adjust_field_tree_exp (type_p t, options
*** 684,727 ****
flds->opt->info = "";
}
- for (i = 0; i < ARRAY_SIZE (data); i++)
- {
- pair_p old_flds = flds;
- pair_p subfields = NULL;
- int r_index;
- const char *sname;
-
- for (r_index = 0;
- r_index < data[i].first_rtl + data[i].num_rtl;
- r_index++)
- {
- pair_p old_subf = subfields;
- subfields = xmalloc (sizeof (*subfields));
- subfields->next = old_subf;
- subfields->name = xasprintf ("[%d]", r_index);
- if (r_index < data[i].first_rtl)
- subfields->type = t->u.a.p;
- else
- subfields->type = create_pointer (find_structure ("rtx_def", 0));
- subfields->line.file = __FILE__;
- subfields->line.line = __LINE__;
- subfields->opt = nodot;
- }
-
- flds = xmalloc (sizeof (*flds));
- flds->next = old_flds;
- flds->name = "";
- sname = xasprintf ("tree_exp_%s", data[i].name);
- new_structure (sname, 0, &lexer_line, subfields, NULL);
- flds->type = find_structure (sname, 0);
- flds->line.file = __FILE__;
- flds->line.line = __LINE__;
- flds->opt = xmalloc (sizeof (*flds->opt));
- flds->opt->next = nodot;
- flds->opt->name = "tag";
- flds->opt->info = data[i].name;
- }
-
new_structure ("tree_exp_subunion", 1, &lexer_line, flds, nodot);
return find_structure ("tree_exp_subunion", 1);
}
--- 675,680 ----
Index: gcc/gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.42
diff -c -p -d -r2.42 gimplify.c
*** gcc/gimplify.c 6 Jul 2004 02:20:08 -0000 2.42
--- gcc/gimplify.c 8 Jul 2004 07:19:34 -0000
*************** gimplify_cleanup_point_expr (tree *expr_
*** 3210,3216 ****
{
if (tsi_one_before_end_p (iter))
{
! tsi_link_before (&iter, TREE_OPERAND (wce, 1), TSI_SAME_STMT);
tsi_delink (&iter);
break;
}
--- 3210,3216 ----
{
if (tsi_one_before_end_p (iter))
{
! tsi_link_before (&iter, TREE_OPERAND (wce, 0), TSI_SAME_STMT);
tsi_delink (&iter);
break;
}
*************** gimplify_cleanup_point_expr (tree *expr_
*** 3220,3227 ****
sl = tsi_split_statement_list_after (&iter);
tfe = build (TRY_FINALLY_EXPR, void_type_node, sl, NULL_TREE);
! append_to_statement_list (TREE_OPERAND (wce, 1),
! &TREE_OPERAND (tfe, 1));
*wce_p = tfe;
iter = tsi_start (sl);
}
--- 3220,3227 ----
sl = tsi_split_statement_list_after (&iter);
tfe = build (TRY_FINALLY_EXPR, void_type_node, sl, NULL_TREE);
! append_to_statement_list (TREE_OPERAND (wce, 0),
! &TREE_OPERAND (tfe, 1));
*wce_p = tfe;
iter = tsi_start (sl);
}
*************** gimple_push_cleanup (tree var, tree clea
*** 3285,3292 ****
tree ftrue = build (MODIFY_EXPR, void_type_node, flag,
boolean_true_node);
cleanup = build (COND_EXPR, void_type_node, flag, cleanup, NULL);
! wce = build (WITH_CLEANUP_EXPR, void_type_node, NULL_TREE,
! cleanup, NULL_TREE);
append_to_statement_list (ffalse, &gimplify_ctxp->conditional_cleanups);
append_to_statement_list (wce, &gimplify_ctxp->conditional_cleanups);
append_to_statement_list (ftrue, pre_p);
--- 3285,3291 ----
tree ftrue = build (MODIFY_EXPR, void_type_node, flag,
boolean_true_node);
cleanup = build (COND_EXPR, void_type_node, flag, cleanup, NULL);
! wce = build (WITH_CLEANUP_EXPR, void_type_node, cleanup);
append_to_statement_list (ffalse, &gimplify_ctxp->conditional_cleanups);
append_to_statement_list (wce, &gimplify_ctxp->conditional_cleanups);
append_to_statement_list (ftrue, pre_p);
*************** gimple_push_cleanup (tree var, tree clea
*** 3298,3309 ****
}
else
{
! wce = build (WITH_CLEANUP_EXPR, void_type_node, NULL_TREE,
! cleanup, NULL_TREE);
append_to_statement_list (wce, pre_p);
}
! gimplify_stmt (&TREE_OPERAND (wce, 1));
}
/* Gimplify a TARGET_EXPR which doesn't appear on the rhs of an INIT_EXPR. */
--- 3297,3307 ----
}
else
{
! wce = build (WITH_CLEANUP_EXPR, void_type_node, cleanup);
append_to_statement_list (wce, pre_p);
}
! gimplify_stmt (&TREE_OPERAND (wce, 0));
}
/* Gimplify a TARGET_EXPR which doesn't appear on the rhs of an INIT_EXPR. */
Index: gcc/integrate.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/integrate.c,v
retrieving revision 1.264
diff -c -p -d -r1.264 integrate.c
*** gcc/integrate.c 7 Jul 2004 19:23:59 -0000 1.264
--- gcc/integrate.c 8 Jul 2004 07:19:34 -0000
*************** copy_decl_for_inlining (tree decl, tree
*** 160,166 ****
if (TREE_CODE (copy) == LABEL_DECL)
{
TREE_ADDRESSABLE (copy) = 0;
- DECL_TOO_LATE (copy) = 0;
}
}
--- 160,165 ----
Index: gcc/print-tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/print-tree.c,v
retrieving revision 1.88
diff -c -p -d -r1.88 print-tree.c
*** gcc/print-tree.c 3 Jul 2004 00:15:43 -0000 1.88
--- gcc/print-tree.c 8 Jul 2004 07:19:34 -0000
*************** print_node (FILE *file, const char *pref
*** 337,344 ****
if (TREE_CODE (node) == FIELD_DECL && DECL_NONADDRESSABLE_P (node))
fputs (" nonaddressable", file);
- if (TREE_CODE (node) == LABEL_DECL && DECL_TOO_LATE (node))
- fputs (" too-late", file);
if (TREE_CODE (node) == LABEL_DECL && DECL_ERROR_ISSUED (node))
fputs (" error-issued", file);
--- 337,342 ----
Index: gcc/stmt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/stmt.c,v
retrieving revision 1.371
diff -c -p -d -r1.371 stmt.c
*** gcc/stmt.c 5 Jul 2004 21:57:44 -0000 1.371
--- gcc/stmt.c 8 Jul 2004 07:19:34 -0000
*************** struct nesting GTY(())
*** 164,196 ****
/* Sequence number of this binding contour within the function,
in order of entry. */
int block_start_count;
- /* Nonzero => value to restore stack to on exit. */
- rtx stack_level;
/* The NOTE that starts this contour.
Used by expand_goto to check whether the destination
is within each contour or not. */
rtx first_insn;
- /* Innermost containing binding contour that has a stack level. */
- struct nesting *innermost_stack_block;
- /* List of cleanups to be run on exit from this contour.
- This is a list of expressions to be evaluated.
- The TREE_PURPOSE of each link is the ..._DECL node
- which the cleanup pertains to. */
- tree cleanups;
- /* List of cleanup-lists of blocks containing this block,
- as they were at the locus where this block appears.
- There is an element for each containing block,
- ordered innermost containing block first.
- The tail of this list can be 0,
- if all remaining elements would be empty lists.
- The element's TREE_VALUE is the cleanup-list of that block,
- which may be null. */
- tree outer_cleanups;
- /* Chain of labels defined inside this binding contour.
- For contours that have stack levels or cleanups. */
- struct label_chain *label_chain;
- /* Nonzero if this is associated with an EH region. */
- int exception_region;
/* The saved target_temp_slot_level from our outer block.
We may reset target_temp_slot_level to be the level of
this block, if that is done, target_temp_slot_level
--- 164,173 ----
*************** do { struct nesting *target = STACK; \
*** 251,258 ****
cond_stack = cond_stack->next; \
if (block_stack == this) \
block_stack = block_stack->next; \
- if (stack_block_stack == this) \
- stack_block_stack = stack_block_stack->next; \
if (case_stack == this) \
case_stack = case_stack->next; \
nesting_depth = nesting_stack->depth - 1; \
--- 228,233 ----
*************** struct goto_fixup GTY(())
*** 284,311 ****
/* Number of binding contours started in current function
before the label reference. */
int block_start_count;
- /* The outermost stack level that should be restored for this jump.
- Each time a binding contour that resets the stack is exited,
- if the target label is *not* yet defined, this slot is updated. */
- rtx stack_level;
- /* List of lists of cleanup expressions to be run by this goto.
- There is one element for each block that this goto is within.
- The tail of this list can be 0,
- if all remaining elements would be empty.
- The TREE_VALUE contains the cleanup list of that block as of the
- time this goto was seen.
- The TREE_ADDRESSABLE flag is 1 for a block that has been exited. */
- tree cleanup_list_list;
- };
-
- /* Within any binding contour that must restore a stack level,
- all labels are recorded with a chain of these structures. */
-
- struct label_chain GTY(())
- {
- /* Points to following fixup. */
- struct label_chain *next;
- tree label;
};
struct stmt_status GTY(())
--- 259,264 ----
*************** struct stmt_status GTY(())
*** 315,324 ****
/* If any new stacks are added here, add them to POPSTACKS too. */
- /* Chain of all pending binding contours that restore stack levels
- or have cleanups. */
- struct nesting * x_stack_block_stack;
-
/* Chain of all pending conditional statements. */
struct nesting * x_cond_stack;
--- 268,273 ----
*************** struct stmt_status GTY(())
*** 343,349 ****
};
#define block_stack (cfun->stmt->x_block_stack)
- #define stack_block_stack (cfun->stmt->x_stack_block_stack)
#define cond_stack (cfun->stmt->x_cond_stack)
#define case_stack (cfun->stmt->x_case_stack)
#define nesting_stack (cfun->stmt->x_nesting_stack)
--- 292,297 ----
*************** int using_eh_for_cleanups_p = 0;
*** 357,374 ****
static int n_occurrences (int, const char *);
static bool decl_conflicts_with_clobbers_p (tree, const HARD_REG_SET);
- static void expand_goto_internal (tree, rtx, rtx);
- static int expand_fixup (tree, rtx, rtx);
static void expand_nl_goto_receiver (void);
- static void fixup_gotos (struct nesting *, rtx, tree, rtx, int);
static bool check_operand_nalternatives (tree, tree);
static bool check_unique_operand_names (tree, tree);
static char *resolve_operand_name_1 (char *, tree, tree);
! static void expand_null_return_1 (rtx);
static enum br_predictor return_prediction (rtx);
static rtx shift_return_value (rtx);
static void expand_value_return (rtx);
- static void expand_cleanups (tree, int, int);
static void do_jump_if_equal (rtx, rtx, rtx, int);
static int estimate_case_costs (case_node_ptr);
static bool same_case_target_p (rtx, rtx);
--- 305,318 ----
static int n_occurrences (int, const char *);
static bool decl_conflicts_with_clobbers_p (tree, const HARD_REG_SET);
static void expand_nl_goto_receiver (void);
static bool check_operand_nalternatives (tree, tree);
static bool check_unique_operand_names (tree, tree);
static char *resolve_operand_name_1 (char *, tree, tree);
! static void expand_null_return_1 (void);
static enum br_predictor return_prediction (rtx);
static rtx shift_return_value (rtx);
static void expand_value_return (rtx);
static void do_jump_if_equal (rtx, rtx, rtx, int);
static int estimate_case_costs (case_node_ptr);
static bool same_case_target_p (rtx, rtx);
*************** expand_computed_goto (tree exp)
*** 507,513 ****
void
expand_label (tree label)
{
- struct label_chain *p;
rtx label_r = label_rtx (label);
do_pending_stack_adjust ();
--- 451,456 ----
*************** expand_label (tree label)
*** 528,541 ****
if (DECL_NONLOCAL (label) || FORCED_LABEL (label))
maybe_set_first_label_num (label_r);
-
- if (stack_block_stack != 0)
- {
- p = ggc_alloc (sizeof (struct label_chain));
- p->next = stack_block_stack->data.block.label_chain;
- stack_block_stack->data.block.label_chain = p;
- p->label = label;
- }
}
/* Generate RTL code for a `goto' statement with target label LABEL.
--- 471,476 ----
*************** expand_goto (tree label)
*** 553,937 ****
abort ();
#endif
! expand_goto_internal (label, label_rtx (label), NULL_RTX);
! }
!
! /* Generate RTL code for a `goto' statement with target label BODY.
! LABEL should be a LABEL_REF.
! LAST_INSN, if non-0, is the rtx we should consider as the last
! insn emitted (for the purposes of cleaning up a return). */
!
! static void
! expand_goto_internal (tree body, rtx label, rtx last_insn)
! {
! struct nesting *block;
! rtx stack_level = 0;
!
! if (GET_CODE (label) != CODE_LABEL)
! abort ();
!
! /* If label has already been defined, we can tell now
! whether and how we must alter the stack level. */
!
! if (PREV_INSN (label) != 0)
! {
! /* Find the innermost pending block that contains the label.
! (Check containment by comparing insn-uids.)
! Then restore the outermost stack level within that block,
! and do cleanups of all blocks contained in it. */
! for (block = block_stack; block; block = block->next)
! {
! if (INSN_UID (block->data.block.first_insn) < INSN_UID (label))
! break;
! if (block->data.block.stack_level != 0)
! stack_level = block->data.block.stack_level;
! /* Execute the cleanups for blocks we are exiting. */
! if (block->data.block.cleanups != 0)
! {
! expand_cleanups (block->data.block.cleanups, 1, 1);
! do_pending_stack_adjust ();
! }
! }
!
! if (stack_level)
! {
! /* Ensure stack adjust isn't done by emit_jump, as this
! would clobber the stack pointer. This one should be
! deleted as dead by flow. */
! clear_pending_stack_adjust ();
! do_pending_stack_adjust ();
!
! /* Don't do this adjust if it's to the end label and this function
! is to return with a depressed stack pointer. */
! if (label == return_label
! && (((TREE_CODE (TREE_TYPE (current_function_decl))
! == FUNCTION_TYPE)
! && (TYPE_RETURNS_STACK_DEPRESSED
! (TREE_TYPE (current_function_decl))))))
! ;
! else
! emit_stack_restore (SAVE_BLOCK, stack_level, NULL_RTX);
! }
!
! if (body != 0 && DECL_TOO_LATE (body))
! error ("jump to `%s' invalidly jumps into binding contour",
! IDENTIFIER_POINTER (DECL_NAME (body)));
! }
! /* Label not yet defined: may need to put this goto
! on the fixup list. */
! else if (! expand_fixup (body, label, last_insn))
! {
! /* No fixup needed. Record that the label is the target
! of at least one goto that has no fixup. */
! if (body != 0)
! TREE_ADDRESSABLE (body) = 1;
! }
!
! emit_jump (label);
! }
!
! /* Generate if necessary a fixup for a goto
! whose target label in tree structure (if any) is TREE_LABEL
! and whose target in rtl is RTL_LABEL.
!
! If LAST_INSN is nonzero, we pretend that the jump appears
! after insn LAST_INSN instead of at the current point in the insn stream.
!
! The fixup will be used later to insert insns just before the goto.
! Those insns will restore the stack level as appropriate for the
! target label, and will (in the case of C++) also invoke any object
! destructors which have to be invoked when we exit the scopes which
! are exited by the goto.
!
! Value is nonzero if a fixup is made. */
!
! static int
! expand_fixup (tree tree_label, rtx rtl_label, rtx last_insn)
! {
! struct nesting *block, *end_block;
!
! /* See if we can recognize which block the label will be output in.
! This is possible in some very common cases.
! If we succeed, set END_BLOCK to that block.
! Otherwise, set it to 0. */
!
! if (cond_stack
! && (rtl_label == cond_stack->data.cond.endif_label
! || rtl_label == cond_stack->data.cond.next_label))
! end_block = cond_stack;
! else
! end_block = 0;
!
! /* Now set END_BLOCK to the binding level to which we will return. */
!
! if (end_block)
! {
! struct nesting *next_block = end_block->all;
! block = block_stack;
!
! /* First see if the END_BLOCK is inside the innermost binding level.
! If so, then no cleanups or stack levels are relevant. */
! while (next_block && next_block != block)
! next_block = next_block->all;
!
! if (next_block)
! return 0;
!
! /* Otherwise, set END_BLOCK to the innermost binding level
! which is outside the relevant control-structure nesting. */
! next_block = block_stack->next;
! for (block = block_stack; block != end_block; block = block->all)
! if (block == next_block)
! next_block = next_block->next;
! end_block = next_block;
! }
!
! /* Does any containing block have a stack level or cleanups?
! If not, no fixup is needed, and that is the normal case
! (the only case, for standard C). */
! for (block = block_stack; block != end_block; block = block->next)
! if (block->data.block.stack_level != 0
! || block->data.block.cleanups != 0)
! break;
!
! if (block != end_block)
! {
! /* Ok, a fixup is needed. Add a fixup to the list of such. */
! struct goto_fixup *fixup = ggc_alloc (sizeof (struct goto_fixup));
! /* In case an old stack level is restored, make sure that comes
! after any pending stack adjust. */
! /* ?? If the fixup isn't to come at the present position,
! doing the stack adjust here isn't useful. Doing it with our
! settings at that location isn't useful either. Let's hope
! someone does it! */
! if (last_insn == 0)
! do_pending_stack_adjust ();
! fixup->target = tree_label;
! fixup->target_rtl = rtl_label;
!
! /* Create a BLOCK node and a corresponding matched set of
! NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes at
! this point. The notes will encapsulate any and all fixup
! code which we might later insert at this point in the insn
! stream. Also, the BLOCK node will be the parent (i.e. the
! `SUPERBLOCK') of any other BLOCK nodes which we might create
! later on when we are expanding the fixup code.
!
! Note that optimization passes might move the *_BLOCK notes away,
! so we use a NOTE_INSN_DELETED as a placeholder. */
!
! {
! rtx original_before_jump
! = last_insn ? last_insn : get_last_insn ();
! rtx start;
! rtx end;
! tree block;
!
! block = make_node (BLOCK);
! TREE_USED (block) = 1;
!
! BLOCK_CHAIN (block)
! = BLOCK_CHAIN (DECL_INITIAL (current_function_decl));
! BLOCK_CHAIN (DECL_INITIAL (current_function_decl))
! = block;
!
! start_sequence ();
! start = emit_note (NOTE_INSN_BLOCK_BEG);
! NOTE_BLOCK (start) = block;
! fixup->before_jump = emit_note (NOTE_INSN_DELETED);
! end = emit_note (NOTE_INSN_BLOCK_END);
! NOTE_BLOCK (end) = block;
! fixup->context = block;
! end_sequence ();
! emit_insn_after (start, original_before_jump);
! }
!
! fixup->block_start_count = current_block_start_count;
! fixup->stack_level = 0;
! fixup->cleanup_list_list
! = ((block->data.block.outer_cleanups
! || block->data.block.cleanups)
! ? tree_cons (NULL_TREE, block->data.block.cleanups,
! block->data.block.outer_cleanups)
! : 0);
! fixup->next = goto_fixup_chain;
! goto_fixup_chain = fixup;
! }
!
! return block != 0;
! }
!
! /* Expand any needed fixups in the outputmost binding level of the
! function. FIRST_INSN is the first insn in the function. */
!
! void
! expand_fixups (rtx first_insn)
! {
! fixup_gotos (NULL, NULL_RTX, NULL_TREE, first_insn, 0);
! }
!
! /* When exiting a binding contour, process all pending gotos requiring fixups.
! THISBLOCK is the structure that describes the block being exited.
! STACK_LEVEL is the rtx for the stack level to restore exiting this contour.
! CLEANUP_LIST is a list of expressions to evaluate on exiting this contour.
! FIRST_INSN is the insn that began this contour.
!
! Gotos that jump out of this contour must restore the
! stack level and do the cleanups before actually jumping.
!
! DONT_JUMP_IN positive means report error if there is a jump into this
! contour from before the beginning of the contour. This is also done if
! STACK_LEVEL is nonzero unless DONT_JUMP_IN is negative. */
!
! static void
! fixup_gotos (struct nesting *thisblock, rtx stack_level,
! tree cleanup_list, rtx first_insn, int dont_jump_in)
! {
! struct goto_fixup *f, *prev;
!
! /* F is the fixup we are considering; PREV is the previous one. */
! /* We run this loop in two passes so that cleanups of exited blocks
! are run first, and blocks that are exited are marked so
! afterwards. */
!
! for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next)
! {
! /* Test for a fixup that is inactive because it is already handled. */
! if (f->before_jump == 0)
! {
! /* Delete inactive fixup from the chain, if that is easy to do. */
! if (prev != 0)
! prev->next = f->next;
! }
! /* Has this fixup's target label been defined?
! If so, we can finalize it. */
! else if (PREV_INSN (f->target_rtl) != 0)
! {
! rtx cleanup_insns;
!
! /* If this fixup jumped into this contour from before the beginning
! of this contour, report an error. This code used to use
! the first non-label insn after f->target_rtl, but that's
! wrong since such can be added, by things like put_var_into_stack
! and have INSN_UIDs that are out of the range of the block. */
! /* ??? Bug: this does not detect jumping in through intermediate
! blocks that have stack levels or cleanups.
! It detects only a problem with the innermost block
! around the label. */
! if (f->target != 0
! && (dont_jump_in > 0 || (dont_jump_in == 0 && stack_level)
! || cleanup_list)
! && INSN_UID (first_insn) < INSN_UID (f->target_rtl)
! && INSN_UID (first_insn) > INSN_UID (f->before_jump)
! && ! DECL_ERROR_ISSUED (f->target))
! {
! error ("%Jlabel '%D' used before containing binding contour",
! f->target, f->target);
! /* Prevent multiple errors for one label. */
! DECL_ERROR_ISSUED (f->target) = 1;
! }
!
! /* We will expand the cleanups into a sequence of their own and
! then later on we will attach this new sequence to the insn
! stream just ahead of the actual jump insn. */
!
! start_sequence ();
!
! /* Temporarily restore the lexical context where we will
! logically be inserting the fixup code. We do this for the
! sake of getting the debugging information right. */
!
! lang_hooks.decls.pushlevel (0);
! lang_hooks.decls.set_block (f->context);
!
! /* Expand the cleanups for blocks this jump exits. */
! if (f->cleanup_list_list)
! {
! tree lists;
! for (lists = f->cleanup_list_list; lists; lists = TREE_CHAIN (lists))
! /* Marked elements correspond to blocks that have been closed.
! Do their cleanups. */
! if (TREE_ADDRESSABLE (lists)
! && TREE_VALUE (lists) != 0)
! {
! expand_cleanups (TREE_VALUE (lists), 1, 1);
! /* Pop any pushes done in the cleanups,
! in case function is about to return. */
! do_pending_stack_adjust ();
! }
! }
!
! /* Restore stack level for the biggest contour that this
! jump jumps out of. */
! if (f->stack_level
! && ! (f->target_rtl == return_label
! && ((TREE_CODE (TREE_TYPE (current_function_decl))
! == FUNCTION_TYPE)
! && (TYPE_RETURNS_STACK_DEPRESSED
! (TREE_TYPE (current_function_decl))))))
! emit_stack_restore (SAVE_BLOCK, f->stack_level, f->before_jump);
!
! /* Finish up the sequence containing the insns which implement the
! necessary cleanups, and then attach that whole sequence to the
! insn stream just ahead of the actual jump insn. Attaching it
! at that point insures that any cleanups which are in fact
! implicit C++ object destructions (which must be executed upon
! leaving the block) appear (to the debugger) to be taking place
! in an area of the generated code where the object(s) being
! destructed are still "in scope". */
!
! cleanup_insns = get_insns ();
! lang_hooks.decls.poplevel (1, 0, 0);
!
! end_sequence ();
! emit_insn_after (cleanup_insns, f->before_jump);
!
! f->before_jump = 0;
! }
! }
!
! /* For any still-undefined labels, do the cleanups for this block now.
! We must do this now since items in the cleanup list may go out
! of scope when the block ends. */
! for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next)
! if (f->before_jump != 0
! && PREV_INSN (f->target_rtl) == 0
! /* Label has still not appeared. If we are exiting a block with
! a stack level to restore, that started before the fixup,
! mark this stack level as needing restoration
! when the fixup is later finalized. */
! && thisblock != 0
! /* Note: if THISBLOCK == 0 and we have a label that hasn't appeared, it
! means the label is undefined. That's erroneous, but possible. */
! && (thisblock->data.block.block_start_count
! <= f->block_start_count))
! {
! tree lists = f->cleanup_list_list;
! rtx cleanup_insns;
!
! for (; lists; lists = TREE_CHAIN (lists))
! /* If the following elt. corresponds to our containing block
! then the elt. must be for this block. */
! if (TREE_CHAIN (lists) == thisblock->data.block.outer_cleanups)
! {
! start_sequence ();
! lang_hooks.decls.pushlevel (0);
! lang_hooks.decls.set_block (f->context);
! expand_cleanups (TREE_VALUE (lists), 1, 1);
! do_pending_stack_adjust ();
! cleanup_insns = get_insns ();
! lang_hooks.decls.poplevel (1, 0, 0);
! end_sequence ();
! if (cleanup_insns != 0)
! f->before_jump
! = emit_insn_after (cleanup_insns, f->before_jump);
!
! f->cleanup_list_list = TREE_CHAIN (lists);
! }
!
! if (stack_level)
! f->stack_level = stack_level;
! }
}
/* Return the number of times character C occurs in string S. */
--- 488,494 ----
abort ();
#endif
! emit_jump (label_rtx (label));
}
/* Return the number of times character C occurs in string S. */
*************** preserve_subexpressions_p (void)
*** 2297,2312 ****
void
expand_null_return (void)
{
- rtx last_insn;
-
- last_insn = get_last_insn ();
-
/* If this function was declared to return a value, but we
didn't, clobber the return registers so that they are not
propagated live to the rest of the function. */
clobber_return_register ();
! expand_null_return_1 (last_insn);
}
/* Generate RTL to return directly from the current function.
--- 1854,1865 ----
void
expand_null_return (void)
{
/* If this function was declared to return a value, but we
didn't, clobber the return registers so that they are not
propagated live to the rest of the function. */
clobber_return_register ();
! expand_null_return_1 ();
}
/* Generate RTL to return directly from the current function.
*************** expand_null_return (void)
*** 2315,2331 ****
void
expand_naked_return (void)
{
! rtx last_insn, end_label;
!
! last_insn = get_last_insn ();
! end_label = naked_return_label;
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
if (end_label == 0)
end_label = naked_return_label = gen_label_rtx ();
! expand_goto_internal (NULL_TREE, end_label, last_insn);
}
/* Try to guess whether the value of return means error code. */
--- 1868,1883 ----
void
expand_naked_return (void)
{
! rtx end_label;
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
+ end_label = naked_return_label;
if (end_label == 0)
end_label = naked_return_label = gen_label_rtx ();
!
! emit_jump (end_label);
}
/* Try to guess whether the value of return means error code. */
*************** shift_return_value (rtx val)
*** 2389,2395 ****
static void
expand_value_return (rtx val)
{
- rtx last_insn;
rtx return_reg;
enum br_predictor pred;
--- 1941,1946 ----
*************** expand_value_return (rtx val)
*** 2405,2411 ****
}
- last_insn = get_last_insn ();
return_reg = DECL_RTL (DECL_RESULT (current_function_decl));
/* Copy the value to the return location
--- 1956,1961 ----
*************** expand_value_return (rtx val)
*** 2431,2453 ****
emit_move_insn (return_reg, val);
}
! expand_null_return_1 (last_insn);
}
! /* Output a return with no value. If LAST_INSN is nonzero,
! pretend that the return takes place after LAST_INSN. */
static void
! expand_null_return_1 (rtx last_insn)
{
! rtx end_label = return_label;
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
if (end_label == 0)
end_label = return_label = gen_label_rtx ();
! expand_goto_internal (NULL_TREE, end_label, last_insn);
}
/* Generate RTL to evaluate the expression RETVAL and return it
--- 1981,2003 ----
emit_move_insn (return_reg, val);
}
! expand_null_return_1 ();
}
! /* Output a return with no value. */
static void
! expand_null_return_1 (void)
{
! rtx end_label;
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
+ end_label = return_label;
if (end_label == 0)
end_label = return_label = gen_label_rtx ();
! emit_jump (end_label);
}
/* Generate RTL to evaluate the expression RETVAL and return it
*************** expand_null_return_1 (rtx last_insn)
*** 2456,2470 ****
void
expand_return (tree retval)
{
- /* If there are any cleanups to be performed, then they will
- be inserted following LAST_INSN. It is desirable
- that the last_insn, for such purposes, should be the
- last insn before computing the return value. Otherwise, cleanups
- which call functions can clobber the return value. */
- /* ??? rms: I think that is erroneous, because in C++ it would
- run destructors on variables that might be used in the subsequent
- computation of the return value. */
- rtx last_insn = 0;
rtx result_rtl;
rtx val = 0;
tree retval_rhs;
--- 2006,2011 ----
*************** expand_return (tree retval)
*** 2487,2500 ****
}
else if (TREE_CODE (retval) == RESULT_DECL)
retval_rhs = retval;
! else if ((TREE_CODE (retval) == MODIFY_EXPR || TREE_CODE (retval) == INIT_EXPR)
&& TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
retval_rhs = TREE_OPERAND (retval, 1);
else
retval_rhs = retval;
- last_insn = get_last_insn ();
-
result_rtl = DECL_RTL (DECL_RESULT (current_function_decl));
/* If the result is an aggregate that is being returned in one (or more)
--- 2028,2040 ----
}
else if (TREE_CODE (retval) == RESULT_DECL)
retval_rhs = retval;
! else if ((TREE_CODE (retval) == MODIFY_EXPR
! || TREE_CODE (retval) == INIT_EXPR)
&& TREE_CODE (TREE_OPERAND (retval, 0)) == RESULT_DECL)
retval_rhs = TREE_OPERAND (retval, 1);
else
retval_rhs = retval;
result_rtl = DECL_RTL (DECL_RESULT (current_function_decl));
/* If the result is an aggregate that is being returned in one (or more)
*************** expand_return (tree retval)
*** 2502,2509 ****
copying a BLKmode value into registers. We could put this code in a
more general area (for use by everyone instead of just function
call/return), but until this feature is generally usable it is kept here
! (and in expand_call). The value must go into a pseudo in case there
! are cleanups that will clobber the real return register. */
if (retval_rhs != 0
&& TYPE_MODE (TREE_TYPE (retval_rhs)) == BLKmode
--- 2042,2048 ----
copying a BLKmode value into registers. We could put this code in a
more general area (for use by everyone instead of just function
call/return), but until this feature is generally usable it is kept here
! (and in expand_call). */
if (retval_rhs != 0
&& TYPE_MODE (TREE_TYPE (retval_rhs)) == BLKmode
*************** expand_return (tree retval)
*** 2631,2643 ****
val = expand_expr (retval_rhs, val, GET_MODE (val), 0);
val = force_not_mem (val);
emit_queue ();
! /* Return the calculated value, doing cleanups first. */
expand_value_return (shift_return_value (val));
}
else
{
! /* No cleanups or no hard reg used;
! calculate value into hard return reg. */
expand_expr (retval, const0_rtx, VOIDmode, 0);
emit_queue ();
expand_value_return (result_rtl);
--- 2170,2181 ----
val = expand_expr (retval_rhs, val, GET_MODE (val), 0);
val = force_not_mem (val);
emit_queue ();
! /* Return the calculated value. */
expand_value_return (shift_return_value (val));
}
else
{
! /* No hard reg used; calculate value into hard return reg. */
expand_expr (retval, const0_rtx, VOIDmode, 0);
emit_queue ();
expand_value_return (result_rtl);
*************** expand_start_bindings_and_block (int fla
*** 2686,2694 ****
thisblock->next = block_stack;
thisblock->all = nesting_stack;
thisblock->depth = ++nesting_depth;
- thisblock->data.block.stack_level = 0;
- thisblock->data.block.cleanups = 0;
- thisblock->data.block.exception_region = 0;
thisblock->data.block.block_target_temp_slot_level = target_temp_slot_level;
thisblock->data.block.conditional_code = 0;
--- 2224,2229 ----
*************** expand_start_bindings_and_block (int fla
*** 2701,2716 ****
never the last instruction. */
emit_note (NOTE_INSN_DELETED);
- if (block_stack
- && !(block_stack->data.block.cleanups == NULL_TREE
- && block_stack->data.block.outer_cleanups == NULL_TREE))
- thisblock->data.block.outer_cleanups
- = tree_cons (NULL_TREE, block_stack->data.block.cleanups,
- block_stack->data.block.outer_cleanups);
- else
- thisblock->data.block.outer_cleanups = 0;
- thisblock->data.block.label_chain = 0;
- thisblock->data.block.innermost_stack_block = stack_block_stack;
thisblock->data.block.first_insn = note;
thisblock->data.block.block_start_count = ++current_block_start_count;
thisblock->exit_label = exit_flag ? gen_label_rtx () : 0;
--- 2236,2241 ----
*************** warn_about_unused_variables (tree vars)
*** 2906,2912 ****
void
expand_end_bindings (tree vars, int mark_ends ATTRIBUTE_UNUSED,
! int dont_jump_in)
{
struct nesting *thisblock = block_stack;
--- 2431,2437 ----
void
expand_end_bindings (tree vars, int mark_ends ATTRIBUTE_UNUSED,
! int dont_jump_in ATTRIBUTE_UNUSED)
{
struct nesting *thisblock = block_stack;
*************** expand_end_bindings (tree vars, int mark
*** 2920,2990 ****
emit_label (thisblock->exit_label);
}
! /* Don't allow jumping into a block that has a stack level.
! Cleanups are allowed, though. */
! if (dont_jump_in > 0
! || (dont_jump_in == 0 && thisblock->data.block.stack_level != 0))
! {
! struct label_chain *chain;
!
! /* Any labels in this block are no longer valid to go to.
! Mark them to cause an error message. */
! for (chain = thisblock->data.block.label_chain; chain; chain = chain->next)
! {
! DECL_TOO_LATE (chain->label) = 1;
! /* If any goto without a fixup came to this label,
! that must be an error, because gotos without fixups
! come from outside all saved stack-levels. */
! if (TREE_ADDRESSABLE (chain->label))
! error ("%Jlabel '%D' used before containing binding contour",
! chain->label, chain->label);
! }
! }
!
! /* Restore stack level in effect before the block
! (only if variable-size objects allocated). */
! /* Perform any cleanups associated with the block. */
!
! if (thisblock->data.block.stack_level != 0
! || thisblock->data.block.cleanups != 0)
! {
! int reachable;
! rtx insn;
!
! /* Only clean up here if this point can actually be reached. */
! insn = get_last_insn ();
! if (GET_CODE (insn) == NOTE)
! insn = prev_nonnote_insn (insn);
! reachable = (! insn || GET_CODE (insn) != BARRIER);
!
! /* Do the cleanups. */
! expand_cleanups (thisblock->data.block.cleanups, 0, reachable);
! if (reachable)
! do_pending_stack_adjust ();
!
! /* Restore the stack level. */
!
! if (reachable && thisblock->data.block.stack_level != 0)
! {
! emit_stack_restore (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION,
! thisblock->data.block.stack_level, NULL_RTX);
! if (cfun->nonlocal_goto_save_area)
! update_nonlocal_goto_save_area ();
! }
!
! /* Any gotos out of this block must also do these things.
! Also report any gotos with fixups that came to labels in this
! level. */
! fixup_gotos (thisblock,
! thisblock->data.block.stack_level,
! thisblock->data.block.cleanups,
! thisblock->data.block.first_insn,
! dont_jump_in);
! }
!
! /* Mark the beginning and end of the scope if requested.
! We do this now, after running cleanups on the variables
! just going out of scope, so they are in scope for their cleanups. */
/* Get rid of the beginning-mark if we don't make an end-mark. */
NOTE_LINE_NUMBER (thisblock->data.block.first_insn) = NOTE_INSN_DELETED;
--- 2445,2451 ----
emit_label (thisblock->exit_label);
}
! /* Mark the beginning and end of the scope if requested. */
/* Get rid of the beginning-mark if we don't make an end-mark. */
NOTE_LINE_NUMBER (thisblock->data.block.first_insn) = NOTE_INSN_DELETED;
*************** expand_end_bindings (tree vars, int mark
*** 2994,3023 ****
/* Restore block_stack level for containing block. */
- stack_block_stack = thisblock->data.block.innermost_stack_block;
POPSTACK (block_stack);
/* Pop the stack slot nesting and free any slots at this level. */
pop_temp_slots ();
}
- /* Generate code to save the stack pointer at the start of the current block
- and set up to restore it on exit. */
-
- void
- save_stack_pointer (void)
- {
- struct nesting *thisblock = block_stack;
-
- if (thisblock->data.block.stack_level == 0)
- {
- emit_stack_save (thisblock->next ? SAVE_BLOCK : SAVE_FUNCTION,
- &thisblock->data.block.stack_level,
- thisblock->data.block.first_insn);
- stack_block_stack = thisblock;
- }
- }
-
/* Generate RTL for the automatic variable declaration DECL.
(Other kinds of declarations are simply ignored if seen here.) */
--- 2455,2466 ----
*************** expand_decl (tree decl)
*** 3143,3149 ****
/* Record the stack pointer on entry to block, if have
not already done so. */
do_pending_stack_adjust ();
- save_stack_pointer ();
/* Compute the variable's size, in bytes. This will expand any
needed SAVE_EXPRs for the first time. */
--- 2586,2591 ----
*************** expand_decl_init (tree decl)
*** 3270,3402 ****
pop_temp_slots ();
}
- /* CLEANUP is an expression to be executed at exit from this binding contour;
- for example, in C++, it might call the destructor for this variable.
-
- We wrap CLEANUP in an UNSAVE_EXPR node, so that we can expand the
- CLEANUP multiple times, and have the correct semantics. This
- happens in exception handling, for gotos, returns, breaks that
- leave the current scope.
-
- If CLEANUP is nonzero and DECL is zero, we record a cleanup
- that is not associated with any particular variable. */
-
- int
- expand_decl_cleanup (tree decl, tree cleanup)
- {
- struct nesting *thisblock;
-
- /* Error if we are not in any block. */
- if (cfun == 0 || block_stack == 0)
- return 0;
-
- thisblock = block_stack;
-
- /* Record the cleanup if there is one. */
-
- if (cleanup != 0)
- {
- tree t;
- rtx seq;
- tree *cleanups = &thisblock->data.block.cleanups;
- int cond_context = conditional_context ();
-
- if (cond_context)
- {
- rtx flag = gen_reg_rtx (word_mode);
- rtx set_flag_0;
- tree cond;
-
- start_sequence ();
- emit_move_insn (flag, const0_rtx);
- set_flag_0 = get_insns ();
- end_sequence ();
-
- thisblock->data.block.last_unconditional_cleanup
- = emit_insn_after (set_flag_0,
- thisblock->data.block.last_unconditional_cleanup);
-
- emit_move_insn (flag, const1_rtx);
-
- cond = build_decl (VAR_DECL, NULL_TREE,
- lang_hooks.types.type_for_mode (word_mode, 1));
- SET_DECL_RTL (cond, flag);
-
- /* Conditionalize the cleanup. */
- cleanup = build (COND_EXPR, void_type_node,
- lang_hooks.truthvalue_conversion (cond),
- cleanup, integer_zero_node);
- cleanup = fold (cleanup);
-
- cleanups = &thisblock->data.block.cleanups;
- }
-
- cleanup = unsave_expr (cleanup);
-
- t = *cleanups = tree_cons (decl, cleanup, *cleanups);
-
- if (! cond_context)
- /* If this block has a cleanup, it belongs in stack_block_stack. */
- stack_block_stack = thisblock;
-
- if (cond_context)
- {
- start_sequence ();
- }
-
- if (! using_eh_for_cleanups_p)
- TREE_ADDRESSABLE (t) = 1;
- else
- expand_eh_region_start ();
-
- if (cond_context)
- {
- seq = get_insns ();
- end_sequence ();
- if (seq)
- thisblock->data.block.last_unconditional_cleanup
- = emit_insn_after (seq,
- thisblock->data.block.last_unconditional_cleanup);
- }
- else
- {
- thisblock->data.block.last_unconditional_cleanup
- = get_last_insn ();
- /* When we insert instructions after the last unconditional cleanup,
- we don't adjust last_insn. That means that a later add_insn will
- clobber the instructions we've just added. The easiest way to
- fix this is to just insert another instruction here, so that the
- instructions inserted after the last unconditional cleanup are
- never the last instruction. */
- emit_note (NOTE_INSN_DELETED);
- }
- }
- return 1;
- }
-
- /* Like expand_decl_cleanup, but maybe only run the cleanup if an exception
- is thrown. */
-
- int
- expand_decl_cleanup_eh (tree decl, tree cleanup, int eh_only)
- {
- int ret = expand_decl_cleanup (decl, cleanup);
- if (cleanup && ret)
- {
- tree node = block_stack->data.block.cleanups;
- CLEANUP_EH_ONLY (node) = eh_only;
- }
- return ret;
- }
/* DECL is an anonymous union. CLEANUP is a cleanup for DECL.
DECL_ELTS is the list of elements that belong to DECL's type.
In each, the TREE_VALUE is a VAR_DECL, and the TREE_PURPOSE a cleanup. */
void
! expand_anon_union_decl (tree decl, tree cleanup, tree decl_elts)
{
- struct nesting *thisblock = cfun == 0 ? 0 : block_stack;
rtx x;
tree t;
--- 2712,2726 ----
pop_temp_slots ();
}
/* DECL is an anonymous union. CLEANUP is a cleanup for DECL.
DECL_ELTS is the list of elements that belong to DECL's type.
In each, the TREE_VALUE is a VAR_DECL, and the TREE_PURPOSE a cleanup. */
void
! expand_anon_union_decl (tree decl, tree cleanup ATTRIBUTE_UNUSED,
! tree decl_elts)
{
rtx x;
tree t;
*************** expand_anon_union_decl (tree decl, tree
*** 3409,3422 ****
}
expand_decl (decl);
- expand_decl_cleanup (decl, cleanup);
x = DECL_RTL (decl);
/* Go through the elements, assigning RTL to each. */
for (t = decl_elts; t; t = TREE_CHAIN (t))
{
tree decl_elt = TREE_VALUE (t);
- tree cleanup_elt = TREE_PURPOSE (t);
enum machine_mode mode = TYPE_MODE (TREE_TYPE (decl_elt));
/* If any of the elements are addressable, so is the entire
--- 2733,2744 ----
*************** expand_anon_union_decl (tree decl, tree
*** 3453,3597 ****
}
else
abort ();
-
- /* Record the cleanup if there is one. */
-
- if (cleanup != 0)
- thisblock->data.block.cleanups
- = tree_cons (decl_elt, cleanup_elt,
- thisblock->data.block.cleanups);
}
}
- /* Expand a list of cleanups LIST.
- Elements may be expressions or may be nested lists.
-
- If IN_FIXUP is nonzero, we are generating this cleanup for a fixup
- goto and handle protection regions specially in that case.
-
- If REACHABLE, we emit code, otherwise just inform the exception handling
- code about this finalization. */
-
- static void
- expand_cleanups (tree list, int in_fixup, int reachable)
- {
- tree tail;
- for (tail = list; tail; tail = TREE_CHAIN (tail))
- if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
- expand_cleanups (TREE_VALUE (tail), in_fixup, reachable);
- else
- {
- if (! in_fixup && using_eh_for_cleanups_p)
- expand_eh_region_end_cleanup (TREE_VALUE (tail));
-
- if (reachable && !CLEANUP_EH_ONLY (tail))
- {
- /* Cleanups may be run multiple times. For example,
- when exiting a binding contour, we expand the
- cleanups associated with that contour. When a goto
- within that binding contour has a target outside that
- contour, it will expand all cleanups from its scope to
- 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 from outer cleanups. */
- if (in_fixup && using_eh_for_cleanups_p)
- {
- expand_eh_region_start ();
-
- expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
-
- expand_eh_region_end_fixup (TREE_VALUE (tail));
- }
- else
- expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
-
- free_temp_slots ();
- }
- }
- }
-
- /* Mark when the context we are emitting RTL for as a conditional
- context, so that any cleanup actions we register with
- expand_decl_init will be properly conditionalized when those
- cleanup actions are later performed. Must be called before any
- expression (tree) is expanded that is within a conditional context. */
-
- void
- start_cleanup_deferral (void)
- {
- /* block_stack can be NULL if we are inside the parameter list. It is
- OK to do nothing, because cleanups aren't possible here. */
- if (block_stack)
- ++block_stack->data.block.conditional_code;
- }
-
- /* Mark the end of a conditional region of code. Because cleanup
- deferrals may be nested, we may still be in a conditional region
- after we end the currently deferred cleanups, only after we end all
- deferred cleanups, are we back in unconditional code. */
-
- void
- end_cleanup_deferral (void)
- {
- /* block_stack can be NULL if we are inside the parameter list. It is
- OK to do nothing, because cleanups aren't possible here. */
- if (block_stack)
- --block_stack->data.block.conditional_code;
- }
-
- tree
- last_cleanup_this_contour (void)
- {
- if (block_stack == 0)
- return 0;
-
- return block_stack->data.block.cleanups;
- }
-
-
- /* Return nonzero if any containing block has a stack level or
- cleanups. */
-
- int
- containing_blocks_have_cleanups_or_stack_level (void)
- {
- struct nesting *block;
-
- for (block = block_stack; block; block = block->next)
- if (block->data.block.stack_level != 0
- || block->data.block.cleanups != 0)
- return 1;
-
- return 0;
- }
-
- /* Return 1 if there are any pending cleanups at this point.
- Check the current contour as well as contours that enclose
- the current contour. */
-
- int
- any_pending_cleanups (void)
- {
- struct nesting *block;
-
- if (cfun == NULL || cfun->stmt == NULL || block_stack == 0)
- return 0;
-
- if (block_stack->data.block.cleanups != NULL)
- return 1;
-
- if (block_stack->data.block.outer_cleanups == 0)
- return 0;
-
- for (block = block_stack->next; block; block = block->next)
- if (block->data.block.cleanups != 0)
- return 1;
-
- return 0;
- }
-
/* Enter a case (Pascal) or switch (C) statement.
Push a block onto case_stack and nesting_stack
to accumulate the case-labels that are seen
--- 2775,2783 ----
*************** expand_start_case (int exit_flag, tree e
*** 3635,3642 ****
emit_note (NOTE_INSN_DELETED);
thiscase->data.case_stmt.start = get_last_insn ();
-
- start_cleanup_deferral ();
}
/* Accumulate one case or default label inside a case or switch statement.
--- 2821,2826 ----
*************** expand_start_case (int exit_flag, tree e
*** 3649,3655 ****
If VALUE is a duplicate or overlaps, return 2 and do nothing
except store the (first) duplicate node in *DUPLICATE.
If VALUE is out of range, return 3 and do nothing.
- If we are jumping into the scope of a cleanup or var-sized array, return 5.
Return 0 on success.
Extended to handle range statements. */
--- 2833,2838 ----
*************** pushcase (tree value, tree (*converter)
*** 3665,3674 ****
if (! (case_stack && case_stack->data.case_stmt.start))
return 1;
- if (stack_block_stack
- && stack_block_stack->depth > case_stack->depth)
- return 5;
-
index_type = TREE_TYPE (case_stack->data.case_stmt.index_expr);
nominal_type = case_stack->data.case_stmt.nominal_type;
--- 2848,2853 ----
*************** pushcase_range (tree value1, tree value2
*** 3710,3719 ****
if (! (case_stack && case_stack->data.case_stmt.start))
return 1;
- if (stack_block_stack
- && stack_block_stack->depth > case_stack->depth)
- return 5;
-
index_type = TREE_TYPE (case_stack->data.case_stmt.index_expr);
nominal_type = case_stack->data.case_stmt.nominal_type;
--- 2889,2894 ----
*************** expand_end_case_type (tree orig_index, t
*** 4268,4275 ****
if (count != 0)
range = fold (build (MINUS_EXPR, index_type, maxval, minval));
- end_cleanup_deferral ();
-
if (count == 0)
{
expand_expr (index_expr, const0_rtx, VOIDmode, 0);
--- 3443,3448 ----
*************** expand_end_case_type (tree orig_index, t
*** 4482,4489 ****
reorder_insns (before_case, end,
thiscase->data.case_stmt.start);
}
- else
- end_cleanup_deferral ();
if (thiscase->exit_label && !exit_done)
emit_label (thiscase->exit_label);
--- 3655,3660 ----
Index: gcc/tree-pretty-print.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-pretty-print.c,v
retrieving revision 2.21
diff -c -p -d -r2.21 tree-pretty-print.c
*** gcc/tree-pretty-print.c 7 Jul 2004 21:26:30 -0000 2.21
--- gcc/tree-pretty-print.c 8 Jul 2004 07:19:34 -0000
*************** dump_generic_node (pretty_printer *buffe
*** 1185,1194 ****
is_expr = false;
break;
- case GOTO_SUBROUTINE_EXPR:
- NIY;
- break;
-
case LABEL_EXPR:
op0 = TREE_OPERAND (node, 0);
/* If this is for break or continue, don't bother printing it. */
--- 1185,1190 ----
Index: gcc/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.390
diff -c -p -d -r1.390 tree.c
*** gcc/tree.c 8 Jul 2004 03:40:29 -0000 1.390
--- gcc/tree.c 8 Jul 2004 07:19:34 -0000
*************** first_rtl_op (enum tree_code code)
*** 1493,1502 ****
{
switch (code)
{
- case GOTO_SUBROUTINE_EXPR:
- return 0;
- case WITH_CLEANUP_EXPR:
- return 2;
default:
return TREE_CODE_LENGTH (code);
}
--- 1493,1498 ----
*************** has_cleanups (tree exp)
*** 1850,1856 ****
switch (TREE_CODE (exp))
{
case TARGET_EXPR:
- case GOTO_SUBROUTINE_EXPR:
case WITH_CLEANUP_EXPR:
return 1;
--- 1846,1851 ----
Index: gcc/tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.91
diff -c -p -d -r1.91 tree.def
*** gcc/tree.def 7 Jul 2004 21:26:30 -0000 1.91
--- gcc/tree.def 8 Jul 2004 07:19:34 -0000
*************** DEFTREECODE (LABELED_BLOCK_EXPR, "labele
*** 494,509 ****
DEFTREECODE (CALL_EXPR, "call_expr", 'e', 3)
/* Specify a value to compute along with its corresponding cleanup.
! Operand 0 argument is an expression whose value needs a cleanup.
! Operand 1 is the cleanup expression for the object.
! Operand 2 is unused.
! The cleanup is executed by the first enclosing CLEANUP_POINT_EXPR, if
! it exists, otherwise it is the responsibility of the caller to manually
! call expand_start_target_temps/expand_end_target_temps, as needed.
!
! This differs from TRY_CATCH_EXPR in that operand 2 is always
! evaluated when an exception isn't thrown when cleanups are run. */
! DEFTREECODE (WITH_CLEANUP_EXPR, "with_cleanup_expr", 'e', 3)
/* Specify a cleanup point.
Operand 0 is an expression that may have cleanups. If it does, those
--- 494,504 ----
DEFTREECODE (CALL_EXPR, "call_expr", 'e', 3)
/* Specify a value to compute along with its corresponding cleanup.
! Operand 0 is the cleanup expression.
! The cleanup is executed by the first enclosing CLEANUP_POINT_EXPR,
! which must exist. This differs from TRY_CATCH_EXPR in that operand 1
! is always evaluated when cleanups are run. */
! DEFTREECODE (WITH_CLEANUP_EXPR, "with_cleanup_expr", 'e', 1)
/* Specify a cleanup point.
Operand 0 is an expression that may have cleanups. If it does, those
*************** DEFTREECODE (LABEL_EXPR, "label_expr", '
*** 790,802 ****
The type should be void and the value should be ignored. */
DEFTREECODE (GOTO_EXPR, "goto_expr", 's', 1)
- /* Used internally for cleanups in the implementation of TRY_FINALLY_EXPR.
- (Specifically, it is created by expand_expr, not front-ends.)
- Operand 0 is the rtx for the start of the subroutine we need to call.
- Operand 1 is the rtx for a variable in which to store the address
- of where the subroutine should return to. */
- DEFTREECODE (GOTO_SUBROUTINE_EXPR, "goto_subroutine", 's', 2)
-
/* RETURN. Evaluates operand 0, then returns from the current function.
Presumably that operand is an assignment that stores into the
RESULT_DECL that hold the value to be returned.
--- 785,790 ----
Index: gcc/tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.545
diff -c -p -d -r1.545 tree.h
*** gcc/tree.h 7 Jul 2004 22:03:43 -0000 1.545
--- gcc/tree.h 8 Jul 2004 07:19:34 -0000
*************** struct tree_vec GTY(())
*** 1025,1034 ****
&& VOID_TYPE_P (TREE_TYPE (NODE)) \
&& integer_zerop (TREE_OPERAND (NODE, 0)))
- /* In a WITH_CLEANUP_EXPR node. */
- #define WITH_CLEANUP_EXPR_RTL(NODE) \
- TREE_RTL_OPERAND_CHECK (NODE, WITH_CLEANUP_EXPR, 2)
-
/* In a CONSTRUCTOR node. */
#define CONSTRUCTOR_ELTS(NODE) TREE_OPERAND_CHECK_CODE (NODE, CONSTRUCTOR, 0)
--- 1025,1030 ----
*************** extern GTY (()) unsigned binfo_lang_slot
*** 2013,2022 ****
specially. */
#define DECL_BIT_FIELD(NODE) (FIELD_DECL_CHECK (NODE)->decl.bit_field_flag)
- /* In a LABEL_DECL, nonzero means label was defined inside a binding
- contour that restored a stack level and which is now exited. */
- #define DECL_TOO_LATE(NODE) (LABEL_DECL_CHECK (NODE)->decl.bit_field_flag)
-
/* Unused in FUNCTION_DECL. */
/* In a VAR_DECL that's static,
--- 2009,2014 ----
*************** extern bool commutative_tree_code (enum
*** 3333,3339 ****
/* In stmt.c */
- extern void expand_fixups (rtx);
extern void expand_expr_stmt (tree);
extern void expand_expr_stmt_value (tree, int, int);
extern int warn_if_unused_value (tree, location_t);
--- 3325,3330 ----
*************** extern void expand_start_bindings_and_bl
*** 3355,3367 ****
expand_start_bindings_and_block(flags, NULL_TREE)
extern void expand_end_bindings (tree, int, int);
extern void warn_about_unused_variables (tree);
- extern void start_cleanup_deferral (void);
- extern void end_cleanup_deferral (void);
extern int is_body_block (tree);
extern int conditional_context (void);
extern struct nesting * current_nesting_level (void);
- extern tree last_cleanup_this_contour (void);
extern void expand_start_case (int, tree, tree, const char *);
extern void expand_end_case_type (tree, tree);
#define expand_end_case(cond) expand_end_case_type (cond, NULL)
--- 3346,3355 ----
*************** extern void expand_asm_operands (tree, t
*** 3613,3629 ****
extern void expand_asm_expr (tree);
extern bool asm_op_is_mem_input (tree, tree);
extern tree resolve_asm_operand_names (tree, tree, tree);
- extern int any_pending_cleanups (void);
extern void init_stmt_for_function (void);
extern void expand_start_target_temps (void);
extern void expand_end_target_temps (void);
extern void expand_elseif (tree);
- extern void save_stack_pointer (void);
extern void expand_decl (tree);
- extern int expand_decl_cleanup (tree, tree);
- extern int expand_decl_cleanup_eh (tree, tree, int);
extern void expand_anon_union_decl (tree, tree, tree);
- extern int containing_blocks_have_cleanups_or_stack_level (void);
/* In gimplify.c. */
extern tree create_artificial_label (void);
--- 3601,3612 ----
Index: gcc/ada/trans.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/ada/trans.c,v
retrieving revision 1.66
diff -c -p -d -r1.66 trans.c
*** gcc/ada/trans.c 2 Jul 2004 01:15:35 -0000 1.66
--- gcc/ada/trans.c 8 Jul 2004 07:19:35 -0000
*************** gnat_to_gnu (Node_Id gnat_node)
*** 3236,3255 ****
case N_Handled_Sequence_Of_Statements:
/* The GCC exception handling mechanism can handle both ZCX and SJLJ
! schemes and we have our own SJLJ mechanism. To call the GCC
! mechanism, we first call expand_eh_region_start if there is at least
! one handler associated with the region. We then generate code for
! the region and call expand_start_all_catch to announce that the
! associated handlers are going to be generated.
!
! For each handler we call expand_start_catch, generate code for the
! handler, and then call expand_end_catch.
!
! After all the handlers, we call expand_end_all_catch.
!
! Here we deal with the region level calls and the
! N_Exception_Handler branch deals with the handler level calls
! (start_catch/end_catch).
??? The region level calls down there have been specifically put in
place for a ZCX context and currently the order in which things are
--- 3236,3244 ----
case N_Handled_Sequence_Of_Statements:
/* The GCC exception handling mechanism can handle both ZCX and SJLJ
! schemes and we have our own SJLJ mechanism. To call the GCC
! mechanism, we call add_cleanup, and when we leave the binding,
! end_stmt_group will create the TRY_FINALLY_EXPR.
??? The region level calls down there have been specifically put in
place for a ZCX context and currently the order in which things are
Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.998
diff -c -p -d -r1.998 cp-tree.h
*** gcc/cp/cp-tree.h 8 Jul 2004 04:32:27 -0000 1.998
--- gcc/cp/cp-tree.h 8 Jul 2004 07:19:35 -0000
*************** extern void init_exception_processing (
*** 3833,3839 ****
extern tree expand_start_catch_block (tree);
extern void expand_end_catch_block (void);
extern void expand_builtin_throw (void);
- extern void expand_eh_spec_block (tree);
extern void expand_exception_blocks (void);
extern tree build_exc_ptr (void);
extern tree build_throw (tree);
--- 3833,3838 ----
Index: gcc/java/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/expr.c,v
retrieving revision 1.196
diff -c -p -d -r1.196 expr.c
*** gcc/java/expr.c 7 Jul 2004 10:20:59 -0000 1.196
--- gcc/java/expr.c 8 Jul 2004 07:19:35 -0000
*************** static void java_push_constant_from_pool
*** 85,93 ****
static void java_stack_pop (int);
static tree build_java_throw_out_of_bounds_exception (tree);
static tree build_java_check_indexed_type (tree, tree);
- static tree case_identity (tree, tree);
static unsigned char peek_opcode_at_pc (struct JCF *, int, int);
- static int emit_init_test_initialization (void **entry, void * ptr);
static GTY(()) tree operand_type[59];
--- 85,91 ----
*************** load_type_state (tree label)
*** 2455,2695 ****
type_map [i] = TREE_VEC_ELT (vec, i);
}
- /* Do the expansion of a Java switch. With Gcc, switches are front-end
- dependent things, but they rely on gcc routines. This function is
- placed here because it uses things defined locally in parse.y. */
-
- static tree
- case_identity (tree t __attribute__ ((__unused__)), tree v)
- {
- return v;
- }
-
- /* Return the name of the vtable for an array of a given primitive
- type. */
- static tree
- get_primitive_array_vtable (tree elt)
- {
- tree r;
- if (elt == boolean_type_node)
- r = boolean_array_vtable;
- else if (elt == byte_type_node)
- r = byte_array_vtable;
- else if (elt == char_type_node)
- r = char_array_vtable;
- else if (elt == short_type_node)
- r = short_array_vtable;
- else if (elt == int_type_node)
- r = int_array_vtable;
- else if (elt == long_type_node)
- r = long_array_vtable;
- else if (elt == float_type_node)
- r = float_array_vtable;
- else if (elt == double_type_node)
- r = double_array_vtable;
- else
- abort ();
- return build_address_of (r);
- }
-
- struct rtx_def *
- java_expand_expr (tree exp, rtx target, enum machine_mode tmode,
- int modifier /* Actually an enum expand_modifier. */,
- rtx *alt_rtl ATTRIBUTE_UNUSED)
- {
- tree current;
-
- abort ();
-
- switch (TREE_CODE (exp))
- {
-
- case EXPR_WITH_FILE_LOCATION:
- {
- rtx to_return;
- const char *saved_input_filename = input_filename;
- int saved_lineno = input_line;
- input_filename = EXPR_WFL_FILENAME (exp);
- input_line = EXPR_WFL_LINENO (exp);
- if (EXPR_WFL_EMIT_LINE_NOTE (exp))
- emit_line_note (input_location);
- /* Possibly avoid switching back and forth here. */
- to_return = expand_expr (EXPR_WFL_NODE (exp), target, tmode, modifier);
- input_filename = saved_input_filename;
- input_line = saved_lineno;
- return to_return;
- }
-
- case NEW_ARRAY_INIT:
- {
- rtx tmp;
- tree array_type = TREE_TYPE (TREE_TYPE (exp));
- tree element_type = TYPE_ARRAY_ELEMENT (array_type);
- tree data_fld = TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (array_type)));
- HOST_WIDE_INT ilength = java_array_type_length (array_type);
- tree length = build_int_2 (ilength, 0);
- tree init = TREE_OPERAND (exp, 0);
- tree array_decl;
-
- /* See if we can generate the array statically. */
- if (TREE_CONSTANT (init) && TREE_STATIC (exp)
- && JPRIMITIVE_TYPE_P (element_type))
- {
- tree temp, value, init_decl;
- struct rtx_def *r;
- START_RECORD_CONSTRUCTOR (temp, object_type_node);
- PUSH_FIELD_VALUE (temp, "vtable",
- get_primitive_array_vtable (element_type));
- if (! flag_hash_synchronization)
- PUSH_FIELD_VALUE (temp, "sync_info", null_pointer_node);
- FINISH_RECORD_CONSTRUCTOR (temp);
- START_RECORD_CONSTRUCTOR (value, array_type);
- PUSH_SUPER_VALUE (value, temp);
- PUSH_FIELD_VALUE (value, "length", length);
- PUSH_FIELD_VALUE (value, "data", init);
- FINISH_RECORD_CONSTRUCTOR (value);
-
- init_decl = build_decl (VAR_DECL, generate_name (), array_type);
- pushdecl_top_level (init_decl);
- TREE_STATIC (init_decl) = 1;
- DECL_INITIAL (init_decl) = value;
- DECL_IGNORED_P (init_decl) = 1;
- TREE_READONLY (init_decl) = 1;
- /* Hash synchronization requires at least 64-bit alignment. */
- if (flag_hash_synchronization && POINTER_SIZE < 64)
- DECL_ALIGN (init_decl) = 64;
- rest_of_decl_compilation (init_decl, NULL, 1, 0);
- TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (init_decl)) = 1;
- init = build1 (ADDR_EXPR, TREE_TYPE (exp), init_decl);
- r = expand_expr (init, target, tmode, modifier);
- return r;
- }
-
- array_decl = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp));
- expand_decl (array_decl);
- tmp = expand_assignment (array_decl,
- build_new_array (element_type, length),
- 1);
- if (TREE_CONSTANT (init)
- && ilength >= 10 && JPRIMITIVE_TYPE_P (element_type))
- {
- tree init_decl;
- init_decl = build_decl (VAR_DECL, generate_name (),
- TREE_TYPE (init));
- pushdecl_top_level (init_decl);
- TREE_STATIC (init_decl) = 1;
- DECL_INITIAL (init_decl) = init;
- DECL_IGNORED_P (init_decl) = 1;
- TREE_READONLY (init_decl) = 1;
- rest_of_decl_compilation (init_decl, NULL, 1, 0);
- TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (init_decl)) = 1;
- init = init_decl;
- }
- expand_assignment (build (COMPONENT_REF, TREE_TYPE (data_fld),
- build_java_indirect_ref (array_type,
- array_decl, flag_check_references),
- data_fld, NULL_TREE),
- init, 0);
- return tmp;
- }
- case BLOCK:
- if (BLOCK_EXPR_BODY (exp))
- {
- tree local;
- rtx last;
- tree body = BLOCK_EXPR_BODY (exp);
- /* Set to 1 or more when we found a static class
- initialization flag. */
- int found_class_initialization_flag = 0;
-
- pushlevel (2); /* 2 and above */
- expand_start_bindings (0);
- local = BLOCK_EXPR_DECLS (exp);
- while (local)
- {
- tree next = TREE_CHAIN (local);
- found_class_initialization_flag +=
- LOCAL_CLASS_INITIALIZATION_FLAG_P (local);
- layout_decl (local, 0);
- expand_decl (pushdecl (local));
- local = next;
- }
-
- /* Emit initialization code for test flags if we saw one. */
- if (! always_initialize_class_p
- && current_function_decl
- && found_class_initialization_flag)
- htab_traverse
- (DECL_FUNCTION_INIT_TEST_TABLE (current_function_decl),
- emit_init_test_initialization, NULL);
-
- /* Avoid deep recursion for long block. */
- while (TREE_CODE (body) == COMPOUND_EXPR)
- {
- expand_expr (TREE_OPERAND (body, 0), const0_rtx, VOIDmode, 0);
- emit_queue ();
- body = TREE_OPERAND (body, 1);
- }
- last = expand_expr (body, NULL_RTX, VOIDmode, 0);
- emit_queue ();
- expand_end_bindings (getdecls (), 1, 0);
- poplevel (1, 1, 0);
- return last;
- }
- return const0_rtx;
-
- case CASE_EXPR:
- {
- tree duplicate;
- if (pushcase (TREE_OPERAND (exp, 0), case_identity,
- build_decl (LABEL_DECL, NULL_TREE, NULL_TREE),
- &duplicate) == 2)
- {
- EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (exp);
- parse_error_context
- (wfl_operator, "Duplicate case label: `%s'",
- print_int_node (TREE_OPERAND (exp, 0)));
- }
- return const0_rtx;
- }
-
- case DEFAULT_EXPR:
- pushcase (NULL_TREE, 0,
- build_decl (LABEL_DECL, NULL_TREE, NULL_TREE), NULL);
- return const0_rtx;
-
- case TRY_EXPR:
- /* We expand a try[-catch] block */
-
- /* Expand the try block */
- expand_eh_region_start ();
- expand_expr_stmt (TREE_OPERAND (exp, 0));
- expand_start_all_catch ();
-
- /* Expand all catch clauses (EH handlers) */
- for (current = TREE_OPERAND (exp, 1); current;
- current = TREE_CHAIN (current))
- {
- tree catch = TREE_OPERAND (current, 0);
- tree decl = BLOCK_EXPR_DECLS (catch);
- tree type = (decl ? TREE_TYPE (TREE_TYPE (decl)) : NULL_TREE);
-
- expand_start_catch (prepare_eh_table_type (type));
- expand_expr_stmt (TREE_OPERAND (current, 0));
- expand_end_catch ();
- }
- expand_end_all_catch ();
- return const0_rtx;
-
- case JAVA_EXC_OBJ_EXPR:
- return expand_expr (build_exception_object_ref (TREE_TYPE (exp)),
- target, tmode, modifier);
-
- default:
- internal_error ("can't expand %s", tree_code_name [TREE_CODE (exp)]);
- }
- }
-
/* Go over METHOD's bytecode and note instruction starts in
instruction_bits[]. */
--- 2453,2458 ----
*************** force_evaluation_order (tree node)
*** 3448,3486 ****
return node;
}
- /* Called for every element in DECL_FUNCTION_INIT_TEST_TABLE of a
- method in order to emit initialization code for each test flag. */
-
- static int
- emit_init_test_initialization (void **entry, void *x ATTRIBUTE_UNUSED)
- {
- struct treetreehash_entry *ite = (struct treetreehash_entry *) *entry;
- tree klass = build_class_ref (ite->key);
- tree rhs;
-
- /* If the DECL_INITIAL of the test flag is set to true, it
- means that the class is already initialized the time it
- is in use. */
- if (DECL_INITIAL (ite->value) == boolean_true_node)
- rhs = boolean_true_node;
- /* Otherwise, we initialize the class init check variable by looking
- at the `state' field of the class to see if it is already
- initialized. This makes things a bit faster if the class is
- already initialized, which should be the common case. */
- else
- rhs = build (GE_EXPR, boolean_type_node,
- build (COMPONENT_REF, byte_type_node,
- build1 (INDIRECT_REF, class_type_node, klass),
- lookup_field (&class_type_node,
- get_identifier ("state")),
- NULL_TREE),
- build_int_2 (JV_STATE_DONE, 0));
-
- expand_expr_stmt (build (MODIFY_EXPR, boolean_type_node,
- ite->value, rhs));
- return true;
- }
-
/* EXPR_WITH_FILE_LOCATION are used to keep track of the exact
location where an expression or an identifier were encountered. It
is necessary for languages where the frontend parser will handle
--- 3211,3216 ----
Index: gcc/java/java-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/java-tree.h,v
retrieving revision 1.207
diff -c -p -d -r1.207 java-tree.h
*** gcc/java/java-tree.h 7 Jul 2004 10:21:00 -0000 1.207
--- gcc/java/java-tree.h 8 Jul 2004 07:19:35 -0000
*************** extern tree decl_constant_value (tree);
*** 1333,1341 ****
extern void java_mark_class_local (tree);
- #if defined(RTX_CODE) && defined (HAVE_MACHINE_MODES)
- struct rtx_def * java_expand_expr (tree, rtx, enum machine_mode, int, rtx *);
- #endif
extern void java_inlining_merge_static_initializers (tree, void *);
extern void java_inlining_map_static_initializers (tree, void *);
--- 1333,1338 ----
Index: gcc/java/lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/java/lang.c,v
retrieving revision 1.153
diff -c -p -d -r1.153 lang.c
*** gcc/java/lang.c 27 Jun 2004 18:16:48 -0000 1.153
--- gcc/java/lang.c 8 Jul 2004 07:19:35 -0000
*************** struct language_function GTY(())
*** 224,231 ****
#define LANG_HOOKS_UNSAFE_FOR_REEVAL java_unsafe_for_reeval
#undef LANG_HOOKS_MARK_ADDRESSABLE
#define LANG_HOOKS_MARK_ADDRESSABLE java_mark_addressable
- #undef LANG_HOOKS_EXPAND_EXPR
- #define LANG_HOOKS_EXPAND_EXPR java_expand_expr
#undef LANG_HOOKS_TRUTHVALUE_CONVERSION
#define LANG_HOOKS_TRUTHVALUE_CONVERSION java_truthvalue_conversion
#undef LANG_HOOKS_DUP_LANG_SPECIFIC_DECL
--- 224,229 ----