diff options
author | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-07-13 18:19:27 +0000 |
---|---|---|
committer | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2000-07-13 18:19:27 +0000 |
commit | 7ecc63d3781a81e0e02174492d98900d9d21a3a1 (patch) | |
tree | 367ba4c9422b7ad93273efb447abfe804fc2163b /gcc/calls.c | |
parent | 0460bb9d80fa835e88d56711e4ad503430c83494 (diff) | |
download | gcc-7ecc63d3781a81e0e02174492d98900d9d21a3a1.tar.gz |
* calls.c (stored_args_map): New variable.
(check_sibcall_argument_overlap_1): New.
(check_sibcall_argument_overlap): New.
(expand_call): Initialize stored_args_map.
Call check_sibcall_argument_overlap.
* gcc.c-torture/execute/20000707-1.c: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@35017 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/calls.c')
-rw-r--r-- | gcc/calls.c | 130 |
1 files changed, 125 insertions, 5 deletions
diff --git a/gcc/calls.c b/gcc/calls.c index 3561f5987f4..784b3b165f8 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA. */ #include "output.h" #include "tm_p.h" #include "timevar.h" +#include "sbitmap.h" #ifndef ACCUMULATE_OUTGOING_ARGS #define ACCUMULATE_OUTGOING_ARGS 0 @@ -145,6 +146,13 @@ 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 @@ -215,6 +223,9 @@ static int special_function_p PARAMS ((tree, int)); static int flags_from_decl_or_type PARAMS ((tree)); static rtx try_to_integrate PARAMS ((tree, tree, rtx, int, tree, rtx)); +static int check_sibcall_argument_overlap_1 PARAMS ((rtx)); +static int check_sibcall_argument_overlap PARAMS ((rtx, struct arg_data *)); + static int combine_pending_stack_adjustment_and_call PARAMS ((int, struct args_size *, int)); @@ -1917,6 +1928,95 @@ combine_pending_stack_adjustment_and_call (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 non-zero if X expression dereferences such argument slots, + zero otherwise. */ + +static int +check_sibcall_argument_overlap_1 (x) + rtx x; +{ + RTX_CODE code; + int i, j; + unsigned int k; + const char *fmt; + + if (x == NULL_RTX) + return 0; + + code = GET_CODE (x); + + if (code == MEM) + { + if (XEXP (x, 0) == current_function_internal_arg_pointer) + i = 0; + else if (GET_CODE (XEXP (x, 0)) == PLUS && + XEXP (XEXP (x, 0), 0) == + current_function_internal_arg_pointer && + GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) + i = INTVAL (XEXP (XEXP (x, 0), 1)); + else + return 0; + + for (k = 0; k < GET_MODE_SIZE (GET_MODE (x)); k++) + if (i + k < stored_args_map->n_bits + && TEST_BIT (stored_args_map, i + k)) + return 1; + + return 0; + } + + /* 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). Add stack slots for ARG to stored_args_map bitmap afterwards. + Return non-zero if sequence after INSN dereferences such argument slots, + zero otherwise. */ + +static int +check_sibcall_argument_overlap (insn, arg) + rtx insn; + struct arg_data *arg; +{ + 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; + + low = arg->offset.constant; + for (high = low + arg->size.constant; low < high; low++) + SET_BIT (stored_args_map, low); + return insn != NULL_RTX; +} + /* Generate all the code for a function call and return an rtx for its value. Store the value in TARGET (specified as an rtx) if convenient. @@ -2589,7 +2689,11 @@ expand_call (exp, target, ignore) /* The argument block when performing a sibling call is the incoming argument block. */ if (pass == 0) - argblock = virtual_incoming_args_rtx; + { + argblock = virtual_incoming_args_rtx; + stored_args_map = sbitmap_alloc (args_size.constant); + sbitmap_zero (stored_args_map); + } /* If we have no actual push instructions, or shouldn't use them, make space for all args right now. */ @@ -2840,8 +2944,15 @@ expand_call (exp, target, ignore) for (i = 0; i < num_actuals; i++) if (args[i].reg == 0 || args[i].pass_on_stack) - store_one_arg (&args[i], argblock, flags, - adjusted_args_size.var != 0, reg_parm_stack_space); + { + rtx before_arg = get_last_insn (); + + store_one_arg (&args[i], argblock, flags, + adjusted_args_size.var != 0, reg_parm_stack_space); + if (pass == 0 && + check_sibcall_argument_overlap (before_arg, &args[i])) + sibcall_failure = 1; + } /* If we have a parm that is passed in registers but not in memory and whose alignment does not permit a direct copy into registers, @@ -2855,8 +2966,15 @@ expand_call (exp, target, ignore) if (reg_parm_seen) for (i = 0; i < num_actuals; i++) if (args[i].partial != 0 && ! args[i].pass_on_stack) - store_one_arg (&args[i], argblock, flags, - adjusted_args_size.var != 0, reg_parm_stack_space); + { + rtx before_arg = get_last_insn (); + + store_one_arg (&args[i], argblock, flags, + adjusted_args_size.var != 0, reg_parm_stack_space); + if (pass == 0 && + check_sibcall_argument_overlap (before_arg, &args[i])) + sibcall_failure = 1; + } #ifdef PREFERRED_STACK_BOUNDARY /* If we pushed args in forward order, perform stack alignment @@ -3234,6 +3352,8 @@ expand_call (exp, target, ignore) args[i].aligned_regs = 0; args[i].stack = 0; } + + sbitmap_free (stored_args_map); } else normal_call_insns = insns; |