diff options
Diffstat (limited to 'gcc/calls.c')
-rw-r--r-- | gcc/calls.c | 162 |
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) |