From 5dab5552a1f1e1a025b47ff2732e1ddaa6febae0 Mon Sep 17 00:00:00 2001 From: Mike Stump Date: Fri, 13 May 1994 00:19:57 +0000 Subject: [PATCH] calls.c (expand_call): Only destroy temporaries at the end of function calls, if flag_short_temps is set. * calls.c (expand_call): Only destroy temporaries at the end of function calls, if flag_short_temps is set. * expr.c (safe_from_p, expand_expr): Handle CLEANUP_POINT_EXPRs. * expr.c (expand_expr): Improve handling of temporaries inside COND_EXPRs, cures call to sorry. * expr.c (defer_cleanups_to): New routine to handle the deferral of cleanups. * flags.h (flag_short_temps): New flag, to allow better control over the lifetime of temporaries. * toplev.c (flag_short_temps, lang_options): Ditto. * tree.def (CLEANUP_POINT_EXPR): Add, to allow better control over the lifetime of temporaries. From-SVN: r7289 --- gcc/calls.c | 9 ++- gcc/emit-rtl.c | 4 +- gcc/expr.c | 152 +++++++++++++++++++++++++++++++++++++++++++------ gcc/flags.h | 4 ++ gcc/toplev.c | 6 ++ gcc/tree.def | 10 +++- 6 files changed, 162 insertions(+), 23 deletions(-) diff --git a/gcc/calls.c b/gcc/calls.c index 99c8a602bbb..cc6a74a5668 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1995,9 +1995,12 @@ expand_call (exp, target, ignore) } #endif - /* Perform all cleanups needed for the arguments of this call - (i.e. destructors in C++). */ - expand_cleanups_to (old_cleanups); + if (flag_short_temps) + { + /* Perform all cleanups needed for the arguments of this call + (i.e. destructors in C++). */ + expand_cleanups_to (old_cleanups); + } /* If size of args is variable or this was a constructor call for a stack argument, restore saved stack-pointer value. */ diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 607dc8ae353..55ee134f07b 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -2176,7 +2176,9 @@ delete_insns_since (from) last_insn = from; } -/* Move a consecutive bunch of insns to a different place in the chain. +/* This function is deprecated, please use sequences instead. + + Move a consecutive bunch of insns to a different place in the chain. The insns to be moved are those between FROM and TO. They are moved to a new position after the insn AFTER. AFTER must not be FROM or TO or any insn in between. diff --git a/gcc/expr.c b/gcc/expr.c index 244a84c57ee..38789ffecc9 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -179,6 +179,7 @@ static void do_jump_by_parts_equality_rtx PROTO((rtx, rtx, rtx)); static void do_jump_for_compare PROTO((rtx, rtx, rtx)); static rtx compare PROTO((tree, enum rtx_code, enum rtx_code)); static rtx do_store_flag PROTO((tree, rtx, enum machine_mode, int)); +static tree defer_cleanups_to PROTO((tree)); /* Record for each mode whether we can move a register directly to or from an object of that mode in memory. If we can't, we won't try @@ -3535,6 +3536,9 @@ safe_from_p (x, exp) exp_rtl = RTL_EXPR_RTL (exp); break; + case CLEANUP_POINT_EXPR: + return safe_from_p (x, TREE_OPERAND (exp, 0)); + case SAVE_EXPR: exp_rtl = SAVE_EXPR_RTL (exp); break; @@ -4609,6 +4613,14 @@ expand_expr (exp, target, tmode, modifier) } return RTL_EXPR_RTL (exp); + case CLEANUP_POINT_EXPR: + { + tree old_cleanups = cleanups_this_call; + op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, modifier); + expand_cleanups_to (old_cleanups); + } + return op0; + case CALL_EXPR: /* Check for a built-in function. */ if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR @@ -5295,6 +5307,17 @@ expand_expr (exp, target, tmode, modifier) case COND_EXPR: { + rtx flag = NULL_RTX; + tree left_cleanups = NULL_TREE; + tree right_cleanups = NULL_TREE; + + /* Used to save a pointer to the place to put the setting of + the flag that indicates if this side of the conditional was + taken. We backpatch the code, if we find out later that we + have any conditional cleanups that need to be performed. */ + rtx dest_right_flag = NULL_RTX; + rtx dest_left_flag = NULL_RTX; + /* Note that COND_EXPRs whose type is a structure or union are required to be constructed to contain assignments of a temporary variable, so that we can evaluate them here @@ -5306,7 +5329,6 @@ expand_expr (exp, target, tmode, modifier) tree singleton = 0; tree binary_op = 0, unary_op = 0; tree old_cleanups = cleanups_this_call; - cleanups_this_call = 0; /* If this is (A ? 1 : 0) and A is a condition, just evaluate it and convert it to our mode, if necessary. */ @@ -5430,6 +5452,7 @@ expand_expr (exp, target, tmode, modifier) NO_DEFER_POP; op0 = gen_label_rtx (); + flag = gen_reg_rtx (word_mode); if (singleton && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))) { if (temp != 0) @@ -5448,16 +5471,14 @@ expand_expr (exp, target, tmode, modifier) else expand_expr (singleton, ignore ? const0_rtx : NULL_RTX, VOIDmode, 0); - if (cleanups_this_call) - { - sorry ("aggregate value in COND_EXPR"); - cleanups_this_call = 0; - } + dest_left_flag = get_last_insn (); if (singleton == TREE_OPERAND (exp, 1)) jumpif (TREE_OPERAND (exp, 0), op0); else jumpifnot (TREE_OPERAND (exp, 0), op0); + /* Allows cleanups up to here. */ + old_cleanups = cleanups_this_call; if (binary_op && temp == 0) /* Just touch the other operand. */ expand_expr (TREE_OPERAND (binary_op, 1), @@ -5472,6 +5493,7 @@ expand_expr (exp, target, tmode, modifier) make_tree (type, temp)), temp, 0); op1 = op0; + dest_right_flag = get_last_insn (); } #if 0 /* This is now done in jump.c and is better done there because it @@ -5498,9 +5520,14 @@ expand_expr (exp, target, tmode, modifier) if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER) temp = gen_reg_rtx (mode); store_expr (TREE_OPERAND (exp, 2), temp, 0); + dest_left_flag = get_last_insn (); jumpifnot (TREE_OPERAND (exp, 0), op0); + + /* Allows cleanups up to here. */ + old_cleanups = cleanups_this_call; store_expr (TREE_OPERAND (exp, 1), temp, 0); op1 = op0; + dest_right_flag = get_last_insn (); } #endif /* Check for A op 0 ? A : FOO and A op 0 ? FOO : A where OP is any @@ -5518,9 +5545,14 @@ expand_expr (exp, target, tmode, modifier) if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER) temp = gen_reg_rtx (mode); store_expr (TREE_OPERAND (exp, 1), temp, 0); + dest_left_flag = get_last_insn (); jumpif (TREE_OPERAND (exp, 0), op0); + + /* Allows cleanups up to here. */ + old_cleanups = cleanups_this_call; store_expr (TREE_OPERAND (exp, 2), temp, 0); op1 = op0; + dest_right_flag = get_last_insn (); } else if (temp && TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<' @@ -5533,24 +5565,31 @@ expand_expr (exp, target, tmode, modifier) if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER) temp = gen_reg_rtx (mode); store_expr (TREE_OPERAND (exp, 2), temp, 0); + dest_left_flag = get_last_insn (); jumpifnot (TREE_OPERAND (exp, 0), op0); + + /* Allows cleanups up to here. */ + old_cleanups = cleanups_this_call; store_expr (TREE_OPERAND (exp, 1), temp, 0); op1 = op0; + dest_right_flag = get_last_insn (); } else { op1 = gen_label_rtx (); jumpifnot (TREE_OPERAND (exp, 0), op0); + + /* Allows cleanups up to here. */ + old_cleanups = cleanups_this_call; if (temp != 0) store_expr (TREE_OPERAND (exp, 1), temp, 0); else expand_expr (TREE_OPERAND (exp, 1), ignore ? const0_rtx : NULL_RTX, VOIDmode, 0); - if (cleanups_this_call) - { - sorry ("aggregate value in COND_EXPR"); - cleanups_this_call = 0; - } + dest_left_flag = get_last_insn (); + + /* Handle conditional cleanups, if any. */ + left_cleanups = defer_cleanups_to (old_cleanups); emit_queue (); emit_jump_insn (gen_jump (op1)); @@ -5561,18 +5600,58 @@ expand_expr (exp, target, tmode, modifier) else expand_expr (TREE_OPERAND (exp, 2), ignore ? const0_rtx : NULL_RTX, VOIDmode, 0); + dest_right_flag = get_last_insn (); } - if (cleanups_this_call) - { - sorry ("aggregate value in COND_EXPR"); - cleanups_this_call = 0; - } + /* Handle conditional cleanups, if any. */ + right_cleanups = defer_cleanups_to (old_cleanups); emit_queue (); emit_label (op1); OK_DEFER_POP; - cleanups_this_call = old_cleanups; + + /* Add back in, any conditional cleanups. */ + if (left_cleanups || right_cleanups) + { + tree new_cleanups; + tree cond; + rtx last; + + /* Now that we know that a flag is needed, go back and add in the + setting of the flag. */ + + /* Do the left side flag. */ + last = get_last_insn (); + /* Flag left cleanups as needed. */ + emit_move_insn (flag, const1_rtx); + /* ??? deprecated, use sequences instead. */ + reorder_insns (NEXT_INSN (last), get_last_insn (), dest_left_flag); + + /* Do the right side flag. */ + last = get_last_insn (); + /* Flag left cleanups as needed. */ + emit_move_insn (flag, const0_rtx); + /* ??? deprecated, use sequences instead. */ + reorder_insns (NEXT_INSN (last), get_last_insn (), dest_right_flag); + + /* convert flag, which is an rtx, into a tree. */ + cond = make_node (RTL_EXPR); + TREE_TYPE (cond) = integer_type_node; + RTL_EXPR_RTL (cond) = flag; + RTL_EXPR_SEQUENCE (cond) = NULL_RTX; + + if (! left_cleanups) + left_cleanups = integer_zero_node; + if (! right_cleanups) + right_cleanups = integer_zero_node; + new_cleanups = build (COND_EXPR, void_type_node, cond, + left_cleanups, right_cleanups); + new_cleanups = fold (new_cleanups); + + /* Now add in the conditionalized cleanups. */ + cleanups_this_call + = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call); + } return temp; } @@ -8170,6 +8249,45 @@ do_pending_stack_adjust () } } +/* Defer the expansion all cleanups up to OLD_CLEANUPS. + Returns the cleanups to be performed. */ + +static tree +defer_cleanups_to (old_cleanups) + tree old_cleanups; +{ + tree new_cleanups = NULL_TREE; + tree cleanups = cleanups_this_call; + tree last = NULL_TREE; + + while (cleanups_this_call != old_cleanups) + { + cleanups_this_call = TREE_CHAIN (cleanups_this_call); + } + + if (last) + { + /* Remove the list from the chain of cleanups. */ + TREE_CHAIN (last) = NULL_TREE; + + /* reverse them so that we can build them in the right order. */ + cleanups = nreverse (cleanups); + + while (cleanups) + { + if (new_cleanups) + new_cleanups = build (COMPOUND_EXPR, TREE_TYPE (new_cleanups), + TREE_VALUE (cleanups), new_cleanups); + else + new_cleanups = TREE_VALUE (cleanups); + + cleanups = TREE_CHAIN (cleanups); + } + } + + return new_cleanups; +} + /* Expand all cleanups up to OLD_CLEANUPS. Needed here, and also for language-dependent calls. */ diff --git a/gcc/flags.h b/gcc/flags.h index 128b27f15ec..07ea73490ee 100644 --- a/gcc/flags.h +++ b/gcc/flags.h @@ -294,6 +294,10 @@ extern int flag_schedule_insns_after_reload; extern int flag_delayed_branch; +/* Nonzero means to run cleanups after CALL_EXPRs. */ + +extern int flag_short_temps; + /* Nonzero means pretend it is OK to examine bits of target floats, even if that isn't true. The resulting code will have incorrect constants, but the same series of instructions that the native compiler would make. */ diff --git a/gcc/toplev.c b/gcc/toplev.c index 96a01adb386..ec0baa4abdd 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -448,6 +448,10 @@ int flag_shared_data; int flag_delayed_branch; +/* Nonzero means to run cleanups after CALL_EXPRs. */ + +int flag_short_temps; + /* Nonzero if we are compiling pure (sharable) code. Value is 1 if we are doing reasonable (i.e. simple offset into offset table) pic. Value is 2 if we can @@ -666,6 +670,8 @@ char *lang_options[] = "-fno-nonnull-objects", "-fsave-memoized", "-fno-save-memoized", + "-fshort-temps", + "-fno-short-temps", "-fstats", "-fno-stats", "-fstrict-prototype", diff --git a/gcc/tree.def b/gcc/tree.def index 7eb9a2e0951..71d638640eb 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -436,10 +436,16 @@ DEFTREECODE (METHOD_CALL_EXPR, "method_call_expr", "e", 4) Operand 2 is the cleanup expression for the object. The RTL_EXPR is used in this expression, which is how the expression manages to act on the proper value. - The cleanup is executed when the value is no longer needed, - which is not at precisely the same time that this value is computed. */ + 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_cleanups_to, as needed. */ DEFTREECODE (WITH_CLEANUP_EXPR, "with_cleanup_expr", "e", 3) +/* Specify a cleanup point. + Operand 0 is the expression that has cleanups that we want ensure are + cleaned up. */ +DEFTREECODE (CLEANUP_POINT_EXPR, "cleanup_point_expr", "e", 1) + /* The following two codes are used in languages that have types where the position and/or sizes of fields vary from object to object of the same type, i.e., where some other field in the object contains a value -- 2.30.2