calls.c (stored_args_map): New variable.
* 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. From-SVN: r35017
This commit is contained in:
parent
7dec90a1bc
commit
c67846f282
4 changed files with 164 additions and 5 deletions
|
@ -1,3 +1,11 @@
|
|||
2000-07-13 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2000-07-13 Bruce Korb <bkorb@gnu.org>
|
||||
|
||||
* fixinc/fixfixes.c: move EXIT_BROKEN to header, add sub-expr max count
|
||||
|
|
130
gcc/calls.c
130
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;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2000-07-13 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* gcc.c-torture/execute/20000707-1.c: New test.
|
||||
|
||||
2000-07-13 Neil Booth <NeilB@earthling.net>
|
||||
|
||||
* testsuite/gcc.dg/cpp/digraph1.c,
|
||||
|
|
27
gcc/testsuite/gcc.c-torture/execute/20000707-1.c
Normal file
27
gcc/testsuite/gcc.c-torture/execute/20000707-1.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
extern void abort(void);
|
||||
extern void exit(int);
|
||||
|
||||
struct baz {
|
||||
int a, b, c;
|
||||
};
|
||||
|
||||
void
|
||||
foo (int a, int b, int c)
|
||||
{
|
||||
if (a != 4)
|
||||
abort ();
|
||||
}
|
||||
|
||||
void
|
||||
bar (struct baz x, int b, int c)
|
||||
{
|
||||
foo (x.b, b, c);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
struct baz x = { 3, 4, 5 };
|
||||
bar (x, 1, 2);
|
||||
exit (0);
|
||||
}
|
Loading…
Add table
Reference in a new issue