aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <merrill@gnu.org>1996-08-12 05:52:13 +0000
committerJason Merrill <merrill@gnu.org>1996-08-12 05:52:13 +0000
commita3a58acc2732e38715f70e5190bd56178beb0b0e (patch)
tree04da7b424421837c34218102bff222a3633c0413
parent5c0bf7476e6547500e2492ef67be94589078cb67 (diff)
downloadgcc-a3a58acc2732e38715f70e5190bd56178beb0b0e.zip
gcc-a3a58acc2732e38715f70e5190bd56178beb0b0e.tar.gz
gcc-a3a58acc2732e38715f70e5190bd56178beb0b0e.tar.bz2
(store_expr): Handle COND_EXPR cleanups like expand_expr.
From-SVN: r12620
-rw-r--r--gcc/expr.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index 7a12b9e..7905fa9 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -3056,6 +3056,17 @@ store_expr (exp, target, want_value)
For non-BLKmode, it is more efficient not to do this. */
rtx lab1 = gen_label_rtx (), lab2 = gen_label_rtx ();
+ rtx flag = NULL_RTX;
+ tree left_cleanups = NULL_TREE;
+ tree right_cleanups = NULL_TREE;
+ tree old_cleanups = cleanups_this_call;
+
+ /* 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;
emit_queue ();
target = protect_from_queue (target, 1);
@@ -3064,14 +3075,74 @@ store_expr (exp, target, want_value)
NO_DEFER_POP;
jumpifnot (TREE_OPERAND (exp, 0), lab1);
store_expr (TREE_OPERAND (exp, 1), target, 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 (lab2));
emit_barrier ();
emit_label (lab1);
store_expr (TREE_OPERAND (exp, 2), target, 0);
+ dest_right_flag = get_last_insn ();
+ /* Handle conditional cleanups, if any. */
+ right_cleanups = defer_cleanups_to (old_cleanups);
emit_queue ();
emit_label (lab2);
OK_DEFER_POP;
+
+ /* 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. */
+
+ flag = gen_reg_rtx (word_mode);
+
+ /* 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);
+
+ /* All cleanups must be on the function_obstack. */
+ push_obstacks_nochange ();
+ resume_temporary_allocation ();
+
+ /* 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;
+ cond = save_expr (cond);
+
+ if (! left_cleanups)
+ left_cleanups = integer_zero_node;
+ if (! right_cleanups)
+ right_cleanups = integer_zero_node;
+ new_cleanups = build (COND_EXPR, void_type_node,
+ truthvalue_conversion (cond),
+ left_cleanups, right_cleanups);
+ new_cleanups = fold (new_cleanups);
+
+ pop_obstacks ();
+
+ /* Now add in the conditionalized cleanups. */
+ cleanups_this_call
+ = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
+ expand_eh_region_start ();
+ }
return want_value ? target : NULL_RTX;
}
else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target)
@@ -6444,6 +6515,8 @@ expand_expr (exp, target, tmode, modifier)
&& ! (GET_CODE (original_target) == MEM
&& MEM_VOLATILE_P (original_target)))
temp = original_target;
+ else if (TREE_ADDRESSABLE (type))
+ abort ();
else
temp = assign_temp (type, 0, 0, 1);