| /* Convert function calls to rtl insns, for GNU C compiler. |
| Copyright (C) 1989-2017 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "backend.h" |
| #include "target.h" |
| #include "rtl.h" |
| #include "tree.h" |
| #include "gimple.h" |
| #include "predict.h" |
| #include "memmodel.h" |
| #include "tm_p.h" |
| #include "stringpool.h" |
| #include "expmed.h" |
| #include "optabs.h" |
| #include "emit-rtl.h" |
| #include "cgraph.h" |
| #include "diagnostic-core.h" |
| #include "fold-const.h" |
| #include "stor-layout.h" |
| #include "varasm.h" |
| #include "internal-fn.h" |
| #include "dojump.h" |
| #include "explow.h" |
| #include "calls.h" |
| #include "expr.h" |
| #include "output.h" |
| #include "langhooks.h" |
| #include "except.h" |
| #include "dbgcnt.h" |
| #include "rtl-iter.h" |
| #include "tree-chkp.h" |
| #include "tree-vrp.h" |
| #include "tree-ssanames.h" |
| #include "rtl-chkp.h" |
| #include "intl.h" |
| |
| /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits. */ |
| #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) |
| |
| /* Data structure and subroutines used within expand_call. */ |
| |
| struct arg_data |
| { |
| /* Tree node for this argument. */ |
| tree tree_value; |
| /* Mode for value; TYPE_MODE unless promoted. */ |
| machine_mode mode; |
| /* Current RTL value for argument, or 0 if it isn't precomputed. */ |
| rtx value; |
| /* Initially-compute RTL value for argument; only for const functions. */ |
| rtx initial_value; |
| /* Register to pass this argument in, 0 if passed on stack, or an |
| PARALLEL if the arg is to be copied into multiple non-contiguous |
| registers. */ |
| rtx reg; |
| /* Register to pass this argument in when generating tail call sequence. |
| This is not the same register as for normal calls on machines with |
| register windows. */ |
| rtx tail_call_reg; |
| /* If REG is a PARALLEL, this is a copy of VALUE pulled into the correct |
| form for emit_group_move. */ |
| rtx parallel_value; |
| /* If value is passed in neither reg nor stack, this field holds a number |
| of a special slot to be used. */ |
| rtx special_slot; |
| /* For pointer bounds hold an index of parm bounds are bound to. -1 if |
| there is no such pointer. */ |
| int pointer_arg; |
| /* If pointer_arg refers a structure, then pointer_offset holds an offset |
| of a pointer in this structure. */ |
| int pointer_offset; |
| /* If REG was promoted from the actual mode of the argument expression, |
| indicates whether the promotion is sign- or zero-extended. */ |
| int unsignedp; |
| /* Number of bytes to put in registers. 0 means put the whole arg |
| in registers. Also 0 if not passed in registers. */ |
| int partial; |
| /* Nonzero if argument must be passed on stack. |
| Note that some arguments may be passed on the stack |
| even though pass_on_stack is zero, just because FUNCTION_ARG says so. |
| pass_on_stack identifies arguments that *cannot* go in registers. */ |
| int pass_on_stack; |
| /* Some fields packaged up for locate_and_pad_parm. */ |
| struct locate_and_pad_arg_data locate; |
| /* Location on the stack at which parameter should be stored. The store |
| has already been done if STACK == VALUE. */ |
| rtx stack; |
| /* Location on the stack of the start of this argument slot. This can |
| differ from STACK if this arg pads downward. This location is known |
| to be aligned to TARGET_FUNCTION_ARG_BOUNDARY. */ |
| rtx stack_slot; |
| /* Place that this stack area has been saved, if needed. */ |
| rtx save_area; |
| /* If an argument's alignment does not permit direct copying into registers, |
| copy in smaller-sized pieces into pseudos. These are stored in a |
| block pointed to by this field. The next field says how many |
| word-sized pseudos we made. */ |
| rtx *aligned_regs; |
| int n_aligned_regs; |
| }; |
| |
| /* A vector of one char per byte of stack space. A byte if nonzero if |
| the corresponding stack location has been used. |
| This vector is used to prevent a function call within an argument from |
| clobbering any stack already set up. */ |
| static char *stack_usage_map; |
| |
| /* Size of STACK_USAGE_MAP. */ |
| static int highest_outgoing_arg_in_use; |
| |
| /* A bitmap of virtual-incoming stack space. Bit is set if the corresponding |
| stack location's tail call argument has been already stored into the stack. |
| This bitmap is used to prevent sibling call optimization if function tries |
| to use parent's incoming argument slots when they have been already |
| overwritten with tail call arguments. */ |
| static sbitmap stored_args_map; |
| |
| /* stack_arg_under_construction is nonzero when an argument may be |
| initialized with a constructor call (including a C function that |
| returns a BLKmode struct) and expand_call must take special action |
| to make sure the object being constructed does not overlap the |
| argument list for the constructor call. */ |
| static int stack_arg_under_construction; |
| |
| static void emit_call_1 (rtx, tree, tree, tree, HOST_WIDE_INT, HOST_WIDE_INT, |
| HOST_WIDE_INT, rtx, rtx, int, rtx, int, |
| cumulative_args_t); |
| static void precompute_register_parameters (int, struct arg_data *, int *); |
| static void store_bounds (struct arg_data *, struct arg_data *); |
| static int store_one_arg (struct arg_data *, rtx, int, int, int); |
| static void store_unaligned_arguments_into_pseudos (struct arg_data *, int); |
| static int finalize_must_preallocate (int, int, struct arg_data *, |
| struct args_size *); |
| static void precompute_arguments (int, struct arg_data *); |
| static int compute_argument_block_size (int, struct args_size *, tree, tree, int); |
| static void initialize_argument_information (int, struct arg_data *, |
| struct args_size *, int, |
| tree, tree, |
| tree, tree, cumulative_args_t, int, |
| rtx *, int *, int *, int *, |
| bool *, bool); |
| 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, |
| int, int *); |
| static rtx emit_library_call_value_1 (int, rtx, rtx, enum libcall_type, |
| machine_mode, int, va_list); |
| static int special_function_p (const_tree, int); |
| static int check_sibcall_argument_overlap_1 (rtx); |
| static int check_sibcall_argument_overlap (rtx_insn *, struct arg_data *, int); |
| |
| static int combine_pending_stack_adjustment_and_call (int, struct args_size *, |
| unsigned int); |
| static tree split_complex_types (tree); |
| |
| #ifdef REG_PARM_STACK_SPACE |
| static rtx save_fixed_argument_area (int, rtx, int *, int *); |
| static void restore_fixed_argument_area (rtx, rtx, int, int); |
| #endif |
| |
| /* Force FUNEXP into a form suitable for the address of a CALL, |
| and return that as an rtx. Also load the static chain register |
| if FNDECL is a nested function. |
| |
| CALL_FUSAGE points to a variable holding the prospective |
| CALL_INSN_FUNCTION_USAGE information. */ |
| |
| rtx |
| prepare_call_address (tree fndecl_or_type, rtx funexp, rtx static_chain_value, |
| rtx *call_fusage, int reg_parm_seen, int flags) |
| { |
| /* 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) |
| { |
| /* If it's an indirect call by descriptor, generate code to perform |
| runtime identification of the pointer and load the descriptor. */ |
| if ((flags & ECF_BY_DESCRIPTOR) && !flag_trampolines) |
| { |
| const int bit_val = targetm.calls.custom_function_descriptors; |
| rtx call_lab = gen_label_rtx (); |
| |
| gcc_assert (fndecl_or_type && TYPE_P (fndecl_or_type)); |
| fndecl_or_type |
| = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL, NULL_TREE, |
| fndecl_or_type); |
| DECL_STATIC_CHAIN (fndecl_or_type) = 1; |
| rtx chain = targetm.calls.static_chain (fndecl_or_type, false); |
| |
| if (GET_MODE (funexp) != Pmode) |
| funexp = convert_memory_address (Pmode, funexp); |
| |
| /* Avoid long live ranges around function calls. */ |
| funexp = copy_to_mode_reg (Pmode, funexp); |
| |
| if (REG_P (chain)) |
| emit_insn (gen_rtx_CLOBBER (VOIDmode, chain)); |
| |
| /* Emit the runtime identification pattern. */ |
| rtx mask = gen_rtx_AND (Pmode, funexp, GEN_INT (bit_val)); |
| emit_cmp_and_jump_insns (mask, const0_rtx, EQ, NULL_RTX, Pmode, 1, |
| call_lab); |
| |
| /* Statically predict the branch to very likely taken. */ |
| rtx_insn *insn = get_last_insn (); |
| if (JUMP_P (insn)) |
| predict_insn_def (insn, PRED_BUILTIN_EXPECT, TAKEN); |
| |
| /* Load the descriptor. */ |
| rtx mem = gen_rtx_MEM (ptr_mode, |
| plus_constant (Pmode, funexp, - bit_val)); |
| MEM_NOTRAP_P (mem) = 1; |
| mem = convert_memory_address (Pmode, mem); |
| emit_move_insn (chain, mem); |
| |
| mem = gen_rtx_MEM (ptr_mode, |
| plus_constant (Pmode, funexp, |
| POINTER_SIZE / BITS_PER_UNIT |
| - bit_val)); |
| MEM_NOTRAP_P (mem) = 1; |
| mem = convert_memory_address (Pmode, mem); |
| emit_move_insn (funexp, mem); |
| |
| emit_label (call_lab); |
| |
| if (REG_P (chain)) |
| { |
| use_reg (call_fusage, chain); |
| STATIC_CHAIN_REG_P (chain) = 1; |
| } |
| |
| /* Make sure we're not going to be overwritten below. */ |
| gcc_assert (!static_chain_value); |
| } |
| |
| /* If we are using registers for parameters, force the |
| function address into a register now. */ |
| funexp = ((reg_parm_seen |
| && targetm.small_register_classes_for_mode_p (FUNCTION_MODE)) |
| ? force_not_mem (memory_address (FUNCTION_MODE, funexp)) |
| : memory_address (FUNCTION_MODE, funexp)); |
| } |
| else |
| { |
| /* funexp could be a SYMBOL_REF represents a function pointer which is |
| of ptr_mode. In this case, it should be converted into address mode |
| to be a valid address for memory rtx pattern. See PR 64971. */ |
| if (GET_MODE (funexp) != Pmode) |
| funexp = convert_memory_address (Pmode, funexp); |
| |
| if (!(flags & ECF_SIBCALL)) |
| { |
| if (!NO_FUNCTION_CSE && optimize && ! flag_no_function_cse) |
| funexp = force_reg (Pmode, funexp); |
| } |
| } |
| |
| if (static_chain_value != 0 |
| && (TREE_CODE (fndecl_or_type) != FUNCTION_DECL |
| || DECL_STATIC_CHAIN (fndecl_or_type))) |
| { |
| rtx chain; |
| |
| chain = targetm.calls.static_chain (fndecl_or_type, false); |
| static_chain_value = convert_memory_address (Pmode, static_chain_value); |
| |
| emit_move_insn (chain, static_chain_value); |
| if (REG_P (chain)) |
| { |
| use_reg (call_fusage, chain); |
| STATIC_CHAIN_REG_P (chain) = 1; |
| } |
| } |
| |
| return funexp; |
| } |
| |
| /* Generate instructions to call function FUNEXP, |
| and optionally pop the results. |
| The CALL_INSN is the first insn generated. |
| |
| FNDECL is the declaration node of the function. This is given to the |
| hook TARGET_RETURN_POPS_ARGS to determine whether this function pops |
| its own args. |
| |
| FUNTYPE is the data type of the function. This is given to the hook |
| TARGET_RETURN_POPS_ARGS to determine whether this function pops its |
| own args. We used to allow an identifier for library functions, but |
| that doesn't work when the return type is an aggregate type and the |
| calling convention says that the pointer to this aggregate is to be |
| popped by the callee. |
| |
| STACK_SIZE is the number of bytes of arguments on the stack, |
| ROUNDED_STACK_SIZE is that number rounded up to |
| PREFERRED_STACK_BOUNDARY; zero if the size is variable. This is |
| both to put into the call insn and to generate explicit popping |
| code if necessary. |
| |
| STRUCT_VALUE_SIZE is the number of bytes wanted in a structure value. |
| It is zero if this call doesn't want a structure value. |
| |
| NEXT_ARG_REG is the rtx that results from executing |
| targetm.calls.function_arg (&args_so_far, VOIDmode, void_type_node, true) |
| just after all the args have had their registers assigned. |
| This could be whatever you like, but normally it is the first |
| arg-register beyond those used for args in this call, |
| or 0 if all the arg-registers are used in this call. |
| It is passed on to `gen_call' so you can put this info in the call insn. |
| |
| VALREG is a hard register in which a value is returned, |
| or 0 if the call does not return a value. |
| |
| OLD_INHIBIT_DEFER_POP is the value that `inhibit_defer_pop' had before |
| the args to this call were processed. |
| We restore `inhibit_defer_pop' to that value. |
| |
| CALL_FUSAGE is either empty or an EXPR_LIST of USE expressions that |
| denote registers used by the called function. */ |
| |
| static void |
| emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNUSED, |
| tree funtype ATTRIBUTE_UNUSED, |
| HOST_WIDE_INT stack_size ATTRIBUTE_UNUSED, |
| HOST_WIDE_INT rounded_stack_size, |
| HOST_WIDE_INT struct_value_size ATTRIBUTE_UNUSED, |
| rtx next_arg_reg ATTRIBUTE_UNUSED, rtx valreg, |
| int old_inhibit_defer_pop, rtx call_fusage, int ecf_flags, |
| cumulative_args_t args_so_far ATTRIBUTE_UNUSED) |
| { |
| rtx rounded_stack_size_rtx = GEN_INT (rounded_stack_size); |
| rtx call, funmem, pat; |
| int already_popped = 0; |
| HOST_WIDE_INT n_popped = 0; |
| |
| /* Sibling call patterns never pop arguments (no sibcall(_value)_pop |
| patterns exist). Any popping that the callee does on return will |
| be from our caller's frame rather than ours. */ |
| if (!(ecf_flags & ECF_SIBCALL)) |
| { |
| n_popped += targetm.calls.return_pops_args (fndecl, funtype, stack_size); |
| |
| #ifdef CALL_POPS_ARGS |
| n_popped += CALL_POPS_ARGS (*get_cumulative_args (args_so_far)); |
| #endif |
| } |
| |
| /* Ensure address is valid. SYMBOL_REF is already valid, so no need, |
| 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) |
| funexp = memory_address (FUNCTION_MODE, funexp); |
| |
| funmem = gen_rtx_MEM (FUNCTION_MODE, funexp); |
| if (fndecl && TREE_CODE (fndecl) == FUNCTION_DECL) |
| { |
| tree t = fndecl; |
| |
| /* Although a built-in FUNCTION_DECL and its non-__builtin |
| counterpart compare equal and get a shared mem_attrs, they |
| produce different dump output in compare-debug compilations, |
| if an entry gets garbage collected in one compilation, then |
| adds a different (but equivalent) entry, while the other |
| doesn't run the garbage collector at the same spot and then |
| shares the mem_attr with the equivalent entry. */ |
| if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL) |
| { |
| tree t2 = builtin_decl_explicit (DECL_FUNCTION_CODE (t)); |
| if (t2) |
| t = t2; |
| } |
| |
| set_mem_expr (funmem, t); |
| } |
| else if (fntree) |
| set_mem_expr (funmem, build_simple_mem_ref (CALL_EXPR_FN (fntree))); |
| |
| if (ecf_flags & ECF_SIBCALL) |
| { |
| if (valreg) |
| pat = targetm.gen_sibcall_value (valreg, funmem, |
| rounded_stack_size_rtx, |
| next_arg_reg, NULL_RTX); |
| else |
| pat = targetm.gen_sibcall (funmem, rounded_stack_size_rtx, |
| next_arg_reg, GEN_INT (struct_value_size)); |
| } |
| /* If the target has "call" or "call_value" insns, then prefer them |
| if no arguments are actually popped. If the target does not have |
| "call" or "call_value" insns, then we must use the popping versions |
| even if the call has no arguments to pop. */ |
| else if (n_popped > 0 |
| || !(valreg |
| ? targetm.have_call_value () |
| : targetm.have_call ())) |
| { |
| rtx n_pop = GEN_INT (n_popped); |
| |
| /* If this subroutine pops its own args, record that in the call insn |
| if possible, for the sake of frame pointer elimination. */ |
| |
| if (valreg) |
| pat = targetm.gen_call_value_pop (valreg, funmem, |
| rounded_stack_size_rtx, |
| next_arg_reg, n_pop); |
| else |
| pat = targetm.gen_call_pop (funmem, rounded_stack_size_rtx, |
| next_arg_reg, n_pop); |
| |
| already_popped = 1; |
| } |
| else |
| { |
| if (valreg) |
| pat = targetm.gen_call_value (valreg, funmem, rounded_stack_size_rtx, |
| next_arg_reg, NULL_RTX); |
| else |
| pat = targetm.gen_call (funmem, rounded_stack_size_rtx, next_arg_reg, |
| GEN_INT (struct_value_size)); |
| } |
| emit_insn (pat); |
| |
| /* Find the call we just emitted. */ |
| rtx_call_insn *call_insn = last_call_insn (); |
| |
| /* Some target create a fresh MEM instead of reusing the one provided |
| above. Set its MEM_EXPR. */ |
| call = get_call_rtx_from (call_insn); |
| if (call |
| && MEM_EXPR (XEXP (call, 0)) == NULL_TREE |
| && MEM_EXPR (funmem) != NULL_TREE) |
| set_mem_expr (XEXP (call, 0), MEM_EXPR (funmem)); |
| |
| /* Mark instrumented calls. */ |
| if (call && fntree) |
| CALL_EXPR_WITH_BOUNDS_P (call) = CALL_WITH_BOUNDS_P (fntree); |
| |
| /* Put the register usage information there. */ |
| add_function_usage_to (call_insn, call_fusage); |
| |
| /* If this is a const call, then set the insn's unchanging bit. */ |
| if (ecf_flags & ECF_CONST) |
| RTL_CONST_CALL_P (call_insn) = 1; |
| |
| /* If this is a pure call, then set the insn's unchanging bit. */ |
| if (ecf_flags & ECF_PURE) |
| RTL_PURE_CALL_P (call_insn) = 1; |
| |
| /* If this is a const call, then set the insn's unchanging bit. */ |
| if (ecf_flags & ECF_LOOPING_CONST_OR_PURE) |
| RTL_LOOPING_CONST_OR_PURE_CALL_P (call_insn) = 1; |
| |
| /* Create a nothrow REG_EH_REGION note, if needed. */ |
| make_reg_eh_region_note (call_insn, ecf_flags, 0); |
| |
| if (ecf_flags & ECF_NORETURN) |
| add_reg_note (call_insn, REG_NORETURN, const0_rtx); |
| |
| if (ecf_flags & ECF_RETURNS_TWICE) |
| { |
| add_reg_note (call_insn, REG_SETJMP, const0_rtx); |
| cfun->calls_setjmp = 1; |
| } |
| |
| SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0); |
| |
| /* 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; |
| |
| if (n_popped > 0) |
| { |
| if (!already_popped) |
| CALL_INSN_FUNCTION_USAGE (call_insn) |
| = gen_rtx_EXPR_LIST (VOIDmode, |
| gen_rtx_CLOBBER (VOIDmode, stack_pointer_rtx), |
| CALL_INSN_FUNCTION_USAGE (call_insn)); |
| rounded_stack_size -= n_popped; |
| rounded_stack_size_rtx = GEN_INT (rounded_stack_size); |
| stack_pointer_delta -= n_popped; |
| |
| add_reg_note (call_insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta)); |
| |
| /* If popup is needed, stack realign must use DRAP */ |
| if (SUPPORTS_STACK_ALIGNMENT) |
| crtl->need_drap = true; |
| } |
| /* For noreturn calls when not accumulating outgoing args force |
| REG_ARGS_SIZE note to prevent crossjumping of calls with different |
| args sizes. */ |
| else if (!ACCUMULATE_OUTGOING_ARGS && (ecf_flags & ECF_NORETURN) != 0) |
| add_reg_note (call_insn, REG_ARGS_SIZE, GEN_INT (stack_pointer_delta)); |
| |
| if (!ACCUMULATE_OUTGOING_ARGS) |
| { |
| /* If returning from the subroutine does not automatically pop the args, |
| we need an instruction to pop them sooner or later. |
| Perhaps do it now; perhaps just record how much space to pop later. |
| |
| If returning from the subroutine does pop the args, indicate that the |
| stack pointer will be changed. */ |
| |
| if (rounded_stack_size != 0) |
| { |
| if (ecf_flags & ECF_NORETURN) |
| /* Just pretend we did the pop. */ |
| stack_pointer_delta -= rounded_stack_size; |
| else if (flag_defer_pop && inhibit_defer_pop == 0 |
| && ! (ecf_flags & (ECF_CONST | ECF_PURE))) |
| pending_stack_adjust += rounded_stack_size; |
| else |
| adjust_stack (rounded_stack_size_rtx); |
| } |
| } |
| /* When we accumulate outgoing args, we must avoid any stack manipulations. |
| Restore the stack pointer to its original value now. Usually |
| ACCUMULATE_OUTGOING_ARGS targets don't get here, but there are exceptions. |
| On i386 ACCUMULATE_OUTGOING_ARGS can be enabled on demand, and |
| popping variants of functions exist as well. |
| |
| ??? We may optimize similar to defer_pop above, but it is |
| probably not worthwhile. |
| |
| ??? It will be worthwhile to enable combine_stack_adjustments even for |
| such machines. */ |
| else if (n_popped) |
| anti_adjust_stack (GEN_INT (n_popped)); |
| } |
| |
| /* Determine if the function identified by FNDECL is one with |
| special properties we wish to know about. Modify FLAGS accordingly. |
| |
| For example, if the function might return more than one time (setjmp), then |
| set ECF_RETURNS_TWICE. |
| |
| Set ECF_MAY_BE_ALLOCA for any memory allocation function that might allocate |
| space from the stack such as alloca. */ |
| |
| static int |
| special_function_p (const_tree fndecl, int flags) |
| { |
| tree name_decl = DECL_NAME (fndecl); |
| |
| /* For instrumentation clones we want to derive flags |
| from the original name. */ |
| if (cgraph_node::get (fndecl) |
| && cgraph_node::get (fndecl)->instrumentation_clone) |
| name_decl = DECL_NAME (cgraph_node::get (fndecl)->orig_decl); |
| |
| if (fndecl && name_decl |
| && IDENTIFIER_LENGTH (name_decl) <= 11 |
| /* Exclude functions not at the file scope, or not `extern', |
| since they are not the magic functions we would otherwise |
| think they are. |
| FIXME: this should be handled with attributes, not with this |
| 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 |
| || TREE_CODE (DECL_CONTEXT (fndecl)) == TRANSLATION_UNIT_DECL) |
| && TREE_PUBLIC (fndecl)) |
| { |
| const char *name = IDENTIFIER_POINTER (name_decl); |
| const char *tname = name; |
| |
| /* We assume that alloca will always be called by name. It |
| makes no sense to pass it as a pointer-to-function to |
| anything that does not understand its behavior. */ |
| if (IDENTIFIER_LENGTH (name_decl) == 6 |
| && name[0] == 'a' |
| && ! strcmp (name, "alloca")) |
| flags |= ECF_MAY_BE_ALLOCA; |
| |
| /* Disregard prefix _ or __. */ |
| if (name[0] == '_') |
| { |
| if (name[1] == '_') |
| tname += 2; |
| else |
| tname += 1; |
| } |
| |
| /* ECF_RETURNS_TWICE is safe even for -ffreestanding. */ |
| if (! strcmp (tname, "setjmp") |
| || ! strcmp (tname, "sigsetjmp") |
| || ! strcmp (name, "savectx") |
| || ! strcmp (name, "vfork") |
| || ! strcmp (name, "getcontext")) |
| flags |= ECF_RETURNS_TWICE; |
| } |
| |
| if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) |
| switch (DECL_FUNCTION_CODE (fndecl)) |
| { |
| case BUILT_IN_ALLOCA: |
| case BUILT_IN_ALLOCA_WITH_ALIGN: |
| flags |= ECF_MAY_BE_ALLOCA; |
| break; |
| default: |
| break; |
| } |
| |
| return flags; |
| } |
| |
| /* Similar to special_function_p; return a set of ERF_ flags for the |
| function FNDECL. */ |
| static int |
| decl_return_flags (tree fndecl) |
| { |
| tree attr; |
| tree type = TREE_TYPE (fndecl); |
| if (!type) |
| return 0; |
| |
| attr = lookup_attribute ("fn spec", TYPE_ATTRIBUTES (type)); |
| if (!attr) |
| return 0; |
| |
| attr = TREE_VALUE (TREE_VALUE (attr)); |
| if (!attr || TREE_STRING_LENGTH (attr) < 1) |
| return 0; |
| |
| switch (TREE_STRING_POINTER (attr)[0]) |
| { |
| case '1': |
| case '2': |
| case '3': |
| case '4': |
| return ERF_RETURNS_ARG | (TREE_STRING_POINTER (attr)[0] - '1'); |
| |
| case 'm': |
| return ERF_NOALIAS; |
| |
| case '.': |
| default: |
| return 0; |
| } |
| } |
| |
| /* Return nonzero when FNDECL represents a call to setjmp. */ |
| |
| int |
| setjmp_call_p (const_tree fndecl) |
| { |
| if (DECL_IS_RETURNS_TWICE (fndecl)) |
| return ECF_RETURNS_TWICE; |
| return special_function_p (fndecl, 0) & ECF_RETURNS_TWICE; |
| } |
| |
| |
| /* Return true if STMT may be an alloca call. */ |
| |
| bool |
| gimple_maybe_alloca_call_p (const gimple *stmt) |
| { |
| tree fndecl; |
| |
| if (!is_gimple_call (stmt)) |
| return false; |
| |
| fndecl = gimple_call_fndecl (stmt); |
| if (fndecl && (special_function_p (fndecl, 0) & ECF_MAY_BE_ALLOCA)) |
| return true; |
| |
| return false; |
| } |
| |
| /* Return true if STMT is a builtin alloca call. */ |
| |
| bool |
| gimple_alloca_call_p (const gimple *stmt) |
| { |
| tree fndecl; |
| |
| if (!is_gimple_call (stmt)) |
| return false; |
| |
| fndecl = gimple_call_fndecl (stmt); |
| if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) |
| switch (DECL_FUNCTION_CODE (fndecl)) |
| { |
| case BUILT_IN_ALLOCA: |
| case BUILT_IN_ALLOCA_WITH_ALIGN: |
| return true; |
| default: |
| break; |
| } |
| |
| return false; |
| } |
| |
| /* Return true when exp contains a builtin alloca call. */ |
| |
| bool |
| alloca_call_p (const_tree exp) |
| { |
| tree fndecl; |
| if (TREE_CODE (exp) == CALL_EXPR |
| && (fndecl = get_callee_fndecl (exp)) |
| && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) |
| switch (DECL_FUNCTION_CODE (fndecl)) |
| { |
| case BUILT_IN_ALLOCA: |
| case BUILT_IN_ALLOCA_WITH_ALIGN: |
| return true; |
| default: |
| break; |
| } |
| |
| return false; |
| } |
| |
| /* Return TRUE if FNDECL is either a TM builtin or a TM cloned |
| function. Return FALSE otherwise. */ |
| |
| static bool |
| is_tm_builtin (const_tree fndecl) |
| { |
| if (fndecl == NULL) |
| return false; |
| |
| if (decl_is_tm_clone (fndecl)) |
| return true; |
| |
| if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) |
| { |
| switch (DECL_FUNCTION_CODE (fndecl)) |
| { |
| case BUILT_IN_TM_COMMIT: |
| case BUILT_IN_TM_COMMIT_EH: |
| case BUILT_IN_TM_ABORT: |
| case BUILT_IN_TM_IRREVOCABLE: |
| case BUILT_IN_TM_GETTMCLONE_IRR: |
| case BUILT_IN_TM_MEMCPY: |
| case BUILT_IN_TM_MEMMOVE: |
| case BUILT_IN_TM_MEMSET: |
| CASE_BUILT_IN_TM_STORE (1): |
| CASE_BUILT_IN_TM_STORE (2): |
| CASE_BUILT_IN_TM_STORE (4): |
| CASE_BUILT_IN_TM_STORE (8): |
| CASE_BUILT_IN_TM_STORE (FLOAT): |
| CASE_BUILT_IN_TM_STORE (DOUBLE): |
| CASE_BUILT_IN_TM_STORE (LDOUBLE): |
| CASE_BUILT_IN_TM_STORE (M64): |
| CASE_BUILT_IN_TM_STORE (M128): |
| CASE_BUILT_IN_TM_STORE (M256): |
| CASE_BUILT_IN_TM_LOAD (1): |
| CASE_BUILT_IN_TM_LOAD (2): |
| CASE_BUILT_IN_TM_LOAD (4): |
| CASE_BUILT_IN_TM_LOAD (8): |
| CASE_BUILT_IN_TM_LOAD (FLOAT): |
| CASE_BUILT_IN_TM_LOAD (DOUBLE): |
| CASE_BUILT_IN_TM_LOAD (LDOUBLE): |
| CASE_BUILT_IN_TM_LOAD (M64): |
| CASE_BUILT_IN_TM_LOAD (M128): |
| CASE_BUILT_IN_TM_LOAD (M256): |
| case BUILT_IN_TM_LOG: |
| case BUILT_IN_TM_LOG_1: |
| case BUILT_IN_TM_LOG_2: |
| case BUILT_IN_TM_LOG_4: |
| case BUILT_IN_TM_LOG_8: |
| case BUILT_IN_TM_LOG_FLOAT: |
| case BUILT_IN_TM_LOG_DOUBLE: |
| case BUILT_IN_TM_LOG_LDOUBLE: |
| case BUILT_IN_TM_LOG_M64: |
| case BUILT_IN_TM_LOG_M128: |
| case BUILT_IN_TM_LOG_M256: |
| return true; |
| default: |
| break; |
| } |
| } |
| return false; |
| } |
| |
| /* Detect flags (function attributes) from the function decl or type node. */ |
| |
| int |
| flags_from_decl_or_type (const_tree exp) |
| { |
| int flags = 0; |
| |
| if (DECL_P (exp)) |
| { |
| /* The function exp may have the `malloc' attribute. */ |
| if (DECL_IS_MALLOC (exp)) |
| flags |= ECF_MALLOC; |
| |
| /* The function exp may have the `returns_twice' attribute. */ |
| if (DECL_IS_RETURNS_TWICE (exp)) |
| flags |= ECF_RETURNS_TWICE; |
| |
| /* Process the pure and const attributes. */ |
| if (TREE_READONLY (exp)) |
| flags |= ECF_CONST; |
| if (DECL_PURE_P (exp)) |
| flags |= ECF_PURE; |
| if (DECL_LOOPING_CONST_OR_PURE_P (exp)) |
| flags |= ECF_LOOPING_CONST_OR_PURE; |
| |
| if (DECL_IS_NOVOPS (exp)) |
| flags |= ECF_NOVOPS; |
| if (lookup_attribute ("leaf", DECL_ATTRIBUTES (exp))) |
| flags |= ECF_LEAF; |
| |
| if (TREE_NOTHROW (exp)) |
| flags |= ECF_NOTHROW; |
| |
| if (flag_tm) |
| { |
| if (is_tm_builtin (exp)) |
| flags |= ECF_TM_BUILTIN; |
| else if ((flags & (ECF_CONST|ECF_NOVOPS)) != 0 |
| || lookup_attribute ("transaction_pure", |
| TYPE_ATTRIBUTES (TREE_TYPE (exp)))) |
| flags |= ECF_TM_PURE; |
| } |
| |
| flags = special_function_p (exp, flags); |
| } |
| else if (TYPE_P (exp)) |
| { |
| if (TYPE_READONLY (exp)) |
| flags |= ECF_CONST; |
| |
| if (flag_tm |
| && ((flags & ECF_CONST) != 0 |
| || lookup_attribute ("transaction_pure", TYPE_ATTRIBUTES (exp)))) |
| flags |= ECF_TM_PURE; |
| } |
| else |
| gcc_unreachable (); |
| |
| if (TREE_THIS_VOLATILE (exp)) |
| { |
| flags |= ECF_NORETURN; |
| if (flags & (ECF_CONST|ECF_PURE)) |
| flags |= ECF_LOOPING_CONST_OR_PURE; |
| } |
| |
| return flags; |
| } |
| |
| /* Detect flags from a CALL_EXPR. */ |
| |
| int |
| call_expr_flags (const_tree t) |
| { |
| int flags; |
| tree decl = get_callee_fndecl (t); |
| |
| if (decl) |
| flags = flags_from_decl_or_type (decl); |
| else if (CALL_EXPR_FN (t) == NULL_TREE) |
| flags = internal_fn_flags (CALL_EXPR_IFN (t)); |
| else |
| { |
| tree type = TREE_TYPE (CALL_EXPR_FN (t)); |
| if (type && TREE_CODE (type) == POINTER_TYPE) |
| flags = flags_from_decl_or_type (TREE_TYPE (type)); |
| else |
| flags = 0; |
| if (CALL_EXPR_BY_DESCRIPTOR (t)) |
| flags |= ECF_BY_DESCRIPTOR; |
| } |
| |
| return flags; |
| } |
| |
| /* Return true if TYPE should be passed by invisible reference. */ |
| |
| bool |
| pass_by_reference (CUMULATIVE_ARGS *ca, machine_mode mode, |
| tree type, bool named_arg) |
| { |
| if (type) |
| { |
| /* If this type contains non-trivial constructors, then it is |
| forbidden for the middle-end to create any new copies. */ |
| if (TREE_ADDRESSABLE (type)) |
| return true; |
| |
| /* GCC post 3.4 passes *all* variable sized types by reference. */ |
| if (!TYPE_SIZE (type) || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) |
| return true; |
| |
| /* If a record type should be passed the same as its first (and only) |
| member, use the type and mode of that member. */ |
| if (TREE_CODE (type) == RECORD_TYPE && TYPE_TRANSPARENT_AGGR (type)) |
| { |
| type = TREE_TYPE (first_field (type)); |
| mode = TYPE_MODE (type); |
| } |
| } |
| |
| return targetm.calls.pass_by_reference (pack_cumulative_args (ca), mode, |
| type, named_arg); |
| } |
| |
| /* Return true if TYPE, which is passed by reference, should be callee |
| copied instead of caller copied. */ |
| |
| bool |
| reference_callee_copied (CUMULATIVE_ARGS *ca, machine_mode mode, |
| tree type, bool named_arg) |
| { |
| if (type && TREE_ADDRESSABLE (type)) |
| return false; |
| return targetm.calls.callee_copies (pack_cumulative_args (ca), mode, type, |
| named_arg); |
| } |
| |
| |
| /* Precompute all register parameters as described by ARGS, storing values |
| into fields within the ARGS array. |
| |
| NUM_ACTUALS indicates the total number elements in the ARGS array. |
| |
| Set REG_PARM_SEEN if we encounter a register parameter. */ |
| |
| static void |
| precompute_register_parameters (int num_actuals, struct arg_data *args, |
| int *reg_parm_seen) |
| { |
| int i; |
| |
| *reg_parm_seen = 0; |
| |
| for (i = 0; i < num_actuals; i++) |
| if (args[i].reg != 0 && ! args[i].pass_on_stack) |
| { |
| *reg_parm_seen = 1; |
| |
| if (args[i].value == 0) |
| { |
| push_temp_slots (); |
| args[i].value = expand_normal (args[i].tree_value); |
| preserve_temp_slots (args[i].value); |
| pop_temp_slots (); |
| } |
| |
| /* If we are to promote the function arg to a wider mode, |
| do it now. */ |
| |
| if (args[i].mode != TYPE_MODE (TREE_TYPE (args[i].tree_value))) |
| args[i].value |
| = convert_modes (args[i].mode, |
| TYPE_MODE (TREE_TYPE (args[i].tree_value)), |
| args[i].value, args[i].unsignedp); |
| |
| /* If the value is a non-legitimate constant, force it into a |
| pseudo now. TLS symbols sometimes need a call to resolve. */ |
| if (CONSTANT_P (args[i].value) |
| && !targetm.legitimate_constant_p (args[i].mode, args[i].value)) |
| args[i].value = force_reg (args[i].mode, args[i].value); |
| |
| /* If we're going to have to load the value by parts, pull the |
| parts into pseudos. The part extraction process can involve |
| non-trivial computation. */ |
| if (GET_CODE (args[i].reg) == PARALLEL) |
| { |
| tree type = TREE_TYPE (args[i].tree_value); |
| args[i].parallel_value |
| = emit_group_load_into_temps (args[i].reg, args[i].value, |
| type, int_size_in_bytes (type)); |
| } |
| |
| /* If the value is expensive, and we are inside an appropriately |
| short loop, put the value into a pseudo and then put the pseudo |
| into the hard reg. |
| |
| For small register classes, also do this if this call uses |
| register parameters. This is to avoid reload conflicts while |
| loading the parameters registers. */ |
| |
| else if ((! (REG_P (args[i].value) |
| || (GET_CODE (args[i].value) == SUBREG |
| && REG_P (SUBREG_REG (args[i].value))))) |
| && args[i].mode != BLKmode |
| && (set_src_cost (args[i].value, args[i].mode, |
| optimize_insn_for_speed_p ()) |
| > COSTS_N_INSNS (1)) |
| && ((*reg_parm_seen |
| && targetm.small_register_classes_for_mode_p (args[i].mode)) |
| || optimize)) |
| args[i].value = copy_to_mode_reg (args[i].mode, args[i].value); |
| } |
| } |
| |
| #ifdef REG_PARM_STACK_SPACE |
| |
| /* The argument list is the property of the called routine and it |
| may clobber it. If the fixed area has been used for previous |
| parameters, we must save and restore it. */ |
| |
| static rtx |
| save_fixed_argument_area (int reg_parm_stack_space, rtx argblock, int *low_to_save, int *high_to_save) |
| { |
| int low; |
| int high; |
| |
| /* Compute the boundary of the area that needs to be saved, if any. */ |
| high = reg_parm_stack_space; |
| if (ARGS_GROW_DOWNWARD) |
| high += 1; |
| |
| if (high > highest_outgoing_arg_in_use) |
| high = highest_outgoing_arg_in_use; |
| |
| for (low = 0; low < high; low++) |
| if (stack_usage_map[low] != 0) |
| { |
| int num_to_save; |
| machine_mode save_mode; |
| int delta; |
| rtx addr; |
| rtx stack_area; |
| rtx save_area; |
| |
| while (stack_usage_map[--high] == 0) |
| ; |
| |
| *low_to_save = low; |
| *high_to_save = high; |
| |
| num_to_save = high - low + 1; |
| save_mode = mode_for_size (num_to_save * BITS_PER_UNIT, MODE_INT, 1); |
| |
| /* If we don't have the required alignment, must do this |
| in BLKmode. */ |
| if ((low & (MIN (GET_MODE_SIZE (save_mode), |
| BIGGEST_ALIGNMENT / UNITS_PER_WORD) - 1))) |
| save_mode = BLKmode; |
| |
| if (ARGS_GROW_DOWNWARD) |
| delta = -high; |
| else |
| delta = low; |
| |
| addr = plus_constant (Pmode, argblock, delta); |
| stack_area = gen_rtx_MEM (save_mode, memory_address (save_mode, addr)); |
| |
| set_mem_align (stack_area, PARM_BOUNDARY); |
| if (save_mode == BLKmode) |
| { |
| save_area = assign_stack_temp (BLKmode, num_to_save); |
| emit_block_move (validize_mem (save_area), stack_area, |
| GEN_INT (num_to_save), BLOCK_OP_CALL_PARM); |
| } |
| else |
| { |
| save_area = gen_reg_rtx (save_mode); |
| emit_move_insn (save_area, stack_area); |
| } |
| |
| return save_area; |
| } |
| |
| return NULL_RTX; |
| } |
| |
| static void |
| restore_fixed_argument_area (rtx save_area, rtx argblock, int high_to_save, int low_to_save) |
| { |
| machine_mode save_mode = GET_MODE (save_area); |
| int delta; |
| rtx addr, stack_area; |
| |
| if (ARGS_GROW_DOWNWARD) |
| delta = -high_to_save; |
| else |
| delta = low_to_save; |
| |
| addr = plus_constant (Pmode, argblock, delta); |
| stack_area = gen_rtx_MEM (save_mode, memory_address (save_mode, addr)); |
| set_mem_align (stack_area, PARM_BOUNDARY); |
| |
| if (save_mode != BLKmode) |
| emit_move_insn (stack_area, save_area); |
| else |
| emit_block_move (stack_area, validize_mem (save_area), |
| GEN_INT (high_to_save - low_to_save + 1), |
| BLOCK_OP_CALL_PARM); |
| } |
| #endif /* REG_PARM_STACK_SPACE */ |
| |
| /* If any elements in ARGS refer to parameters that are to be passed in |
| registers, but not in memory, and whose alignment does not permit a |
| direct copy into registers. Copy the values into a group of pseudos |
| which we will later copy into the appropriate hard registers. |
| |
| Pseudos for each unaligned argument will be stored into the array |
| args[argnum].aligned_regs. The caller is responsible for deallocating |
| the aligned_regs array if it is nonzero. */ |
| |
| static void |
| store_unaligned_arguments_into_pseudos (struct arg_data *args, int num_actuals) |
| { |
| int i, j; |
| |
| for (i = 0; i < num_actuals; i++) |
| if (args[i].reg != 0 && ! args[i].pass_on_stack |
| && GET_CODE (args[i].reg) != PARALLEL |
| && args[i].mode == BLKmode |
| && MEM_P (args[i].value) |
| && (MEM_ALIGN (args[i].value) |
| < (unsigned int) MIN (BIGGEST_ALIGNMENT, BITS_PER_WORD))) |
| { |
| int bytes = int_size_in_bytes (TREE_TYPE (args[i].tree_value)); |
| int endian_correction = 0; |
| |
| if (args[i].partial) |
| { |
| gcc_assert (args[i].partial % UNITS_PER_WORD == 0); |
| args[i].n_aligned_regs = args[i].partial / UNITS_PER_WORD; |
| } |
| else |
| { |
| args[i].n_aligned_regs |
| = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; |
| } |
| |
| args[i].aligned_regs = XNEWVEC (rtx, args[i].n_aligned_regs); |
| |
| /* Structures smaller than a word are normally aligned to the |
| least significant byte. On a BYTES_BIG_ENDIAN machine, |
| this means we must skip the empty high order bytes when |
| calculating the bit offset. */ |
| if (bytes < UNITS_PER_WORD |
| #ifdef BLOCK_REG_PADDING |
| && (BLOCK_REG_PADDING (args[i].mode, |
| TREE_TYPE (args[i].tree_value), 1) |
| == downward) |
| #else |
| && BYTES_BIG_ENDIAN |
| #endif |
| ) |
| endian_correction = BITS_PER_WORD - bytes * BITS_PER_UNIT; |
| |
| for (j = 0; j < args[i].n_aligned_regs; j++) |
| { |
| rtx reg = gen_reg_rtx (word_mode); |
| rtx word = operand_subword_force (args[i].value, j, BLKmode); |
| int bitsize = MIN (bytes * BITS_PER_UNIT, BITS_PER_WORD); |
| |
| args[i].aligned_regs[j] = reg; |
| word = extract_bit_field (word, bitsize, 0, 1, NULL_RTX, |
| word_mode, word_mode, false); |
| |
| /* There is no need to restrict this code to loading items |
| in TYPE_ALIGN sized hunks. The bitfield instructions can |
| load up entire word sized registers efficiently. |
| |
| ??? This may not be needed anymore. |
| We use to emit a clobber here but that doesn't let later |
| passes optimize the instructions we emit. By storing 0 into |
| the register later passes know the first AND to zero out the |
| bitfield being set in the register is unnecessary. The store |
| of 0 will be deleted as will at least the first AND. */ |
| |
| emit_move_insn (reg, const0_rtx); |
| |
| bytes -= bitsize / BITS_PER_UNIT; |
| store_bit_field (reg, bitsize, endian_correction, 0, 0, |
| word_mode, word, false); |
| } |
| } |
| } |
| |
| /* The limit set by -Walloc-larger-than=. */ |
| static GTY(()) tree alloc_object_size_limit; |
| |
| /* Initialize ALLOC_OBJECT_SIZE_LIMIT based on the -Walloc-size-larger-than= |
| setting if the option is specified, or to the maximum object size if it |
| is not. Return the initialized value. */ |
| |
| static tree |
| alloc_max_size (void) |
| { |
| if (alloc_object_size_limit) |
| return alloc_object_size_limit; |
| |
| alloc_object_size_limit = TYPE_MAX_VALUE (ssizetype); |
| |
| if (!warn_alloc_size_limit) |
| return alloc_object_size_limit; |
| |
| const char *optname = "-Walloc-size-larger-than="; |
| |
| char *end = NULL; |
| errno = 0; |
| unsigned HOST_WIDE_INT unit = 1; |
| unsigned HOST_WIDE_INT limit |
| = strtoull (warn_alloc_size_limit, &end, 10); |
| |
| /* If the value is too large to be represented use the maximum |
| representable value that strtoull sets limit to (setting |
| errno to ERANGE). */ |
| |
| if (end && *end) |
| { |
| /* Numeric option arguments are at most INT_MAX. Make it |
| possible to specify a larger value by accepting common |
| suffixes. */ |
| if (!strcmp (end, "kB")) |
| unit = 1000; |
| else if (!strcasecmp (end, "KiB") || !strcmp (end, "KB")) |
| unit = 1024; |
| else if (!strcmp (end, "MB")) |
| unit = HOST_WIDE_INT_UC (1000) * 1000; |
| else if (!strcasecmp (end, "MiB")) |
| unit = HOST_WIDE_INT_UC (1024) * 1024; |
| else if (!strcasecmp (end, "GB")) |
| unit = HOST_WIDE_INT_UC (1000) * 1000 * 1000; |
| else if (!strcasecmp (end, "GiB")) |
| unit = HOST_WIDE_INT_UC (1024) * 1024 * 1024; |
| else if (!strcasecmp (end, "TB")) |
| unit = HOST_WIDE_INT_UC (1000) * 1000 * 1000 * 1000; |
| else if (!strcasecmp (end, "TiB")) |
| unit = HOST_WIDE_INT_UC (1024) * 1024 * 1024 * 1024; |
| else if (!strcasecmp (end, "PB")) |
| unit = HOST_WIDE_INT_UC (1000) * 1000 * 1000 * 1000 * 1000; |
| else if (!strcasecmp (end, "PiB")) |
| unit = HOST_WIDE_INT_UC (1024) * 1024 * 1024 * 1024 * 1024; |
| else if (!strcasecmp (end, "EB")) |
| unit = HOST_WIDE_INT_UC (1000) * 1000 * 1000 * 1000 * 1000 |
| * 1000; |
| else if (!strcasecmp (end, "EiB")) |
| unit = HOST_WIDE_INT_UC (1024) * 1024 * 1024 * 1024 * 1024 |
| * 1024; |
| else |
| { |
| /* This could mean an unknown suffix or a bad prefix, like |
| "+-1". */ |
| warning_at (UNKNOWN_LOCATION, 0, |
| "invalid argument %qs to %qs", |
| warn_alloc_size_limit, optname); |
| /* Ignore the limit extracted by strtoull. */ |
| unit = 0; |
| } |
| } |
| |
| if (unit) |
| { |
| widest_int w = wi::mul (limit, unit); |
| if (w < wi::to_widest (alloc_object_size_limit)) |
| alloc_object_size_limit |
| = wide_int_to_tree (ptrdiff_type_node, w); |
| else |
| alloc_object_size_limit = build_all_ones_cst (size_type_node); |
| } |
| |
| return alloc_object_size_limit; |
| } |
| |
| /* Return true when EXP's range can be determined and set RANGE[] to it |
| after adjusting it if necessary to make EXP a valid size argument to |
| an allocation function declared with attribute alloc_size (whose |
| argument may be signed), or to a string manipulation function like |
| memset. */ |
| |
| bool |
| get_size_range (tree exp, tree range[2]) |
| { |
| if (tree_fits_uhwi_p (exp)) |
| { |
| /* EXP is a constant. */ |
| range[0] = range[1] = exp; |
| return true; |
| } |
| |
| wide_int min, max; |
| enum value_range_type range_type |
| = ((TREE_CODE (exp) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (exp))) |
| ? get_range_info (exp, &min, &max) : VR_VARYING); |
| |
| if (range_type == VR_VARYING) |
| { |
| /* No range information available. */ |
| range[0] = NULL_TREE; |
| range[1] = NULL_TREE; |
| return false; |
| } |
| |
| tree exptype = TREE_TYPE (exp); |
| unsigned expprec = TYPE_PRECISION (exptype); |
| wide_int wzero = wi::zero (expprec); |
| wide_int wmaxval = wide_int (TYPE_MAX_VALUE (exptype)); |
| |
| bool signed_p = !TYPE_UNSIGNED (exptype); |
| |
| if (range_type == VR_ANTI_RANGE) |
| { |
| if (signed_p) |
| { |
| if (wi::les_p (max, wzero)) |
| { |
| /* EXP is not in a strictly negative range. That means |
| it must be in some (not necessarily strictly) positive |
| range which includes zero. Since in signed to unsigned |
| conversions negative values end up converted to large |
| positive values, and otherwise they are not valid sizes, |
| the resulting range is in both cases [0, TYPE_MAX]. */ |
| min = wzero; |
| max = wmaxval; |
| } |
| else if (wi::les_p (min - 1, wzero)) |
| { |
| /* EXP is not in a negative-positive range. That means EXP |
| is either negative, or greater than max. Since negative |
| sizes are invalid make the range [MAX + 1, TYPE_MAX]. */ |
| min = max + 1; |
| max = wmaxval; |
| } |
| else |
| { |
| max = min - 1; |
| min = wzero; |
| } |
| } |
| else if (wi::eq_p (wzero, min - 1)) |
| { |
| /* EXP is unsigned and not in the range [1, MAX]. That means |
| it's either zero or greater than MAX. Even though 0 would |
| normally be detected by -Walloc-zero set the range to |
| [MAX, TYPE_MAX] so that when MAX is greater than the limit |
| the whole range is diagnosed. */ |
| min = max + 1; |
| max = wmaxval; |
| } |
| else |
| { |
| max = min - 1; |
| min = wzero; |
| } |
| } |
| |
| range[0] = wide_int_to_tree (exptype, min); |
| range[1] = wide_int_to_tree (exptype, max); |
| |
| return true; |
| } |
| |
| /* Diagnose a call EXP to function FN decorated with attribute alloc_size |
| whose argument numbers given by IDX with values given by ARGS exceed |
| the maximum object size or cause an unsigned oveflow (wrapping) when |
| multiplied. When ARGS[0] is null the function does nothing. ARGS[1] |
| may be null for functions like malloc, and non-null for those like |
| calloc that are decorated with a two-argument attribute alloc_size. */ |
| |
| void |
| maybe_warn_alloc_args_overflow (tree fn, tree exp, tree args[2], int idx[2]) |
| { |
| /* The range each of the (up to) two arguments is known to be in. */ |
| tree argrange[2][2] = { { NULL_TREE, NULL_TREE }, { NULL_TREE, NULL_TREE } }; |
| |
| /* Maximum object size set by -Walloc-size-larger-than= or SIZE_MAX / 2. */ |
| tree maxobjsize = alloc_max_size (); |
| |
| location_t loc = EXPR_LOCATION (exp); |
| |
| bool warned = false; |
| |
| /* Validate each argument individually. */ |
| for (unsigned i = 0; i != 2 && args[i]; ++i) |
| { |
| if (TREE_CODE (args[i]) == INTEGER_CST) |
| { |
| argrange[i][0] = args[i]; |
| argrange[i][1] = args[i]; |
| |
| if (tree_int_cst_lt (args[i], integer_zero_node)) |
| { |
| warned = warning_at (loc, OPT_Walloc_size_larger_than_, |
| "%Kargument %i value %qE is negative", |
| exp, idx[i] + 1, args[i]); |
| } |
| else if (integer_zerop (args[i])) |
| { |
| /* Avoid issuing -Walloc-zero for allocation functions other |
| than __builtin_alloca that are declared with attribute |
| returns_nonnull because there's no portability risk. This |
| avoids warning for such calls to libiberty's xmalloc and |
| friends. |
| Also avoid issuing the warning for calls to function named |
| "alloca". */ |
| if ((DECL_FUNCTION_CODE (fn) == BUILT_IN_ALLOCA |
| && IDENTIFIER_LENGTH (DECL_NAME (fn)) != 6) |
| || (DECL_FUNCTION_CODE (fn) != BUILT_IN_ALLOCA |
| && !lookup_attribute ("returns_nonnull", |
| TYPE_ATTRIBUTES (TREE_TYPE (fn))))) |
| warned = warning_at (loc, OPT_Walloc_zero, |
| "%Kargument %i value is zero", |
| exp, idx[i] + 1); |
| } |
| else if (tree_int_cst_lt (maxobjsize, args[i])) |
| { |
| /* G++ emits calls to ::operator new[](SIZE_MAX) in C++98 |
| mode and with -fno-exceptions as a way to indicate array |
| size overflow. There's no good way to detect C++98 here |
| so avoid diagnosing these calls for all C++ modes. */ |
| if (i == 0 |
| && !args[1] |
| && lang_GNU_CXX () |
| && DECL_IS_OPERATOR_NEW (fn) |
| && integer_all_onesp (args[i])) |
| continue; |
| |
| warned = warning_at (loc, OPT_Walloc_size_larger_than_, |
| "%Kargument %i value %qE exceeds " |
| "maximum object size %E", |
| exp, idx[i] + 1, args[i], maxobjsize); |
| } |
| } |
| else if (TREE_CODE (args[i]) == SSA_NAME |
| && get_size_range (args[i], argrange[i])) |
| { |
| /* Verify that the argument's range is not negative (including |
| upper bound of zero). */ |
| if (tree_int_cst_lt (argrange[i][0], integer_zero_node) |
| && tree_int_cst_le (argrange[i][1], integer_zero_node)) |
| { |
| warned = warning_at (loc, OPT_Walloc_size_larger_than_, |
| "%Kargument %i range [%E, %E] is negative", |
| exp, idx[i] + 1, |
| argrange[i][0], argrange[i][1]); |
| } |
| else if (tree_int_cst_lt (maxobjsize, argrange[i][0])) |
| { |
| warned = warning_at (loc, OPT_Walloc_size_larger_than_, |
| "%Kargument %i range [%E, %E] exceeds " |
| "maximum object size %E", |
| exp, idx[i] + 1, |
| argrange[i][0], argrange[i][1], |
| maxobjsize); |
| } |
| } |
| } |
| |
| if (!argrange[0]) |
| return; |
| |
| /* For a two-argument alloc_size, validate the product of the two |
| arguments if both of their values or ranges are known. */ |
| if (!warned && tree_fits_uhwi_p (argrange[0][0]) |
| && argrange[1][0] && tree_fits_uhwi_p (argrange[1][0]) |
| && !integer_onep (argrange[0][0]) |
| && !integer_onep (argrange[1][0])) |
| { |
| /* Check for overflow in the product of a function decorated with |
| attribute alloc_size (X, Y). */ |
| unsigned szprec = TYPE_PRECISION (size_type_node); |
| wide_int x = wi::to_wide (argrange[0][0], szprec); |
| wide_int y = wi::to_wide (argrange[1][0], szprec); |
| |
| bool vflow; |
| wide_int prod = wi::umul (x, y, &vflow); |
| |
| if (vflow) |
| warned = warning_at (loc, OPT_Walloc_size_larger_than_, |
| "%Kproduct %<%E * %E%> of arguments %i and %i " |
| "exceeds %<SIZE_MAX%>", |
| exp, argrange[0][0], argrange[1][0], |
| idx[0] + 1, idx[1] + 1); |
| else if (wi::ltu_p (wi::to_wide (maxobjsize, szprec), prod)) |
| warned = warning_at (loc, OPT_Walloc_size_larger_than_, |
| "%Kproduct %<%E * %E%> of arguments %i and %i " |
| "exceeds maximum object size %E", |
| exp, argrange[0][0], argrange[1][0], |
| idx[0] + 1, idx[1] + 1, |
| maxobjsize); |
| |
| if (warned) |
| { |
| /* Print the full range of each of the two arguments to make |
| it clear when it is, in fact, in a range and not constant. */ |
| if (argrange[0][0] != argrange [0][1]) |
| inform (loc, "argument %i in the range [%E, %E]", |
| idx[0] + 1, argrange[0][0], argrange[0][1]); |
| if (argrange[1][0] != argrange [1][1]) |
| inform (loc, "argument %i in the range [%E, %E]", |
| idx[1] + 1, argrange[1][0], argrange[1][1]); |
| } |
| } |
| |
| if (warned) |
| { |
| location_t fnloc = DECL_SOURCE_LOCATION (fn); |
| |
| if (DECL_IS_BUILTIN (fn)) |
| inform (loc, |
| "in a call to built-in allocation function %qD", fn); |
| else |
| inform (fnloc, |
| "in a call to allocation function %qD declared here", fn); |
| } |
| } |
| |
| /* Issue an error if CALL_EXPR was flagged as requiring |
| tall-call optimization. */ |
| |
| static void |
| maybe_complain_about_tail_call (tree call_expr, const char *reason) |
| { |
| gcc_assert (TREE_CODE (call_expr) == CALL_EXPR); |
| if (!CALL_EXPR_MUST_TAIL_CALL (call_expr)) |
| return; |
| |
| error_at (EXPR_LOCATION (call_expr), "cannot tail-call: %s", reason); |
| } |
| |
| /* Fill in ARGS_SIZE and ARGS array based on the parameters found in |
| CALL_EXPR EXP. |
| |
| NUM_ACTUALS is the total number of parameters. |
| |
| N_NAMED_ARGS is the total number of named arguments. |
| |
| STRUCT_VALUE_ADDR_VALUE is the implicit argument for a struct return |
| value, or null. |
| |
| FNDECL is the tree code for the target of this call (if known) |
| |
| ARGS_SO_FAR holds state needed by the target to know where to place |
| the next argument. |
| |
| REG_PARM_STACK_SPACE is the number of bytes of stack space reserved |
| for arguments which are passed in registers. |
| |
| OLD_STACK_LEVEL is a pointer to an rtx which olds the old stack level |
| and may be modified by this routine. |
| |
| OLD_PENDING_ADJ, MUST_PREALLOCATE and FLAGS are pointers to integer |
| flags which may be modified by this routine. |
| |
| MAY_TAILCALL is cleared if we encounter an invisible pass-by-reference |
| that requires allocation of stack space. |
| |
| CALL_FROM_THUNK_P is true if this call is the jump from a thunk to |
| the thunked-to function. */ |
| |
| static void |
| initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, |
| struct arg_data *args, |
| struct args_size *args_size, |
| int n_named_args ATTRIBUTE_UNUSED, |
| tree exp, tree struct_value_addr_value, |
| tree fndecl, tree fntype, |
| cumulative_args_t args_so_far, |
| 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) |
| { |
| CUMULATIVE_ARGS *args_so_far_pnt = get_cumulative_args (args_so_far); |
| location_t loc = EXPR_LOCATION (exp); |
| |
| /* Count arg position in order args appear. */ |
| int argpos; |
| |
| int i; |
| |
| args_size->constant = 0; |
| args_size->var = 0; |
| |
| bitmap_obstack_initialize (NULL); |
| |
| /* In this loop, we consider args in the order they are written. |
| We fill up ARGS from the back. */ |
| |
| i = num_actuals - 1; |
| { |
| int j = i, ptr_arg = -1; |
| call_expr_arg_iterator iter; |
| tree arg; |
| bitmap slots = NULL; |
| |
| if (struct_value_addr_value) |
| { |
| args[j].tree_value = struct_value_addr_value; |
| j--; |
| |
| /* If we pass structure address then we need to |
| create bounds for it. Since created bounds is |
| a call statement, we expand it right here to avoid |
| fixing all other places where it may be expanded. */ |
| if (CALL_WITH_BOUNDS_P (exp)) |
| { |
| args[j].value = gen_reg_rtx (targetm.chkp_bound_mode ()); |
| args[j].tree_value |
| = chkp_make_bounds_for_struct_addr (struct_value_addr_value); |
| expand_expr_real (args[j].tree_value, args[j].value, VOIDmode, |
| EXPAND_NORMAL, 0, false); |
| args[j].pointer_arg = j + 1; |
| j--; |
| } |
| } |
| argpos = 0; |
| FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) |
| { |
| tree argtype = TREE_TYPE (arg); |
| |
| /* Remember last param with pointer and associate it |
| with following pointer bounds. */ |
| if (CALL_WITH_BOUNDS_P (exp) |
| && chkp_type_has_pointer (argtype)) |
| { |
| if (slots) |
| BITMAP_FREE (slots); |
| ptr_arg = j; |
| if (!BOUNDED_TYPE_P (argtype)) |
| { |
| slots = BITMAP_ALLOC (NULL); |
| chkp_find_bound_slots (argtype, slots); |
| } |
| } |
| else if (CALL_WITH_BOUNDS_P (exp) |
| && pass_by_reference (NULL, TYPE_MODE (argtype), argtype, |
| argpos < n_named_args)) |
| { |
| if (slots) |
| BITMAP_FREE (slots); |
| ptr_arg = j; |
| } |
| else if (POINTER_BOUNDS_TYPE_P (argtype)) |
| { |
| /* We expect bounds in instrumented calls only. |
| Otherwise it is a sign we lost flag due to some optimization |
| and may emit call args incorrectly. */ |
| gcc_assert (CALL_WITH_BOUNDS_P (exp)); |
| |
| /* For structures look for the next available pointer. */ |
| if (ptr_arg != -1 && slots) |
| { |
| unsigned bnd_no = bitmap_first_set_bit (slots); |
| args[j].pointer_offset = |
| bnd_no * POINTER_SIZE / BITS_PER_UNIT; |
| |
| bitmap_clear_bit (slots, bnd_no); |
| |
| /* Check we have no more pointers in the structure. */ |
| if (bitmap_empty_p (slots)) |
| BITMAP_FREE (slots); |
| } |
| args[j].pointer_arg = ptr_arg; |
| |
| /* Check we covered all pointers in the previous |
| non bounds arg. */ |
| if (!slots) |
| ptr_arg = -1; |
| } |
| else |
| ptr_arg = -1; |
| |
| if (targetm.calls.split_complex_arg |
| && argtype |
| && TREE_CODE (argtype) == COMPLEX_TYPE |
| && targetm.calls.split_complex_arg (argtype)) |
| { |
| tree subtype = TREE_TYPE (argtype); |
| args[j].tree_value = build1 (REALPART_EXPR, subtype, arg); |
| j--; |
| args[j].tree_value = build1 (IMAGPART_EXPR, subtype, arg); |
| } |
| else |
| args[j].tree_value = arg; |
| j--; |
| argpos++; |
| } |
| |
| if (slots) |
| BITMAP_FREE (slots); |
| } |
| |
| bitmap_obstack_release (NULL); |
| |
| /* Extract attribute alloc_size and if set, store the indices of |
| the corresponding arguments in ALLOC_IDX, and then the actual |
| argument(s) at those indices in ALLOC_ARGS. */ |
| int alloc_idx[2] = { -1, -1 }; |
| if (tree alloc_size |
| = (fndecl ? lookup_attribute ("alloc_size", |
| TYPE_ATTRIBUTES (TREE_TYPE (fndecl))) |
| : NULL_TREE)) |
| { |
| tree args = TREE_VALUE (alloc_size); |
| alloc_idx[0] = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1; |
| if (TREE_CHAIN (args)) |
| alloc_idx[1] = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (args))) - 1; |
| } |
| |
| /* Array for up to the two attribute alloc_size arguments. */ |
| tree alloc_args[] = { NULL_TREE, NULL_TREE }; |
| |
| /* I counts args in order (to be) pushed; ARGPOS counts in order written. */ |
| for (argpos = 0; argpos < num_actuals; i--, argpos++) |
| { |
| tree type = TREE_TYPE (args[i].tree_value); |
| int unsignedp; |
| machine_mode mode; |
| |
| /* Replace erroneous argument with constant zero. */ |
| if (type == error_mark_node || !COMPLETE_TYPE_P (type)) |
| args[i].tree_value = integer_zero_node, type = integer_type_node; |
| |
| /* If TYPE is a transparent union or record, pass things the way |
| we would pass the first field of the union or record. We have |
| already verified that the modes are the same. */ |
| if ((TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == RECORD_TYPE) |
| && TYPE_TRANSPARENT_AGGR (type)) |
| type = TREE_TYPE (first_field (type)); |
| |
| /* Decide where to pass this arg. |
| |
| args[i].reg is nonzero if all or part is passed in registers. |
| |
| args[i].partial is nonzero if part but not all is passed in registers, |
| and the exact value says how many bytes are passed in registers. |
| |
| args[i].pass_on_stack is nonzero if the argument must at least be |
| computed on the stack. It may then be loaded back into registers |
| if args[i].reg is nonzero. |
| |
| These decisions are driven by the FUNCTION_... macros and must agree |
| with those made by function.c. */ |
| |
| /* See if this argument should be passed by invisible reference. */ |
| if (pass_by_reference (args_so_far_pnt, TYPE_MODE (type), |
| type, argpos < n_named_args)) |
| { |
| bool callee_copies; |
| tree base = NULL_TREE; |
| |
| callee_copies |
| = reference_callee_copied (args_so_far_pnt, TYPE_MODE (type), |
| type, argpos < n_named_args); |
| |
| /* If we're compiling a thunk, pass through invisible references |
| instead of making a copy. */ |
| if (call_from_thunk_p |
| || (callee_copies |
| && !TREE_ADDRESSABLE (type) |
| && (base = get_base_address (args[i].tree_value)) |
| && TREE_CODE (base) != SSA_NAME |
| && (!DECL_P (base) || MEM_P (DECL_RTL (base))))) |
| { |
| /* We may have turned the parameter value into an SSA name. |
| Go back to the original parameter so we can take the |
| address. */ |
| if (TREE_CODE (args[i].tree_value) == SSA_NAME) |
| { |
| gcc_assert (SSA_NAME_IS_DEFAULT_DEF (args[i].tree_value)); |
| args[i].tree_value = SSA_NAME_VAR (args[i].tree_value); |
| gcc_assert (TREE_CODE (args[i].tree_value) == PARM_DECL); |
| } |
| /* Argument setup code may have copied the value to register. We |
| revert that optimization now because the tail call code must |
| use the original location. */ |
| if (TREE_CODE (args[i].tree_value) == PARM_DECL |
| && !MEM_P (DECL_RTL (args[i].tree_value)) |
| && DECL_INCOMING_RTL (args[i].tree_value) |
| && MEM_P (DECL_INCOMING_RTL (args[i].tree_value))) |
| set_decl_rtl (args[i].tree_value, |
| DECL_INCOMING_RTL (args[i].tree_value)); |
| |
| mark_addressable (args[i].tree_value); |
| |
| /* We can't use sibcalls if a callee-copied argument is |
| stored in the current function's frame. */ |
| if (!call_from_thunk_p && DECL_P (base) && !TREE_STATIC (base)) |
| { |
| *may_tailcall = false; |
| maybe_complain_about_tail_call (exp, |
| "a callee-copied argument is" |
| " stored in the current " |
| " function's frame"); |
| } |
| |
| args[i].tree_value = build_fold_addr_expr_loc (loc, |
| args[i].tree_value); |
| type = TREE_TYPE (args[i].tree_value); |
| |
| if (*ecf_flags & ECF_CONST) |
| *ecf_flags &= ~(ECF_CONST | ECF_LOOPING_CONST_OR_PURE); |
| } |
| else |
| { |
| /* We make a copy of the object and pass the address to the |
| function being called. */ |
| rtx copy; |
| |
| if (!COMPLETE_TYPE_P (type) |
| || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST |
| || (flag_stack_check == GENERIC_STACK_CHECK |
| && compare_tree_int (TYPE_SIZE_UNIT (type), |
| STACK_CHECK_MAX_VAR_SIZE) > 0)) |
| { |
| /* This is a variable-sized object. Make space on the stack |
| for it. */ |
| rtx size_rtx = expr_size (args[i].tree_value); |
| |
| if (*old_stack_level == 0) |
| { |
| emit_stack_save (SAVE_BLOCK, old_stack_level); |
| *old_pending_adj = pending_stack_adjust; |
| pending_stack_adjust = 0; |
| } |
| |
| /* We can pass TRUE as the 4th argument because we just |
| saved the stack pointer and will restore it right after |
| the call. */ |
| copy = allocate_dynamic_stack_space (size_rtx, |
| TYPE_ALIGN (type), |
| TYPE_ALIGN (type), |
| true); |
| copy = gen_rtx_MEM (BLKmode, copy); |
| set_mem_attributes (copy, type, 1); |
| } |
| else |
| copy = assign_temp (type, 1, 0); |
| |
| store_expr (args[i].tree_value, copy, 0, false, false); |
| |
| /* Just change the const function to pure and then let |
| the next test clear the pure based on |
| callee_copies. */ |
| if (*ecf_flags & ECF_CONST) |
| { |
| *ecf_flags &= ~ECF_CONST; |
| *ecf_flags |= ECF_PURE; |
| } |
| |
| if (!callee_copies && *ecf_flags & ECF_PURE) |
| *ecf_flags &= ~(ECF_PURE | ECF_LOOPING_CONST_OR_PURE); |
| |
| args[i].tree_value |
| = build_fold_addr_expr_loc (loc, make_tree (type, copy)); |
| type = TREE_TYPE (args[i].tree_value); |
| *may_tailcall = false; |
| maybe_complain_about_tail_call (exp, |
| "argument must be passed" |
| " by copying"); |
| } |
| } |
| |
| unsignedp = TYPE_UNSIGNED (type); |
| mode = promote_function_mode (type, TYPE_MODE (type), &unsignedp, |
| fndecl ? TREE_TYPE (fndecl) : fntype, 0); |
| |
| args[i].unsignedp = unsignedp; |
| args[i].mode = mode; |
| |
| args[i].reg = targetm.calls.function_arg (args_so_far, mode, type, |
| argpos < n_named_args); |
| |
| if (args[i].reg && CONST_INT_P (args[i].reg)) |
| { |
| args[i].special_slot = args[i].reg; |
| args[i].reg = NULL; |
| } |
| |
| /* If this is a sibling call and the machine has register windows, the |
| register window has to be unwinded before calling the routine, so |
| arguments have to go into the incoming registers. */ |
| if (targetm.calls.function_incoming_arg != targetm.calls.function_arg) |
| args[i].tail_call_reg |
| = targetm.calls.function_incoming_arg (args_so_far, mode, type, |
| argpos < n_named_args); |
| else |
| args[i].tail_call_reg = args[i].reg; |
| |
| if (args[i].reg) |
| args[i].partial |
| = targetm.calls.arg_partial_bytes (args_so_far, mode, type, |
| argpos < n_named_args); |
| |
| args[i].pass_on_stack = targetm.calls.must_pass_in_stack (mode, type); |
| |
| /* If FUNCTION_ARG returned a (parallel [(expr_list (nil) ...) ...]), |
| it means that we are to pass this arg in the register(s) designated |
| by the PARALLEL, but also to pass it in the stack. */ |
| if (args[i].reg && GET_CODE (args[i].reg) == PARALLEL |
| && XEXP (XVECEXP (args[i].reg, 0, 0), 0) == 0) |
| args[i].pass_on_stack = 1; |
| |
| /* If this is an addressable type, we must preallocate the stack |
| since we must evaluate the object into its final location. |
| |
| If this is to be passed in both registers and the stack, it is simpler |
| to preallocate. */ |
| if (TREE_ADDRESSABLE (type) |
| || (args[i].pass_on_stack && args[i].reg != 0)) |
| *must_preallocate = 1; |
| |
| /* No stack allocation and padding for bounds. */ |
| if (POINTER_BOUNDS_P (args[i].tree_value)) |
| ; |
| /* Compute the stack-size of this argument. */ |
| else if (args[i].reg == 0 || args[i].partial != 0 |
| || reg_parm_stack_space > 0 |
| || args[i].pass_on_stack) |
| locate_and_pad_parm (mode, type, |
| #ifdef STACK_PARMS_IN_REG_PARM_AREA |
| 1, |
| #else |
| args[i].reg != 0, |
| #endif |
| reg_parm_stack_space, |
| args[i].pass_on_stack ? 0 : args[i].partial, |
| fndecl, args_size, &args[i].locate); |
| #ifdef BLOCK_REG_PADDING |
| else |
| /* The argument is passed entirely in registers. See at which |
| end it should be padded. */ |
| args[i].locate.where_pad = |
| BLOCK_REG_PADDING (mode, type, |
| int_size_in_bytes (type) <= UNITS_PER_WORD); |
| #endif |
| |
| /* Update ARGS_SIZE, the total stack space for args so far. */ |
| |
| args_size->constant += args[i].locate.size.constant; |
| if (args[i].locate.size.var) |
| ADD_PARM_SIZE (*args_size, args[i].locate.size.var); |
| |
| /* Increment ARGS_SO_FAR, which has info about which arg-registers |
| have been used, etc. */ |
| |
| targetm.calls.function_arg_advance (args_so_far, TYPE_MODE (type), |
| type, argpos < n_named_args); |
| |
| /* Store argument values for functions decorated with attribute |
| alloc_size. */ |
| if (argpos == alloc_idx[0]) |
| alloc_args[0] = args[i].tree_value; |
| else if (argpos == alloc_idx[1]) |
| alloc_args[1] = args[i].tree_value; |
| } |
| |
| if (alloc_args[0]) |
| { |
| /* Check the arguments of functions decorated with attribute |
| alloc_size. */ |
| maybe_warn_alloc_args_overflow (fndecl, exp, alloc_args, alloc_idx); |
| } |
| } |
| |
| /* Update ARGS_SIZE to contain the total size for the argument block. |
| Return the original constant component of the argument block's size. |
| |
| REG_PARM_STACK_SPACE holds the number of bytes of stack space reserved |
| for arguments passed in registers. */ |
| |
| static int |
| compute_argument_block_size (int reg_parm_stack_space, |
| struct args_size *args_size, |
| tree fndecl ATTRIBUTE_UNUSED, |
| tree fntype ATTRIBUTE_UNUSED, |
| int preferred_stack_boundary ATTRIBUTE_UNUSED) |
| { |
| int unadjusted_args_size = args_size->constant; |
| |
| /* For accumulate outgoing args mode we don't need to align, since the frame |
| will be already aligned. Align to STACK_BOUNDARY in order to prevent |
| backends from generating misaligned frame sizes. */ |
| if (ACCUMULATE_OUTGOING_ARGS && preferred_stack_boundary > STACK_BOUNDARY) |
| preferred_stack_boundary = STACK_BOUNDARY; |
| |
| /* Compute the actual size of the argument block required. The variable |
| and constant sizes must be combined, the size may have to be rounded, |
| and there may be a minimum required size. */ |
| |
| if (args_size->var) |
| { |
| args_size->var = ARGS_SIZE_TREE (*args_size); |
| args_size->constant = 0; |
| |
| preferred_stack_boundary /= BITS_PER_UNIT; |
| if (preferred_stack_boundary > 1) |
| { |
| /* We don't handle this case yet. To handle it correctly we have |
| to add the delta, round and subtract the delta. |
| Currently no machine description requires this support. */ |
| gcc_assert (!(stack_pointer_delta & (preferred_stack_boundary - 1))); |
| args_size->var = round_up (args_size->var, preferred_stack_boundary); |
| } |
| |
| if (reg_parm_stack_space > 0) |
| { |
| args_size->var |
| = size_binop (MAX_EXPR, args_size->var, |
| ssize_int (reg_parm_stack_space)); |
| |
| /* The area corresponding to register parameters is not to count in |
| the size of the block we need. So make the adjustment. */ |
| if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl)))) |
| args_size->var |
| = size_binop (MINUS_EXPR, args_size->var, |
| ssize_int (reg_parm_stack_space)); |
| } |
| } |
| else |
| { |
| preferred_stack_boundary /= BITS_PER_UNIT; |
| if (preferred_stack_boundary < 1) |
| preferred_stack_boundary = 1; |
| args_size->constant = (((args_size->constant |
| + stack_pointer_delta |
| + preferred_stack_boundary - 1) |
| / preferred_stack_boundary |
| * preferred_stack_boundary) |
| - stack_pointer_delta); |
| |
| args_size->constant = MAX (args_size->constant, |
| reg_parm_stack_space); |
| |
| if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl)))) |
| args_size->constant -= reg_parm_stack_space; |
| } |
| return unadjusted_args_size; |
| } |
| |
| /* Precompute parameters as needed for a function call. |
| |
| FLAGS is mask of ECF_* constants. |
| |
| NUM_ACTUALS is the number of arguments. |
| |
| ARGS is an array containing information for each argument; this |
| routine fills in the INITIAL_VALUE and VALUE fields for each |
| precomputed argument. */ |
| |
| static void |
| precompute_arguments (int num_actuals, struct arg_data *args) |
| { |
| int i; |
| |
| /* If this is a libcall, then precompute all arguments so that we do not |
| get extraneous instructions emitted as part of the libcall sequence. */ |
| |
| /* If we preallocated the stack space, and some arguments must be passed |
| on the stack, then we must precompute any parameter which contains a |
| function call which will store arguments on the stack. |
| Otherwise, evaluating the parameter may clobber previous parameters |
| which have already been stored into the stack. (we have code to avoid |
| such case by saving the outgoing stack arguments, but it results in |
| worse code) */ |
| if (!ACCUMULATE_OUTGOING_ARGS) |
| return; |
| |
| for (i = 0; i < num_actuals; i++) |
| { |
| tree type; |
| machine_mode mode; |
| |
| if (TREE_CODE (args[i].tree_value) != CALL_EXPR) |
| continue; |
| |
| /* If this is an addressable type, we cannot pre-evaluate it. */ |
| type = TREE_TYPE (args[i].tree_value); |
| gcc_assert (!TREE_ADDRESSABLE (type)); |
| |
| args[i].initial_value = args[i].value |
| = expand_normal (args[i].tree_value); |
| |
| mode = TYPE_MODE (type); |
| if (mode != args[i].mode) |
| { |
| int unsignedp = args[i].unsignedp; |
| args[i].value |
| = convert_modes (args[i].mode, mode, |
| args[i].value, args[i].unsignedp); |
| |
| /* CSE will replace this only if it contains args[i].value |
| pseudo, so convert it down to the declared mode using |
| a SUBREG. */ |
| if (REG_P (args[i].value) |
| && GET_MODE_CLASS (args[i].mode) == MODE_INT |
| && promote_mode (type, mode, &unsignedp) != args[i].mode) |
| { |
| args[i].initial_value |
| = gen_lowpart_SUBREG (mode, args[i].value); |
| SUBREG_PROMOTED_VAR_P (args[i].initial_value) = 1; |
| SUBREG_PROMOTED_SET (args[i].initial_value, args[i].unsignedp); |
| } |
| } |
| } |
| } |
| |
| /* Given the current state of MUST_PREALLOCATE and information about |
| arguments to a function call in NUM_ACTUALS, ARGS and ARGS_SIZE, |
| compute and return the final value for MUST_PREALLOCATE. */ |
| |
| static int |
| finalize_must_preallocate (int must_preallocate, int num_actuals, |
| struct arg_data *args, struct args_size *args_size) |
| { |
| /* See if we have or want to preallocate stack space. |
| |
| If we would have to push a partially-in-regs parm |
| before other stack parms, preallocate stack space instead. |
| |
| If the size of some parm is not a multiple of the required stack |
| alignment, we must preallocate. |
| |
| If the total size of arguments that would otherwise create a copy in |
| a temporary (such as a CALL) is more than half the total argument list |
| size, preallocation is faster. |
| |
| Another reason to preallocate is if we have a machine (like the m88k) |
| where stack alignment is required to be maintained between every |
| pair of insns, not just when the call is made. However, we assume here |
| that such machines either do not have push insns (and hence preallocation |
| would occur anyway) or the problem is taken care of with |
| PUSH_ROUNDING. */ |
| |
| if (! must_preallocate) |
| { |
| int partial_seen = 0; |
| int copy_to_evaluate_size = 0; |
| int i; |
| |
| for (i = 0; i < num_actuals && ! must_preallocate; i++) |
| { |
| if (args[i].partial > 0 && ! args[i].pass_on_stack) |
| partial_seen = 1; |
| else if (partial_seen && args[i].reg == 0) |
| must_preallocate = 1; |
| /* We preallocate in case there are bounds passed |
| in the bounds table to have precomputed address |
| for bounds association. */ |
| else if (POINTER_BOUNDS_P (args[i].tree_value) |
| && !args[i].reg) |
| must_preallocate = 1; |
| |
| if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode |
| && (TREE_CODE (args[i].tree_value) == CALL_EXPR |
| || TREE_CODE (args[i].tree_value) == TARGET_EXPR |
| || TREE_CODE (args[i].tree_value) == COND_EXPR |
| || TREE_ADDRESSABLE (TREE_TYPE (args[i].tree_value)))) |
| copy_to_evaluate_size |
| += int_size_in_bytes (TREE_TYPE (args[i].tree_value)); |
| } |
| |
| if (copy_to_evaluate_size * 2 >= args_size->constant |
| && args_size->constant > 0) |
| must_preallocate = 1; |
| } |
| return must_preallocate; |
| } |
| |
| /* If we preallocated stack space, compute the address of each argument |
| and store it into the ARGS array. |
| |
| We need not ensure it is a valid memory address here; it will be |
| validized when it is used. |
| |
| ARGBLOCK is an rtx for the address of the outgoing arguments. */ |
| |
| static void |
| compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals) |
| { |
| if (argblock) |
| { |
| rtx arg_reg = argblock; |
| int i, arg_offset = 0; |
| |
| if (GET_CODE (argblock) == PLUS) |
| arg_reg = XEXP (argblock, 0), arg_offset = INTVAL (XEXP (argblock, 1)); |
| |
| for (i = 0; i < num_actuals; i++) |
| { |
| rtx offset = ARGS_SIZE_RTX (args[i].locate.offset); |
| rtx slot_offset = ARGS_SIZE_RTX (args[i].locate.slot_offset); |
| rtx addr; |
| unsigned int align, boundary; |
| unsigned int units_on_stack = 0; |
| machine_mode partial_mode = VOIDmode; |
| |
| /* Skip this parm if it will not be passed on the stack. */ |
| if (! args[i].pass_on_stack |
| && args[i].reg != 0 |
| && args[i].partial == 0) |
| continue; |
| |
| /* Pointer Bounds are never passed on the stack. */ |
| if (POINTER_BOUNDS_P (args[i].tree_value)) |
| continue; |
| |
| if (CONST_INT_P (offset)) |
| addr = plus_constant (Pmode, arg_reg, INTVAL (offset)); |
| else |
| addr = gen_rtx_PLUS (Pmode, arg_reg, offset); |
| |
| addr = plus_constant (Pmode, addr, arg_offset); |
| |
| if (args[i].partial != 0) |
| { |
| /* Only part of the parameter is being passed on the stack. |
| Generate a simple memory reference of the correct size. */ |
| units_on_stack = args[i].locate.size.constant; |
| partial_mode = mode_for_size (units_on_stack * BITS_PER_UNIT, |
| MODE_INT, 1); |
| args[i].stack = gen_rtx_MEM (partial_mode, addr); |
| set_mem_size (args[i].stack, units_on_stack); |
| } |
| else |
| { |
| args[i].stack = gen_rtx_MEM (args[i].mode, addr); |
| set_mem_attributes (args[i].stack, |
| TREE_TYPE (args[i].tree_value), 1); |
| } |
| align = BITS_PER_UNIT; |
| boundary = args[i].locate.boundary; |
| if (args[i].locate.where_pad != downward) |
| align = boundary; |
| else if (CONST_INT_P (offset)) |
| { |
| align = INTVAL (offset) * BITS_PER_UNIT | boundary; |
| align = least_bit_hwi (align); |
| } |
| set_mem_align (args[i].stack, align); |
| |
| if (CONST_INT_P (slot_offset)) |
| addr = plus_constant (Pmode, arg_reg, INTVAL (slot_offset)); |
| else |
| addr = gen_rtx_PLUS (Pmode, arg_reg, slot_offset); |
| |
| addr = plus_constant (Pmode, addr, arg_offset); |
| |
| if (args[i].partial != 0) |
| { |
| /* Only part of the parameter is being passed on the stack. |
| Generate a simple memory reference of the correct size. |
| */ |
| args[i].stack_slot = gen_rtx_MEM (partial_mode, addr); |
| set_mem_size (args[i].stack_slot, units_on_stack); |
| } |
| else |
| { |
| args[i].stack_slot = gen_rtx_MEM (args[i].mode, addr); |
| set_mem_attributes (args[i].stack_slot, |
| TREE_TYPE (args[i].tree_value), 1); |
| } |
| set_mem_align (args[i].stack_slot, args[i].locate.boundary); |
| |
| /* Function incoming arguments may overlap with sibling call |
| outgoing arguments and we cannot allow reordering of reads |
| from function arguments with stores to outgoing arguments |
| of sibling calls. */ |
| set_mem_alias_set (args[i].stack, 0); |
| set_mem_alias_set (args[i].stack_slot, 0); |
| } |
| } |
| } |
| |
| /* Given a FNDECL and EXP, return an rtx suitable for use as a target address |
| in a call instruction. |
| |
| FNDECL is the tree node for the target function. For an indirect call |
| FNDECL will be NULL_TREE. |
| |
| ADDR is the operand 0 of CALL_EXPR for this call. */ |
| |
| static rtx |
| rtx_for_function_call (tree fndecl, tree addr) |
| { |
| rtx funexp; |
| |
| /* Get the function to call, in the form of RTL. */ |
| if (fndecl) |
| { |
| if (!TREE_USED (fndecl) && fndecl != current_function_decl) |
| TREE_USED (fndecl) = 1; |
| |
| /* Get a SYMBOL_REF rtx for the function address. */ |
| funexp = XEXP (DECL_RTL (fndecl), 0); |
| } |
| else |
| /* Generate an rtx (probably a pseudo-register) for the address. */ |
| { |
| push_temp_slots (); |
| funexp = expand_normal (addr); |
| pop_temp_slots (); /* FUNEXP can't be BLKmode. */ |
| } |
| return funexp; |
| } |
| |
| /* Internal state for internal_arg_pointer_based_exp and its helpers. */ |
| static struct |
| { |
| /* Last insn that has been scanned by internal_arg_pointer_based_exp_scan, |
| or NULL_RTX if none has been scanned yet. */ |
| rtx_insn *scan_start; |
| /* Vector indexed by REGNO - FIRST_PSEUDO_REGISTER, recording if a pseudo is |
| based on crtl->args.internal_arg_pointer. The element is NULL_RTX if the |
| pseudo isn't based on it, a CONST_INT offset if the pseudo is based on it |
| with fixed offset, or PC if this is with variable or unknown offset. */ |
| vec<rtx> cache; |
| } internal_arg_pointer_exp_state; |
| |
| static rtx internal_arg_pointer_based_exp (const_rtx, bool); |
| |
| /* Helper function for internal_arg_pointer_based_exp. Scan insns in |
| the tail call sequence, starting with first insn that hasn't been |
| scanned yet, and note for each pseudo on the LHS whether it is based |
| on crtl->args.internal_arg_pointer or not, and what offset from that |
| that pointer it has. */ |
| |
| static void |
| internal_arg_pointer_based_exp_scan (void) |
| { |
| rtx_insn *insn, *scan_start = internal_arg_pointer_exp_state.scan_start; |
| |
| if (scan_start == NULL_RTX) |
| insn = get_insns (); |
| else |
| insn = NEXT_INSN (scan_start); |
| |
| while (insn) |
| { |
| rtx set = single_set (insn); |
| if (set && REG_P (SET_DEST (set)) && !HARD_REGISTER_P (SET_DEST (set))) |
| { |
| rtx val = NULL_RTX; |
| unsigned int idx = REGNO (SET_DEST (set)) - FIRST_PSEUDO_REGISTER; |
| /* Punt on pseudos set multiple times. */ |
| if (idx < internal_arg_pointer_exp_state.cache.length () |
| && (internal_arg_pointer_exp_state.cache[idx] |
| != NULL_RTX)) |
| val = pc_rtx; |
| else |
| val = internal_arg_pointer_based_exp (SET_SRC (set), false); |
| if (val != NULL_RTX) |
| { |
| if (idx >= internal_arg_pointer_exp_state.cache.length ()) |
| internal_arg_pointer_exp_state.cache |
| .safe_grow_cleared (idx + 1); |
| internal_arg_pointer_exp_state.cache[idx] = val; |
| } |
| } |
| if (NEXT_INSN (insn) == NULL_RTX) |
| scan_start = insn; |
| insn = NEXT_INSN (insn); |
| } |
| |
| internal_arg_pointer_exp_state.scan_start = scan_start; |
| } |
| |
| /* Compute whether RTL is based on crtl->args.internal_arg_pointer. Return |
| NULL_RTX if RTL isn't based on it, a CONST_INT offset if RTL is based on |
| it with fixed offset, or PC if this is with variable or unknown offset. |
| TOPLEVEL is true if the function is invoked at the topmost level. */ |
| |
| static rtx |
| internal_arg_pointer_based_exp (const_rtx rtl, bool toplevel) |
| { |
| if (CONSTANT_P (rtl)) |
| return NULL_RTX; |
| |
| if (rtl == crtl->args.internal_arg_pointer) |
| return const0_rtx; |
| |
| if (REG_P (rtl) && HARD_REGISTER_P (rtl)) |
| return NULL_RTX; |
| |
| if (GET_CODE (rtl) == PLUS && CONST_INT_P (XEXP (rtl, 1))) |
| { |
| rtx val = internal_arg_pointer_based_exp (XEXP (rtl, 0), toplevel); |
| if (val == NULL_RTX || val == pc_rtx) |
| return val; |
| return plus_constant (Pmode, val, INTVAL (XEXP (rtl, 1))); |
| } |
| |
| /* When called at the topmost level, scan pseudo assignments in between the |
| last scanned instruction in the tail call sequence and the latest insn |
| in that sequence. */ |
| if (toplevel) |
| internal_arg_pointer_based_exp_scan (); |
| |
| if (REG_P (rtl)) |
| { |
| unsigned int idx = REGNO (rtl) - FIRST_PSEUDO_REGISTER; |
| if (idx < internal_arg_pointer_exp_state.cache.length ()) |
| return internal_arg_pointer_exp_state.cache[idx]; |
| |
| return NULL_RTX; |
| } |
| |
| subrtx_iterator::array_type array; |
| FOR_EACH_SUBRTX (iter, array, rtl, NONCONST) |
| { |
| const_rtx x = *iter; |
| if (REG_P (x) && internal_arg_pointer_based_exp (x, false) != NULL_RTX) |
| return pc_rtx; |
| if (MEM_P (x)) |
| iter.skip_subrtxes (); |
| } |
| |
| return NULL_RTX; |
| } |
| |
| /* Return true if and only if SIZE storage units (usually bytes) |
| starting from address ADDR overlap with already clobbered argument |
| area. This function is used to determine if we should give up a |
| sibcall. */ |
| |
| static bool |
| mem_overlaps_already_clobbered_arg_p (rtx addr, unsigned HOST_WIDE_INT size) |
| { |
| HOST_WIDE_INT i; |
| rtx val; |
| |
| if (bitmap_empty_p (stored_args_map)) |
| return false; |
| val = internal_arg_pointer_based_exp (addr, true); |
| if (val == NULL_RTX) |
| return false; |
| else if (val == pc_rtx) |
| return true; |
| else |
| i = INTVAL (val); |
| |
| if (STACK_GROWS_DOWNWARD) |
| i -= crtl->args.pretend_args_size; |
| else |
| i += crtl->args.pretend_args_size; |
| |
| |
| if (ARGS_GROW_DOWNWARD) |
| i = -i - size; |
| |
| if (size > 0) |
| { |
| unsigned HOST_WIDE_INT k; |
| |
| for (k = 0; k < size; k++) |
| if (i + k < SBITMAP_SIZE (stored_args_map) |
| && bitmap_bit_p (stored_args_map, i + k)) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /* Do the register loads required for any wholly-register parms or any |
| parms which are passed both on the stack and in a register. Their |
| expressions were already evaluated. |
| |
| Mark all register-parms as living through the call, putting these USE |
| insns in the CALL_INSN_FUNCTION_USAGE field. |
| |
| When IS_SIBCALL, perform the check_sibcall_argument_overlap |
| checking, setting *SIBCALL_FAILURE if appropriate. */ |
| |
| static void |
| load_register_parameters (struct arg_data *args, int num_actuals, |
| rtx *call_fusage, int flags, int is_sibcall, |
| int *sibcall_failure) |
| { |
| int i, j; |
| |
| for (i = 0; i < num_actuals; i++) |
| { |
| rtx reg = ((flags & ECF_SIBCALL) |
| ? args[i].tail_call_reg : args[i].reg); |
| if (reg) |
| { |
| int partial = args[i].partial; |
| int nregs; |
| int size = 0; |
| rtx_insn *before_arg = get_last_insn (); |
| /* Set non-negative if we must move a word at a time, even if |
| just one word (e.g, partial == 4 && mode == DFmode). Set |
| to -1 if we just use a normal move insn. This value can be |
| zero if the argument is a zero size structure. */ |
| nregs = -1; |
| if (GET_CODE (reg) == PARALLEL) |
| ; |
| else if (partial) |
| { |
| gcc_assert (partial % UNITS_PER_WORD == 0); |
| nregs = partial / UNITS_PER_WORD; |
| } |
| else if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode) |
| { |
| size = int_size_in_bytes (TREE_TYPE (args[i].tree_value)); |
| nregs = (size + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD; |
| } |
| else |
| size = GET_MODE_SIZE (args[i].mode); |
| |
| /* Handle calls that pass values in multiple non-contiguous |
| locations. The Irix 6 ABI has examples of this. */ |
| |
| if (GET_CODE (reg) == PARALLEL) |
| emit_group_move (reg, args[i].parallel_value); |
| |
| /* If simple case, just do move. If normal partial, store_one_arg |
| has already loaded the register for us. In all other cases, |
| load the register(s) from memory. */ |
| |
| else if (nregs == -1) |
| { |
| emit_move_insn (reg, args[i].value); |
| #ifdef BLOCK_REG_PADDING |
| /* Handle case where we have a value that needs shifting |
| up to the msb. eg. a QImode value and we're padding |
| upward on a BYTES_BIG_ENDIAN machine. */ |
| if (size < UNITS_PER_WORD |
| && (args[i].locate.where_pad |
| == (BYTES_BIG_ENDIAN ? upward : downward))) |
| { |
| rtx x; |
| int shift = (UNITS_PER_WORD - size) * BITS_PER_UNIT; |
| |
| /* Assigning REG here rather than a temp makes CALL_FUSAGE |
| report the whole reg as used. Strictly speaking, the |
| call only uses SIZE bytes at the msb end, but it doesn't |
| seem worth generating rtl to say that. */ |
| reg = gen_rtx_REG (word_mode, REGNO (reg)); |
| x = expand_shift (LSHIFT_EXPR, word_mode, reg, shift, reg, 1); |
| if (x != reg) |
| emit_move_insn (reg, x); |
| } |
| #endif |
| } |
| |
| /* If we have pre-computed the values to put in the registers in |
| the case of non-aligned structures, copy them in now. */ |
| |
| else if (args[i].n_aligned_regs != 0) |
| for (j = 0; j < args[i].n_aligned_regs; j++) |
| emit_move_insn (gen_rtx_REG (word_mode, REGNO (reg) + j), |
| args[i].aligned_regs[j]); |
| |
| else if (partial == 0 || args[i].pass_on_stack) |
| { |
| rtx mem = validize_mem (copy_rtx (args[i].value)); |
| |
| /* Check for overlap with already clobbered argument area, |
| providing that this has non-zero size. */ |
| if (is_sibcall |
| && size != 0 |
| && (mem_overlaps_already_clobbered_arg_p |
| (XEXP (args[i].value, 0), size))) |
| *sibcall_failure = 1; |
| |
| if (size % UNITS_PER_WORD == 0 |
| || MEM_ALIGN (mem) % BITS_PER_WORD == 0) |
| move_block_to_reg (REGNO (reg), mem, nregs, args[i].mode); |
| else |
| { |
| if (nregs > 1) |
| move_block_to_reg (REGNO (reg), mem, nregs - 1, |
| args[i].mode); |
| rtx dest = gen_rtx_REG (word_mode, REGNO (reg) + nregs - 1); |
| unsigned int bitoff = (nregs - 1) * BITS_PER_WORD; |
| unsigned int bitsize = size * BITS_PER_UNIT - bitoff; |
| rtx x = extract_bit_field (mem, bitsize, bitoff, 1, dest, |
| word_mode, word_mode, false); |
| if (BYTES_BIG_ENDIAN) |
| x = expand_shift (LSHIFT_EXPR, word_mode, x, |
| BITS_PER_WORD - bitsize, dest, 1); |
| if (x != dest) |
| emit_move_insn (dest, x); |
| } |
| |
| /* Handle a BLKmode that needs shifting. */ |
| if (nregs == 1 && size < UNITS_PER_WORD |
| #ifdef BLOCK_REG_PADDING |
| && args[i].locate.where_pad == downward |
| #else |
| && BYTES_BIG_ENDIAN |
| #endif |
| ) |
| { |
| rtx dest = gen_rtx_REG (word_mode, REGNO (reg)); |
| int shift = (UNITS_PER_WORD - size) * BITS_PER_UNIT; |
| enum tree_code dir = (BYTES_BIG_ENDIAN |
| ? RSHIFT_EXPR : LSHIFT_EXPR); |
| rtx x; |
| |
| x = expand_shift (dir, word_mode, dest, shift, dest, 1); |
| if (x != dest) |
| emit_move_insn (dest, x); |
| } |
| } |
| |
| /* When a parameter is a block, and perhaps in other cases, it is |
| possible that it did a load from an argument slot that was |
| already clobbered. */ |
| if (is_sibcall |
| && check_sibcall_argument_overlap (before_arg, &args[i], 0)) |
| *sibcall_failure = 1; |
| |
| /* Handle calls that pass values in multiple non-contiguous |
| locations. The Irix 6 ABI has examples of this. */ |
| if (GET_CODE (reg) == PARALLEL) |
| use_group_regs (call_fusage, reg); |
| else if (nregs == -1) |
| use_reg_mode (call_fusage, reg, |
| TYPE_MODE (TREE_TYPE (args[i].tree_value))); |
| else if (nregs > 0) |
| use_regs (call_fusage, REGNO (reg), nregs); |
| } |
| } |
| } |
| |
| /* We need to pop PENDING_STACK_ADJUST bytes. But, if the arguments |
| wouldn't fill up an even multiple of PREFERRED_UNIT_STACK_BOUNDARY |
| bytes, then we would need to push some additional bytes to pad the |
| arguments. So, we compute an adjust to the stack pointer for an |
| amount that will leave the stack under-aligned by UNADJUSTED_ARGS_SIZE |
| bytes. Then, when the arguments are pushed the stack will be perfectly |
| aligned. ARGS_SIZE->CONSTANT is set to the number of bytes that should |
| be popped after the call. Returns the adjustment. */ |
| |
| static int |
| combine_pending_stack_adjustment_and_call (int unadjusted_args_size, |
| struct args_size *args_size, |
| 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. */ |
| unsigned HOST_WIDE_INT unadjusted_alignment; |
| |
| unadjusted_alignment |
| = ((stack_pointer_delta + unadjusted_args_size) |
| % preferred_unit_stack_boundary); |
| |
| /* We want to get rid of as many of the PENDING_STACK_ADJUST bytes |
| as possible -- leaving just enough left to cancel out the |
| UNADJUSTED_ALIGNMENT. In other words, we want to ensure that the |
| PENDING_STACK_ADJUST is non-negative, and congruent to |
| -UNADJUSTED_ALIGNMENT modulo the PREFERRED_UNIT_STACK_BOUNDARY. */ |
| |
| /* Begin by trying to pop all the bytes. */ |
| unadjusted_alignment |
| = (unadjusted_alignment |
| - (pending_stack_adjust % preferred_unit_stack_boundary)); |
| adjustment = pending_stack_adjust; |
| /* Push enough additional bytes that the stack will be aligned |
| after the arguments are pushed. */ |
| if (preferred_unit_stack_boundary > 1) |
| { |
| if (unadjusted_alignment > 0) |
| adjustment -= preferred_unit_stack_boundary - unadjusted_alignment; |
| else |
| adjustment += unadjusted_alignment; |
| } |
| |
| /* Now, sets ARGS_SIZE->CONSTANT so that we pop the right number of |
| bytes after the call. The right number is the entire |
| PENDING_STACK_ADJUST less our ADJUSTMENT plus the amount required |
| by the arguments in the first place. */ |
| args_size->constant |
| = pending_stack_adjust - adjustment + unadjusted_args_size; |
| |
| return adjustment; |
| } |
| |
| /* Scan X expression if it does not dereference any argument slots |
| we already clobbered by tail call arguments (as noted in stored_args_map |
| bitmap). |
| Return nonzero if X expression dereferences such argument slots, |
| zero otherwise. */ |
| |
| static int |
| check_sibcall_argument_overlap_1 (rtx x) |
| { |
| RTX_CODE code; |
| int i, j; |
| const char *fmt; |
| |
| if (x == NULL_RTX) |
| return 0; |
| |
| code = GET_CODE (x); |
| |
| /* We need not check the operands of the CALL expression itself. */ |
| if (code == CALL) |
| return 0; |
| |
| if (code == MEM) |
| return mem_overlaps_already_clobbered_arg_p (XEXP (x, 0), |
| GET_MODE_SIZE (GET_MODE (x))); |
| |
| /* Scan all subexpressions. */ |
| fmt = GET_RTX_FORMAT (code); |
| for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) |
| { |
| if (*fmt == 'e') |
| { |
| if (check_sibcall_argument_overlap_1 (XEXP (x, i))) |
| return 1; |
| } |
| else if (*fmt == 'E') |
| { |
| for (j = 0; j < XVECLEN (x, i); j++) |
| if (check_sibcall_argument_overlap_1 (XVECEXP (x, i, j))) |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| /* Scan sequence after INSN if it does not dereference any argument slots |
| we already clobbered by tail call arguments (as noted in stored_args_map |
| bitmap). If MARK_STORED_ARGS_MAP, add stack slots for ARG to |
| stored_args_map bitmap afterwards (when ARG is a register MARK_STORED_ARGS_MAP |
| should be 0). Return nonzero if sequence after INSN dereferences such argument |
| slots, zero otherwise. */ |
| |
| static int |
| check_sibcall_argument_overlap (rtx_insn *insn, struct arg_data *arg, |
| int mark_stored_args_map) |
| { |
| int low, high; |
| |
| if (insn == NULL_RTX) |
| insn = get_insns (); |
| else |
| insn = NEXT_INSN (insn); |
| |
| for (; insn; insn = NEXT_INSN (insn)) |
| if (INSN_P (insn) |
| && check_sibcall_argument_overlap_1 (PATTERN (insn))) |
| break; |
| |
| if (mark_stored_args_map) |
| { |
| if (ARGS_GROW_DOWNWARD) |
| low = -arg->locate.slot_offset.constant - arg->locate.size.constant; |
| else |
| low = arg->locate.slot_offset.constant; |
| |
| for (high = low + arg->locate.size.constant; low < high; low++) |
| bitmap_set_bit (stored_args_map, low); |
| } |
| return insn != NULL_RTX; |
| } |
| |
| /* Given that a function returns a value of mode MODE at the most |
| significant end of hard register VALUE, shift VALUE left or right |
| as specified by LEFT_P. Return true if some action was needed. */ |
| |
| bool |
| shift_return_value (machine_mode mode, bool left_p, rtx value) |
| { |
| HOST_WIDE_INT shift; |
| |
| gcc_assert (REG_P (value) && HARD_REGISTER_P (value)); |
| shift = GET_MODE_BITSIZE (GET_MODE (value)) - GET_MODE_BITSIZE (mode); |
| if (shift == 0) |
| return false; |
| |
| /* Use ashr rather than lshr for right shifts. This is for the benefit |
| of the MIPS port, which requires SImode values to be sign-extended |
| when stored in 64-bit registers. */ |
| if (!force_expand_binop (GET_MODE (value), left_p ? ashl_optab : ashr_optab, |
| value, GEN_INT (shift), value, 1, OPTAB_WIDEN)) |
| gcc_unreachable (); |
| return true; |
| } |
| |
| /* If X is a likely-spilled register value, copy it to a pseudo |
| register and return that register. Return X otherwise. */ |
| |
| static rtx |
| avoid_likely_spilled_reg (rtx x) |
| { |
| rtx new_rtx; |
| |
| if (REG_P (x) |
| && HARD_REGISTER_P (x) |
| && targetm.class_likely_spilled_p (REGNO_REG_CLASS (REGNO (x)))) |
| { |
| /* Make sure that we generate a REG rather than a CONCAT. |
| Moves into CONCATs can need nontrivial instructions, |
| and the whole point of this function is to avoid |
| using the hard register directly in such a situation. */ |
| generating_concat_p = 0; |
| new_rtx = gen_reg_rtx (GET_MODE (x)); |
| generating_concat_p = 1; |
| emit_move_insn (new_rtx, x); |
| return new_rtx; |
| } |
| return x; |
| } |
| |
| /* Helper function for expand_call. |
| Return false is EXP is not implementable as a sibling call. */ |
| |
| static bool |
| can_implement_as_sibling_call_p (tree exp, |
| rtx structure_value_addr, |
| tree funtype, |
| int reg_parm_stack_space ATTRIBUTE_UNUSED, |
| tree fndecl, |
| int flags, |
| tree addr, |
| const args_size &args_size) |
| { |
| if (!targetm.have_sibcall_epilogue ()) |
| { |
| maybe_complain_about_tail_call |
| (exp, |
| "machine description does not have" |
| " a sibcall_epilogue instruction pattern"); |
| return false; |
| } |
| |
| /* Doing sibling call optimization needs some work, since |
| structure_value_addr can be allocated on the stack. |
| It does not seem worth the effort since few optimizable |
| sibling calls will return a structure. */ |
| if (structure_value_addr != NULL_RTX) |
| { |
| maybe_complain_about_tail_call (exp, "callee returns a structure"); |
| return false; |
| } |
| |
| #ifdef REG_PARM_STACK_SPACE |
| /* If outgoing reg parm stack space changes, we can not do sibcall. */ |
| if (OUTGOING_REG_PARM_STACK_SPACE (funtype) |
| != OUTGOING_REG_PARM_STACK_SPACE (TREE_TYPE (current_function_decl)) |
| || (reg_parm_stack_space != REG_PARM_STACK_SPACE (current_function_decl))) |
| { |
| maybe_complain_about_tail_call (exp, |
| "inconsistent size of stack space" |
| " allocated for arguments which are" |
| " passed in registers"); |
| return false; |
| } |
| #endif |
| |
| /* Check whether the target is able to optimize the call |
| into a sibcall. */ |
| if (!targetm.function_ok_for_sibcall (fndecl, exp)) |
| { |
| maybe_complain_about_tail_call (exp, |
| "target is not able to optimize the" |
| " call into a sibling call"); |
| return false; |
| } |
| |
| /* Functions that do not return exactly once may not be sibcall |
| optimized. */ |
| if (flags & ECF_RETURNS_TWICE) |
| { |
| maybe_complain_about_tail_call (exp, "callee returns twice"); |
| return false; |
| } |
| if (flags & ECF_NORETURN) |
| { |
| maybe_complain_about_tail_call (exp, "callee does not return"); |
| return false; |
| } |
| |
| if (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (addr)))) |
| { |
| maybe_complain_about_tail_call (exp, "volatile function type"); |
| return false; |
| } |
| |
| /* If the called function is nested in the current one, it might access |
| some of the caller's arguments, but could clobber them beforehand if |
| the argument areas are shared. */ |
| if (fndecl && decl_function_context (fndecl) == current_function_decl) |
| { |
| maybe_complain_about_tail_call (exp, "nested function"); |
| return false; |
| } |
| |
| /* If this function requires more stack slots than the current |
| function, we cannot change it into a sibling call. |
| crtl->args.pretend_args_size is not part of the |
| stack allocated by our caller. */ |
| if (args_size.constant > (crtl->args.size - crtl->args.pretend_args_size)) |
| { |
| maybe_complain_about_tail_call (exp, |
| "callee required more stack slots" |
| " than the caller"); |
| return false; |
| } |
| |
| /* If the callee pops its own arguments, then it must pop exactly |
| the same number of arguments as the current function. */ |
| if (targetm.calls.return_pops_args (fndecl, funtype, args_size.constant) |
| != targetm.calls.return_pops_args (current_function_decl, |
| TREE_TYPE (current_function_decl), |
| crtl->args.size)) |
| { |
| maybe_complain_about_tail_call (exp, |
| "inconsistent number of" |
| " popped arguments"); |
| return false; |
| } |
| |
| if (!lang_hooks.decls.ok_for_sibcall (fndecl)) |
| { |
| maybe_complain_about_tail_call (exp, "frontend does not support" |
| " sibling call"); |
| return false; |
| } |
| |
| /* All checks passed. */ |
| return true; |
| } |
| |
| /* Generate all the code for a CALL_EXPR exp |
| and return an rtx for its value. |
| Store the value in TARGET (specified as an rtx) if convenient. |
| If the value is stored in TARGET then TARGET is returned. |
| If IGNORE is nonzero, then we ignore the value of the function call. */ |
| |
| rtx |
| expand_call (tree exp, rtx target, int ignore) |
| { |
| /* Nonzero if we are currently expanding a call. */ |
| static int currently_expanding_call = 0; |
| |
| /* RTX for the function to be called. */ |
| rtx funexp; |
| /* Sequence of insns to perform a normal "call". */ |
| rtx_insn *normal_call_insns = NULL; |
| /* Sequence of insns to perform a tail "call". */ |
| rtx_insn *tail_call_insns = NULL; |
| /* Data type of the function. */ |
| tree funtype; |
| tree type_arg_types; |
| tree rettype; |
| /* Declaration of the function being called, |
| or 0 if the function is computed (not known by name). */ |
| tree fndecl = 0; |
| /* The type of the function being called. */ |
| tree fntype; |
| bool try_tail_call = CALL_EXPR_TAILCALL (exp); |
| bool must_tail_call = CALL_EXPR_MUST_TAIL_CALL (exp); |
| int pass; |
| |
| /* Register in which non-BLKmode value will be returned, |
| or 0 if no value or if value is BLKmode. */ |
| rtx valreg; |
| /* Register(s) in which bounds are returned. */ |
| rtx valbnd = NULL; |
| /* Address where we should return a BLKmode value; |
| 0 if value not BLKmode. */ |
| rtx structure_value_addr = 0; |
| /* Nonzero if that address is being passed by treating it as |
| an extra, implicit first parameter. Otherwise, |
| it is passed by being copied directly into struct_value_rtx. */ |
| int structure_value_addr_parm = 0; |
| /* Holds the value of implicit argument for the struct value. */ |
| tree structure_value_addr_value = NULL_TREE; |
| /* Size of aggregate value wanted, or zero if none wanted |
| or if we are using the non-reentrant PCC calling convention |
| or expecting the value in registers. */ |
| HOST_WIDE_INT struct_value_size = 0; |
| /* Nonzero if called function returns an aggregate in memory PCC style, |
| by returning the address of where to find it. */ |
| int pcc_struct_value = 0; |
| rtx struct_value = 0; |
| |
| /* Number of actual parameters in this call, including struct value addr. */ |
| int num_actuals; |
| /* Number of named args. Args after this are anonymous ones |
| and they must all go on the stack. */ |
| int n_named_args; |
| /* Number of complex actual arguments that need to be split. */ |
| int num_complex_actuals = 0; |
| |
| /* Vector of information about each argument. |
| Arguments are numbered in the order they will be pushed, |
| not the order they are written. */ |
| struct arg_data *args; |
| |
| /* Total size in bytes of all the stack-parms scanned so far. */ |
| struct args_size args_size; |
| struct args_size adjusted_args_size; |
| /* Size of arguments before any adjustments (such as rounding). */ |
| int unadjusted_args_size; |
| /* Data on reg parms scanned so far. */ |
| CUMULATIVE_ARGS args_so_far_v; |
| cumulative_args_t args_so_far; |
| /* Nonzero if a reg parm has been scanned. */ |
| int reg_parm_seen; |
| /* Nonzero if this is an indirect function call. */ |
| |
| /* Nonzero if we must avoid push-insns in the args for this call. |
| If stack space is allocated for register parameters, but not by the |
| caller, then it is preallocated in the fixed part of the stack frame. |
| So the entire argument block must then be preallocated (i.e., we |
| ignore PUSH_ROUNDING in that case). */ |
| |
| int must_preallocate = !PUSH_ARGS; |
| |
| /* Size of the stack reserved for parameter registers. */ |
| int reg_parm_stack_space = 0; |
| |
| /* Address of space preallocated for stack parms |
| (on machines that lack push insns), or 0 if space not preallocated. */ |
| rtx argblock = 0; |
| |
| /* Mask of ECF_ and ERF_ flags. */ |
| int flags = 0; |
| int return_flags = 0; |
| #ifdef REG_PARM_STACK_SPACE |
| /* Define the boundary of the register parm stack space that needs to be |
| saved, if any. */ |
| int low_to_save, high_to_save; |
| rtx save_area = 0; /* Place that it is saved */ |
| #endif |
| |
| int initial_highest_arg_in_use = highest_outgoing_arg_in_use; |
| char *initial_stack_usage_map = stack_usage_map; |
| char *stack_usage_map_buf = NULL; |
| |
| int old_stack_allocated; |
| |
| /* State variables to track stack modifications. */ |
| rtx old_stack_level = 0; |
| int old_stack_arg_under_construction = 0; |
| int old_pending_adj = 0; |
| int old_inhibit_defer_pop = inhibit_defer_pop; |
| |
| /* Some stack pointer alterations we make are performed via |
| allocate_dynamic_stack_space. This modifies the stack_pointer_delta, |
| which we then also need to save/restore along the way. */ |
| int old_stack_pointer_delta = 0; |
| |
| rtx call_fusage; |
| tree addr = CALL_EXPR_FN (exp); |
| int i; |
| /* The alignment of the stack, in bits. */ |
| unsigned HOST_WIDE_INT preferred_stack_boundary; |
| /* The alignment of the stack, in bytes. */ |
| 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. */ |
| if (TREE_NOTHROW (exp)) |
| flags |= ECF_NOTHROW; |
| |
| /* See if we can find a DECL-node for the actual function, and get the |
| function attributes (flags) from the function decl or type node. */ |
| fndecl = get_callee_fndecl (exp); |
| if (fndecl) |
| { |
| fntype = TREE_TYPE (fndecl); |
| flags |= flags_from_decl_or_type (fndecl); |
| return_flags |= decl_return_flags (fndecl); |
| } |
| else |
| { |
| fntype = TREE_TYPE (TREE_TYPE (addr)); |
| flags |= flags_from_decl_or_type (fntype); |
| if (CALL_EXPR_BY_DESCRIPTOR (exp)) |
| flags |= ECF_BY_DESCRIPTOR; |
| } |
| rettype = TREE_TYPE (exp); |
| |
| struct_value = targetm.calls.struct_value_rtx (fntype, 0); |
| |
| /* Warn if this value is an aggregate type, |
| regardless of which calling convention we are using for it. */ |
| if (AGGREGATE_TYPE_P (rettype)) |
| warning (OPT_Waggregate_return, "function call has aggregate value"); |
| |
| /* If the result of a non looping pure or const function call is |
| ignored (or void), and none of its arguments are volatile, we can |
| avoid expanding the call and just evaluate the arguments for |
| side-effects. */ |
| if ((flags & (ECF_CONST | ECF_PURE)) |
| && (!(flags & ECF_LOOPING_CONST_OR_PURE)) |
| && (ignore || target == const0_rtx |
| || TYPE_MODE (rettype) == VOIDmode)) |
| { |
| bool volatilep = false; |
| tree arg; |
| call_expr_arg_iterator iter; |
| |
| FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) |
| if (TREE_THIS_VOLATILE (arg)) |
| { |
| volatilep = true; |
| break; |
| } |
| |
| if (! volatilep) |
| { |
| FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) |
| expand_expr (arg, const0_rtx, VOIDmode, EXPAND_NORMAL); |
| return const0_rtx; |
| } |
| } |
| |
| #ifdef REG_PARM_STACK_SPACE |
| reg_parm_stack_space = REG_PARM_STACK_SPACE (!fndecl ? fntype : fndecl); |
| #endif |
| |
| if (! OUTGOING_REG_PARM_STACK_SPACE ((!fndecl ? fntype : TREE_TYPE (fndecl))) |
| && reg_parm_stack_space > 0 && PUSH_ARGS) |
| must_preallocate = 1; |
| |
| /* Set up a place to return a structure. */ |
| |
| /* Cater to broken compilers. */ |
| if (aggregate_value_p (exp, fntype)) |
| { |
| /* This call returns a big structure. */ |
| flags &= ~(ECF_CONST | ECF_PURE | ECF_LOOPING_CONST_OR_PURE); |
| |
| #ifdef PCC_STATIC_STRUCT_RETURN |
| { |
| pcc_struct_value = 1; |
| } |
| #else /* not PCC_STATIC_STRUCT_RETURN */ |
| { |
| struct_value_size = int_size_in_bytes (rettype); |
| |
| /* Even if it is semantically safe to use the target as the return |
| slot, it may be not sufficiently aligned for the return type. */ |
| if (CALL_EXPR_RETURN_SLOT_OPT (exp) |
| && target |
| && MEM_P (target) |
| /* If rettype is addressable, we may not create a temporary. |
| If target is properly aligned at runtime and the compiler |
| just doesn't know about it, it will work fine, otherwise it |
| will be UB. */ |
| && (TREE_ADDRESSABLE (rettype) |
| || !(MEM_ALIGN (target) < TYPE_ALIGN (rettype) |
| && SLOW_UNALIGNED_ACCESS (TYPE_MODE (rettype), |
| MEM_ALIGN (target))))) |
| structure_value_addr = XEXP (target, 0); |
| else |
| { |
| /* For variable-sized objects, we must be called with a target |
| specified. If we were to allocate space on the stack here, |
| we would have no way of knowing when to free it. */ |
| rtx d = assign_temp (rettype, 1, 1); |
| structure_value_addr = XEXP (d, 0); |
| target = 0; |
| } |
| } |
| #endif /* not PCC_STATIC_STRUCT_RETURN */ |
| } |
| |
| /* Figure out the amount to which the stack should be aligned. */ |
| |