aboutsummaryrefslogtreecommitdiff
path: root/gcc/calls.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/calls.c')
-rw-r--r--gcc/calls.c162
1 files changed, 156 insertions, 6 deletions
diff --git a/gcc/calls.c b/gcc/calls.c
index 291f88cb835..ed001324830 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -135,7 +135,8 @@ static void initialize_argument_information (int, struct arg_data *,
struct args_size *, int, tree,
tree, CUMULATIVE_ARGS *, int,
rtx *, int *, int *, int *,
- bool *, bool);
+ /* APPLE LOCAL Altivec */
+ bool *, bool, tree);
static void compute_argument_addresses (struct arg_data *, rtx, int);
static rtx rtx_for_function_call (tree, tree);
static void load_register_parameters (struct arg_data *, int, rtx *, int,
@@ -262,7 +263,15 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
and we don't want to load it into a register as an optimization,
because prepare_call_address already did it if it should be done. */
if (GET_CODE (funexp) != SYMBOL_REF)
+/* APPLE LOCAL begin use R12 as register for indirect calls */
+/* This improves codegen (computation of value will be into R12) and
+ makes indirect sibcalls possible by ensuring a volatile reg is used. */
+#ifdef MAGIC_INDIRECT_CALL_REG
+ funexp = gen_rtx_REG (Pmode, MAGIC_INDIRECT_CALL_REG);
+#else
funexp = memory_address (FUNCTION_MODE, funexp);
+#endif
+/* APPLE LOCAL end use R12 as register for indirect calls */
#if defined (HAVE_sibcall_pop) && defined (HAVE_sibcall_value_pop)
if ((ecf_flags & ECF_SIBCALL)
@@ -408,6 +417,23 @@ emit_call_1 (rtx funexp, tree fntree, tree fndecl ATTRIBUTE_UNUSED,
SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0);
+ /* APPLE LOCAL begin ObjC direct dispatch */
+ /* Annotate calls to functions with fixed addresses. */
+ if (fndecl && TREE_CODE (fndecl) == FUNCTION_DECL)
+ {
+ tree t = lookup_attribute ("hard_coded_address",
+ DECL_ATTRIBUTES (fndecl));
+ if (t)
+ /* The constant address stored here has only 32 bits. This
+ is not a limitation, because the bla instruction has an
+ architectural limit of 26 bits. */
+ REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_ABSCALL,
+ gen_rtx_CONST_INT (FUNCTION_MODE,
+ tree_low_cst (TREE_VALUE (t), 0)),
+ REG_NOTES (call_insn));
+ }
+ /* APPLE LOCAL end ObjC direct dispatch */
+
/* Restore this now, so that we do defer pops for this call's args
if the context of the call as a whole permits. */
inhibit_defer_pop = old_inhibit_defer_pop;
@@ -930,7 +956,10 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
int reg_parm_stack_space,
rtx *old_stack_level, int *old_pending_adj,
int *must_preallocate, int *ecf_flags,
- bool *may_tailcall, bool call_from_thunk_p)
+ /* APPLE LOCAL begin Altivec */
+ bool *may_tailcall, bool call_from_thunk_p,
+ tree type_arg_types)
+ /* APPLE LOCAL end Altivec */
{
/* 1 if scanning parms front to back, -1 if scanning back to front. */
int inc;
@@ -941,6 +970,12 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
int i;
tree p;
+ /* APPLE LOCAL begin Altivec */
+ int pass, last_pass;
+ int save_i, save_inc;
+ int stdarg;
+ /* APPLE LOCAL end Altivec */
+
args_size->constant = 0;
args_size->var = 0;
@@ -959,13 +994,31 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
i = 0, inc = 1;
}
- /* I counts args in order (to be) pushed; ARGPOS counts in order written. */
- for (p = actparms, argpos = 0; p; p = TREE_CHAIN (p), i += inc, argpos++)
+ /* APPLE LOCAL begin Altivec */
+ stdarg = (type_arg_types != 0
+ && TREE_VALUE (tree_last (type_arg_types)) != void_type_node);
+ last_pass = 1;
+ save_i = i;
+ save_inc = inc;
+ for (pass = 1; pass <= last_pass; pass++)
+ {
+ i = save_i;
+ inc = save_inc;
+ /* I counts args in order (to be) pushed; ARGPOS counts in order written. */
+ for (p = actparms, argpos = 0; p; p = TREE_CHAIN (p), i += inc, argpos++)
+ /* APPLE LOCAL end Altivec */
{
tree type = TREE_TYPE (TREE_VALUE (p));
int unsignedp;
enum machine_mode mode;
+ /* APPLE LOCAL begin Altivec */
+ /* In 1st iteration over actual arguments, only consider non-vectors.
+ During 2nd iteration, finish off with vector parameters. */
+ if (!stdarg && targetm.calls.skip_vec_args (type, pass, &last_pass))
+ continue;
+ /* APPLE LOCAL end Altivec */
+
args[i].tree_value = TREE_VALUE (p);
/* Replace erroneous argument with constant zero. */
@@ -1148,6 +1201,9 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
FUNCTION_ARG_ADVANCE (*args_so_far, TYPE_MODE (type), type,
argpos < n_named_args);
}
+ /* APPLE LOCAL begin Altivec */
+ }
+ /* APPLE LOCAL end Altivec */
}
/* Update ARGS_SIZE to contain the total size for the argument block.
@@ -1545,6 +1601,8 @@ load_register_parameters (struct arg_data *args, int num_actuals,
&& args[i].locate.where_pad == downward
#else
&& BYTES_BIG_ENDIAN
+ /* APPLE LOCAL fix to regression caused by PR 14262 */
+ && !args[i].pass_on_stack
#endif
)
{
@@ -1802,12 +1860,20 @@ expand_call (tree exp, rtx target, int ignore)
tree actparms = TREE_OPERAND (exp, 1);
/* RTX for the function to be called. */
rtx funexp;
+ /* APPLE LOCAL begin use R12 as register for indirect calls */
+ /* A single rtx to be shared among multiple chains for indirect sibcalls */
+ rtx funexp_keep = NULL_RTX;
+ /* APPLE LOCAL end use R12 as register for indirect calls */
/* Sequence of insns to perform a normal "call". */
rtx normal_call_insns = NULL_RTX;
/* Sequence of insns to perform a tail "call". */
rtx tail_call_insns = NULL_RTX;
/* Data type of the function. */
tree funtype;
+ /* APPLE LOCAL begin objc stret methods */
+ /* Return type of the function. */
+ tree saved_return_type;
+ /* APPLE LOCAL end objc stret methods */
tree type_arg_types;
/* Declaration of the function being called,
or 0 if the function is computed (not known by name). */
@@ -2025,6 +2091,17 @@ expand_call (tree exp, rtx target, int ignore)
gcc_assert (POINTER_TYPE_P (funtype));
funtype = TREE_TYPE (funtype);
+ /* APPLE LOCAL begin objc stret methods */
+ /* Set the return type of the function to the type of the call expression,
+ in case that's different from the function declaration.
+ (This is the case when calling _objc_msgSend_stret, for example,
+ which is declared to return id, but actually returns a struct.)
+ But save the original return type first, so it can be restored later
+ in case it's needed. */
+ saved_return_type = TREE_TYPE (funtype);
+ TREE_TYPE (funtype) = TREE_TYPE (exp);
+ /* APPLE LOCAL end objc stret methods */
+
/* Munge the tree to split complex arguments into their imaginary
and real parts. */
if (targetm.calls.split_complex_arg)
@@ -2127,7 +2204,10 @@ expand_call (tree exp, rtx target, int ignore)
&args_so_far, reg_parm_stack_space,
&old_stack_level, &old_pending_adj,
&must_preallocate, &flags,
- &try_tail_call, CALL_FROM_THUNK_P (exp));
+ /* APPLE LOCAL begin Altivec */
+ &try_tail_call, CALL_FROM_THUNK_P (exp),
+ type_arg_types);
+ /* APPLE LOCAL end Altivec */
if (args_size.var)
{
@@ -2181,6 +2261,20 @@ expand_call (tree exp, rtx target, int ignore)
It does not seem worth the effort since few optimizable
sibling calls will return a structure. */
|| structure_value_addr != NULL_RTX
+/* APPLE LOCAL begin indirect sibcalls */
+#ifndef MAGIC_INDIRECT_CALL_REG
+/* The register holding the address is now always R12, so
+ we can consider indirect calls as sibcall candidates on ppc. */
+ /* If the register holding the address is a callee saved
+ register, then we lose. We have no way to prevent that,
+ so we only allow calls to named functions. */
+ /* ??? This could be done by having the insn constraints
+ use a register class that is all call-clobbered. Any
+ reload insns generated to fix things up would appear
+ before the sibcall_epilogue. */
+ || fndecl == NULL_TREE
+#endif
+/* APPLE LOCAL end indirect sibcalls */
/* Check whether the target is able to optimize the call
into a sibcall. */
|| !targetm.function_ok_for_sibcall (fndecl, exp)
@@ -2215,6 +2309,15 @@ expand_call (tree exp, rtx target, int ignore)
preferred_unit_stack_boundary = preferred_stack_boundary / BITS_PER_UNIT;
+ /* APPLE LOCAL begin indirect sibcalls */
+ /* Do this before creating the chains, to avoid a branch within them.
+ The paired chains both branch to the same label, but only one
+ chain has a definition of that label, because of the way the
+ infrastructure works. */
+ if ( !fndecl )
+ funexp_keep = rtx_for_function_call (fndecl, addr);
+ /* APPLE LOCAL end indirect sibcalls */
+
/* We want to make two insn chains; one for a sibling call, the other
for a normal call. We will select one of the two chains after
initial RTL generation is complete. */
@@ -2524,7 +2627,12 @@ expand_call (tree exp, rtx target, int ignore)
be deferred during the evaluation of the arguments. */
NO_DEFER_POP;
- funexp = rtx_for_function_call (fndecl, addr);
+ /* APPLE LOCAL begin indirect sibcalls */
+ if ( !fndecl )
+ funexp = funexp_keep;
+ else
+ funexp = rtx_for_function_call (fndecl, addr);
+ /* APPLE LOCAL end indirect sibcalls */
/* Figure out the register where the value, if any, will come back. */
valreg = 0;
@@ -2659,6 +2767,24 @@ expand_call (tree exp, rtx target, int ignore)
next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode,
void_type_node, 1);
+ /* APPLE LOCAL begin indirect calls in R12 */
+#ifdef MAGIC_INDIRECT_CALL_REG
+ /* For indirect calls, put the callee address in R12. This is necessary
+ for ObjC methods. This could be handled by patterns in rs6000.md,
+ as in 2.95, but it is better to put this copy in the RTL so the
+ optimizer can see it, and sometimes get rid of it, and the scheduler
+ can move it around. Right now none of these good things seems to
+ happen, but this should be fixable. (But note FSF won't like
+ putting it here.) */
+ if (!fndecl)
+ {
+ rtx magic_reg = gen_rtx_REG (Pmode, MAGIC_INDIRECT_CALL_REG);
+ emit_move_insn (magic_reg, funexp);
+ use_reg (&call_fusage, magic_reg);
+ }
+#endif
+ /* APPLE LOCAL end indirect calls in R12 */
+
/* All arguments and registers used for the call must be set up by
now! */
@@ -2686,6 +2812,12 @@ expand_call (tree exp, rtx target, int ignore)
valreg = gen_rtx_REG (TYPE_MODE (TREE_TYPE (exp)), REGNO (valreg));
}
+ /* APPLE LOCAL begin objc stret methods */
+ /* Restore the function's original return type
+ in case it's needed later on. */
+ TREE_TYPE (funtype) = saved_return_type;
+ /* APPLE LOCAL end objc stret methods */
+
/* If call is cse'able, make appropriate pair of reg-notes around it.
Test valreg so we don't crash; may safely ignore `const'
if return type is void. Disable for PARALLEL return values, because
@@ -3002,6 +3134,24 @@ expand_call (tree exp, rtx target, int ignore)
== stack_pointer_delta - pending_stack_adjust));
}
+ /* APPLE LOCAL begin sibcall optimization stomped CW frames (radar 3007352) */
+ /* GCC for PPC on Darwin has always rounded 'current_function_args_size' up to a multiple of 16.
+ CodeWarrior doesn't.
+ A father() that passes, say, 40 bytes of parameters to daughter() will have eight bytes of
+ padding if compiled with GCC, and zero bytes of padding if compiled with CW.
+ If a GCC-compiled daughter() in turn sibcalls to granddaughter() with, say, 44 bytes of parameters,
+ GCC will generate a store of that extra parameter into padding of the father() parameter area.
+ Alas, if father() was compild by CW, father() will not have the parameter area padding,
+ and something in the father() stackframe will be stomped.
+ Parameter areas are guaranteed to be a minimum of 32 bytes. See Radar 3007352. */
+ if ( ( ! sibcall_failure)
+ && args_size.constant > 32
+ && args_size.constant > cfun->unrounded_args_size)
+ {
+ sibcall_failure = 1;
+ }
+ /* APPLE LOCAL end sibcall optimization stomped CW frames (radar 3007352) */
+
/* If something prevents making this a sibling call,
zero out the sequence. */
if (sibcall_failure)