static int check_sibcall_argument_overlap (rtx, struct arg_data *, int);
static int combine_pending_stack_adjustment_and_call (int, struct args_size *,
- int);
-static tree fix_unsafe_tree (tree);
+ unsigned int);
static bool shift_returned_value (tree, rtx *);
#ifdef REG_PARM_STACK_SPACE
prepare_call_address (rtx funexp, rtx static_chain_value,
rtx *call_fusage, int reg_parm_seen, int sibcallp)
{
- funexp = protect_from_queue (funexp, 0);
-
/* Make a valid memory address and copy constants through pseudo-regs,
but not for a constant address if -fno-function-cse. */
if (GET_CODE (funexp) != SYMBOL_REF)
hacky imitation of DECL_ASSEMBLER_NAME. It's (also) wrong
because you can declare fork() inside a function if you
wish. */
- && (DECL_CONTEXT (fndecl) == NULL_TREE
+ && (DECL_CONTEXT (fndecl) == NULL_TREE
|| TREE_CODE (DECL_CONTEXT (fndecl)) == TRANSLATION_UNIT_DECL)
&& TREE_PUBLIC (fndecl))
{
VOIDmode, 0);
preserve_temp_slots (args[i].value);
pop_temp_slots ();
-
- /* ANSI doesn't require a sequence point here,
- but PCC has one, so this will avoid some problems. */
- emit_queue ();
}
/* If the value is a non-legitimate constant, force it into a
&& args[i].mode != BLKmode
&& rtx_cost (args[i].value, SET) > COSTS_N_INSNS (1)
&& ((SMALL_REGISTER_CLASSES && *reg_parm_seen)
- || preserve_subexpressions_p ()))
+ || optimize))
args[i].value = copy_to_mode_reg (args[i].mode, args[i].value);
}
}
and may be modified by this routine.
OLD_PENDING_ADJ, MUST_PREALLOCATE and FLAGS are pointers to integer
- flags which may may be modified by this routine.
+ flags which may may be modified by this routine.
MAY_TAILCALL is cleared if we encounter an invisible pass-by-reference
that requires allocation of stack space.
get extraneous instructions emitted as part of the libcall sequence. */
if ((flags & ECF_LIBCALL_BLOCK) == 0)
return;
-
+
for (i = 0; i < num_actuals; i++)
{
enum machine_mode mode;
if (TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)))
abort ();
- args[i].value
- = expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0);
-
- /* ANSI doesn't require a sequence point here,
- but PCC has one, so this will avoid some problems. */
- emit_queue ();
-
args[i].initial_value = args[i].value
- = protect_from_queue (args[i].value, 0);
+ = expand_expr (args[i].tree_value, NULL_RTX, VOIDmode, 0);
mode = TYPE_MODE (TREE_TYPE (args[i].tree_value));
if (mode != args[i].mode)
push_temp_slots ();
funexp = expand_expr (addr, NULL_RTX, VOIDmode, 0);
pop_temp_slots (); /* FUNEXP can't be BLKmode. */
- emit_queue ();
}
return funexp;
}
seem worth generating rtl to say that. */
reg = gen_rtx_REG (word_mode, REGNO (reg));
x = expand_shift (LSHIFT_EXPR, word_mode, reg,
- build_int_2 (shift, 0), reg, 1);
+ build_int_cst (NULL_TREE, shift),
+ reg, 1);
if (x != reg)
emit_move_insn (reg, x);
}
emit_move_insn (x, tem);
x = expand_shift (dir, word_mode, x,
- build_int_2 (shift, 0), ri, 1);
+ build_int_cst (NULL_TREE, shift),
+ ri, 1);
if (x != ri)
emit_move_insn (ri, x);
}
static int
combine_pending_stack_adjustment_and_call (int unadjusted_args_size,
struct args_size *args_size,
- int preferred_unit_stack_boundary)
+ unsigned int preferred_unit_stack_boundary)
{
/* The number of bytes to pop so that the stack will be
under-aligned by UNADJUSTED_ARGS_SIZE bytes. */
HOST_WIDE_INT adjustment;
/* The alignment of the stack after the arguments are pushed, if we
just pushed the arguments without adjust the stack here. */
- HOST_WIDE_INT unadjusted_alignment;
+ unsigned HOST_WIDE_INT unadjusted_alignment;
unadjusted_alignment
= ((stack_pointer_delta + unadjusted_args_size)
return insn != NULL_RTX;
}
-static tree
-fix_unsafe_tree (tree t)
-{
- switch (unsafe_for_reeval (t))
- {
- case 0: /* Safe. */
- break;
-
- case 1: /* Mildly unsafe. */
- t = unsave_expr (t);
- break;
-
- case 2: /* Wildly unsafe. */
- {
- tree var = build_decl (VAR_DECL, NULL_TREE,
- TREE_TYPE (t));
- SET_DECL_RTL (var,
- expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL));
- t = var;
- }
- break;
-
- default:
- abort ();
- }
- return t;
-}
-
-
/* If function value *VALUE was returned at the most significant end of a
register, shift it towards the least significant end and convert it to
TYPE's mode. Return true and update *VALUE if some action was needed.
}
}
-/* Clear RTX_UNCHANGING_P flag of incoming argument MEMs. */
-
-static void
-purge_mem_unchanging_flag (rtx x)
-{
- RTX_CODE code;
- int i, j;
- const char *fmt;
-
- if (x == NULL_RTX)
- return;
-
- code = GET_CODE (x);
-
- if (code == MEM)
- {
- if (RTX_UNCHANGING_P (x)
- && (XEXP (x, 0) == current_function_internal_arg_pointer
- || (GET_CODE (XEXP (x, 0)) == PLUS
- && XEXP (XEXP (x, 0), 0) ==
- current_function_internal_arg_pointer
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
- RTX_UNCHANGING_P (x) = 0;
- return;
- }
-
- /* Scan all subexpressions. */
- fmt = GET_RTX_FORMAT (code);
- for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
- {
- if (*fmt == 'e')
- purge_mem_unchanging_flag (XEXP (x, i));
- else if (*fmt == 'E')
- for (j = 0; j < XVECLEN (x, i); j++)
- purge_mem_unchanging_flag (XVECEXP (x, i, j));
- }
-}
-
-
/* Generate all the code for a function call
and return an rtx for its value.
Store the value in TARGET (specified as an rtx) if convenient.
tree addr = TREE_OPERAND (exp, 0);
int i;
/* The alignment of the stack, in bits. */
- HOST_WIDE_INT preferred_stack_boundary;
+ unsigned HOST_WIDE_INT preferred_stack_boundary;
/* The alignment of the stack, in bytes. */
- HOST_WIDE_INT preferred_unit_stack_boundary;
+ unsigned HOST_WIDE_INT preferred_unit_stack_boundary;
/* The static chain value to use for this call. */
rtx static_chain_value;
/* See if this is "nothrow" function call. */
|| (ACCUMULATE_OUTGOING_ARGS
&& stack_arg_under_construction
&& structure_value_addr == virtual_outgoing_args_rtx)
- ? copy_addr_to_reg (convert_memory_address
+ ? copy_addr_to_reg (convert_memory_address
(Pmode, structure_value_addr))
: structure_value_addr);
|| (!ACCUMULATE_OUTGOING_ARGS && args_size.constant)))
structure_value_addr = copy_to_reg (structure_value_addr);
- /* Tail calls can make things harder to debug, and we're traditionally
+ /* Tail calls can make things harder to debug, and we've traditionally
pushed these optimizations into -O2. Don't try if we're already
expanding a call, as that means we're an argument. Don't try if
- there's cleanups, as we know there's code to follow the call.
+ there's cleanups, as we know there's code to follow the call. */
- If rtx_equal_function_value_matters is false, that means we've
- finished with regular parsing. Which means that some of the
- machinery we use to generate tail-calls is no longer in place.
- This is most often true of sjlj-exceptions, which we couldn't
- tail-call to anyway.
-
- If current_nesting_level () == 0, we're being called after
- the function body has been expanded. This can happen when
- setting up trampolines in expand_function_end. */
if (currently_expanding_call++ != 0
|| !flag_optimize_sibling_calls
- || !rtx_equal_function_value_matters
- || current_nesting_level () == 0
|| args_size.var
|| lookup_stmt_eh_region (exp) >= 0)
try_tail_call = 0;
|| !lang_hooks.decls.ok_for_sibcall (fndecl))
try_tail_call = 0;
- if (try_tail_call)
- {
- 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);
- }
- /* Do the same for the function address if it is an expression. */
- if (!fndecl)
- addr = fix_unsafe_tree (addr);
- }
-
-
/* Ensure current function's preferred stack boundary is at least
what we need. We don't have to increase alignment for recursive
functions. */
int sibcall_failure = 0;
/* 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 can be ignored if we indeed use the tail
call expansion. */
int save_pending_stack_adjust = 0;
int save_stack_pointer_delta = 0;
if (pass == 0)
{
- /* Emit any queued insns now; otherwise they would end up in
- only one of the alternates. */
- emit_queue ();
-
/* State variables we need to save and restore between
iterations. */
save_pending_stack_adjust = pending_stack_adjust;
sibcall_failure instead of continuing the loop. */
start_sequence ();
- if (pass == 0)
- {
- /* We know at this point that there are not currently any
- pending cleanups. If, however, in the process of evaluating
- the arguments we were to create some, we'll need to be
- able to get rid of them. */
- expand_start_target_temps ();
- }
-
/* Don't let pending stack adjusts add up to too much.
Also, do all pending adjustments now if there is any chance
this might be a call to alloca or if we are expanding a sibling
structure value. */
if (pass != 0 && structure_value_addr && ! structure_value_addr_parm)
{
- structure_value_addr
+ structure_value_addr
= convert_memory_address (Pmode, structure_value_addr);
emit_move_insn (struct_value,
force_reg (Pmode,
load_register_parameters (args, num_actuals, &call_fusage, flags,
pass == 0, &sibcall_failure);
- /* Perform postincrements before actually calling the function. */
- emit_queue ();
-
/* Save a pointer to the last insn before the call, so that we can
later safely search backwards to find the CALL_INSN. */
before_call = get_last_insn ();
&& (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_SQRT
|| DECL_FUNCTION_CODE (fndecl) == BUILT_IN_SQRTF
|| DECL_FUNCTION_CODE (fndecl) == BUILT_IN_SQRTL))
- note = gen_rtx_fmt_e (SQRT,
- GET_MODE (temp),
+ note = gen_rtx_fmt_e (SQRT,
+ GET_MODE (temp),
args[0].initial_value);
else
{
note = gen_rtx_EXPR_LIST (VOIDmode,
args[i].initial_value, note);
note = gen_rtx_EXPR_LIST (VOIDmode, funexp, note);
-
+
if (flags & ECF_PURE)
note = gen_rtx_EXPR_LIST (VOIDmode,
gen_rtx_USE (VOIDmode,
emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
stack_pointer_delta = old_stack_pointer_delta;
pending_stack_adjust = old_pending_adj;
+ old_stack_allocated = stack_pointer_delta - pending_stack_adjust;
stack_arg_under_construction = old_stack_arg_under_construction;
highest_outgoing_arg_in_use = initial_highest_arg_in_use;
stack_usage_map = initial_stack_usage_map;
if (args[i].aligned_regs)
free (args[i].aligned_regs);
- if (pass == 0)
- {
- /* Undo the fake expand_start_target_temps we did earlier. If
- there had been any cleanups created, we've already set
- sibcall_failure. */
- expand_end_target_temps ();
- }
-
- /* If this function is returning into a memory location marked as
- readonly, it means it is initializing that location. We normally treat
- functions as not clobbering such locations, so we need to specify that
- this one does. We do this by adding the appropriate CLOBBER to the
- CALL_INSN function usage list. This cannot be done by emitting a
- standalone CLOBBER after the call because the latter would be ignored
- by at least the delay slot scheduling pass. We do this now instead of
- adding to call_fusage before the call to emit_call_1 because TARGET
- may be modified in the meantime. */
- if (structure_value_addr != 0 && target != 0
- && MEM_P (target) && RTX_UNCHANGING_P (target))
- add_function_usage_to
- (last_call_insn (),
- gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_CLOBBER (VOIDmode, target),
- NULL_RTX));
-
insns = get_insns ();
end_sequence ();
void
fixup_tail_calls (void)
{
- rtx insn;
- tree arg;
-
purge_reg_equiv_notes ();
-
- /* A sibling call sequence also may invalidate RTX_UNCHANGING_P
- flag of some incoming arguments MEM RTLs, because it can write into
- those slots. We clear all those bits now.
-
- This is (slight) overkill, we could keep track of which arguments
- we actually write into. */
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- {
- if (INSN_P (insn))
- purge_mem_unchanging_flag (PATTERN (insn));
- }
-
- /* Similarly, invalidate RTX_UNCHANGING_P for any incoming
- arguments passed in registers. */
- for (arg = DECL_ARGUMENTS (current_function_decl);
- arg;
- arg = TREE_CHAIN (arg))
- {
- if (REG_P (DECL_RTL (arg)))
- RTX_UNCHANGING_P (DECL_RTL (arg)) = false;
- }
}
/* Traverse an argument list in VALUES and expand all complex
|| (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode))
abort ();
- /* There's no need to call protect_from_queue, because
- either emit_move_insn or emit_push_insn will do that. */
-
/* Make sure it is a reasonable operand for a move or push insn. */
if (!REG_P (val) && !MEM_P (val)
&& ! (CONSTANT_P (val) && LEGITIMATE_CONSTANT_P (val)))
if (GET_CODE (valreg) == PARALLEL)
{
temp = gen_reg_rtx (outmode);
- emit_group_store (temp, valreg, NULL_TREE,
+ emit_group_store (temp, valreg, NULL_TREE,
GET_MODE_SIZE (outmode));
valreg = temp;
}
for a value of mode OUTMODE,
with NARGS different arguments, passed as alternating rtx values
and machine_modes to convert them to.
- The rtx values should have been passed through protect_from_queue already.
FN_TYPE should be LCT_NORMAL for `normal' calls, LCT_CONST for `const'
calls, LCT_PURE for `pure' calls, LCT_CONST_MAKE_BLOCK for `const' calls
excess = (arg->locate.size.constant
- int_size_in_bytes (TREE_TYPE (pval))
+ partial * GET_MODE_SIZE (GET_MODE (elt)));
- }
+ }
else
excess = (arg->locate.size.constant
- int_size_in_bytes (TREE_TYPE (pval))
be deferred during the rest of the arguments. */
NO_DEFER_POP;
- /* ANSI doesn't require a sequence point here,
- but PCC has one, so this will avoid some problems. */
- emit_queue ();
-
/* Free any temporary slots made in processing this argument. Show
that we might have taken the address of something and pushed that
as an operand. */
return false;
}
-/* Another version of the TARGET_MUST_PASS_IN_STACK hook. This one
+/* Another version of the TARGET_MUST_PASS_IN_STACK hook. This one
takes trailing padding of a structure into account. */
/* ??? Should be able to merge these two by examining BLOCK_REG_PADDING. */