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++;