summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/expr.c16
-rw-r--r--gcc/expr.h6
-rw-r--r--gcc/function.c20
3 files changed, 36 insertions, 6 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index b9cd009f7af..256f46faf08 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -95,6 +95,12 @@ int inhibit_defer_pop;
function calls being expanded by expand_call. */
tree cleanups_this_call;
+/* When temporaries are created by TARGET_EXPRs, they are created at
+ this level of temp_slot_level, so that they can remain allocated
+ until no longer needed. CLEANUP_POINT_EXPRs define the lifetime
+ of TARGET_EXPRs. */
+int target_temp_slot_level;
+
/* Nonzero means __builtin_saveregs has already been done in this function.
The value is the pseudoreg containing the value __builtin_saveregs
returned. */
@@ -4623,9 +4629,17 @@ expand_expr (exp, target, tmode, modifier)
case CLEANUP_POINT_EXPR:
{
+ extern int temp_slot_level;
tree old_cleanups = cleanups_this_call;
+ int old_temp_level = target_temp_slot_level;
+ push_temp_slots ();
+ target_temp_slot_level = temp_slot_level;
op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, modifier);
expand_cleanups_to (old_cleanups);
+ preserve_temp_slots (op0);
+ free_temp_slots ();
+ pop_temp_slots ();
+ target_temp_slot_level = old_temp_level;
}
return op0;
@@ -5695,7 +5709,7 @@ expand_expr (exp, target, tmode, modifier)
}
else
{
- target = assign_stack_temp (mode, int_size_in_bytes (type), 0);
+ target = assign_stack_temp (mode, int_size_in_bytes (type), 2);
/* All temp slots at this level must not conflict. */
preserve_temp_slots (target);
DECL_RTL (slot) = target;
diff --git a/gcc/expr.h b/gcc/expr.h
index 3b3ce5d2a8a..3bb94907e1e 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -119,6 +119,12 @@ extern int pending_stack_adjust;
#ifdef TREE_CODE /* Don't lose if tree.h not included. */
extern tree cleanups_this_call;
#endif
+
+/* When temporaries are created by TARGET_EXPRs, they are created at
+ this level of temp_slot_level, so that they can remain allocated
+ until no longer needed. CLEANUP_POINT_EXPRs define the lifetime
+ of TARGET_EXPRs. */
+extern int target_temp_slot_level;
#ifdef TREE_CODE /* Don't lose if tree.h not included. */
/* Structure to record the size of a sequence of arguments
diff --git a/gcc/function.c b/gcc/function.c
index 4b9e33cd33b..16d4a935b83 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -771,9 +771,10 @@ assign_outer_stack_local (mode, size, align, function)
SIZE is the size in units of the space required. We do no rounding here
since assign_stack_local will do any required rounding.
- KEEP is non-zero if this slot is to be retained after a call to
- free_temp_slots. Automatic variables for a block are allocated with this
- flag. */
+ KEEP is 1 if this slot is to be retained after a call to
+ free_temp_slots. Automatic variables for a block are allocated
+ with this flag. KEEP is 2, if we allocate a longer term temporary,
+ whose lifetime is controlled by CLEANUP_POINT_EXPRs. */
rtx
assign_stack_temp (mode, size, keep)
@@ -845,8 +846,16 @@ assign_stack_temp (mode, size, keep)
p->in_use = 1;
p->rtl_expr = sequence_rtl_expr;
- p->level = temp_slot_level;
- p->keep = keep;
+ if (keep == 2)
+ {
+ p->level = target_temp_slot_level;
+ p->keep = 0;
+ }
+ else
+ {
+ p->level = temp_slot_level;
+ p->keep = keep;
+ }
return p->slot;
}
@@ -4615,6 +4624,7 @@ init_function_start (subr, filename, line)
/* We have not allocated any temporaries yet. */
temp_slots = 0;
temp_slot_level = 0;
+ target_temp_slot_level = 0;
/* Within function body, compute a type's size as soon it is laid out. */
immediate_size_expand++;