- if (try_tail_call || try_tail_recursion)
- {
- int end, inc;
- actparms = NULL_TREE;
- /* Ok, we're going to give the tail call the old college try.
- This means we're going to evaluate the function arguments
- up to three times. There are two degrees of badness we can
- encounter, those that can be unsaved and those that can't.
- (See unsafe_for_reeval commentary for details.)
-
- Generate a new argument list. Pass safe arguments through
- unchanged. For the easy badness wrap them in UNSAVE_EXPRs.
- For hard badness, evaluate them now and put their resulting
- rtx in a temporary VAR_DECL.
-
- initialize_argument_information has ordered the array for the
- order to be pushed, and we must remember this when reconstructing
- the original argument order. */
-
- if (PUSH_ARGS_REVERSED)
- {
- inc = 1;
- i = 0;
- end = num_actuals;
- }
- else
- {
- inc = -1;
- i = num_actuals - 1;
- end = -1;
- }
-
- for (; i != end; i += inc)
- {
- args[i].tree_value = fix_unsafe_tree (args[i].tree_value);
- /* We need to build actparms for optimize_tail_recursion. We can
- safely trash away TREE_PURPOSE, since it is unused by this
- function. */
- if (try_tail_recursion)
- actparms = tree_cons (NULL_TREE, args[i].tree_value, actparms);
- }
- /* 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 = try_tail_recursion = 0;
- }
-
- /* Generate a tail recursion sequence when calling ourselves. */
-
- if (try_tail_recursion)
- {
- /* We want to emit any pending stack adjustments before the tail
- recursion "call". That way we know any adjustment after the tail
- recursion call can be ignored if we indeed use the tail recursion
- call expansion. */
- int save_pending_stack_adjust = pending_stack_adjust;
- int save_stack_pointer_delta = stack_pointer_delta;
-
- /* Emit any queued insns now; otherwise they would end up in
- only one of the alternates. */
- emit_queue ();
-
- /* Use a new sequence to hold any RTL we generate. We do not even
- know if we will use this RTL yet. The final decision can not be
- made until after RTL generation for the entire function is
- complete. */
- start_sequence ();
- /* If expanding any of the arguments creates cleanups, we can't
- do a tailcall. So, we'll need to pop the pending cleanups
- list. If, however, all goes well, and there are no cleanups
- then the call to expand_start_target_temps will have no
- effect. */
- expand_start_target_temps ();
- if (optimize_tail_recursion (actparms, get_last_insn ()))
- {
- if (any_pending_cleanups ())
- try_tail_call = try_tail_recursion = 0;
- else
- tail_recursion_insns = get_insns ();
- }
- expand_end_target_temps ();
- end_sequence ();
-
- /* Restore the original pending stack adjustment for the sibling and
- normal call cases below. */
- pending_stack_adjust = save_pending_stack_adjust;
- stack_pointer_delta = save_stack_pointer_delta;
- }
-
- if (profile_arc_flag && (flags & ECF_FORK_OR_EXEC))
- {
- /* A fork duplicates the profile information, and an exec discards
- it. We can't rely on fork/exec to be paired. So write out the
- profile information we have gathered so far, and clear it. */
- /* ??? When Linux's __clone is called with CLONE_VM set, profiling
- is subject to race conditions, just as with multithreaded
- programs. */
-
- emit_library_call (gcov_flush_libfunc, LCT_ALWAYS_RETURN, VOIDmode, 0);
- }
-