re PR middle-end/51323 (g++ confuses this with function argument in optimized call)
PR middle-end/51323 PR middle-end/50074 * calls.c (internal_arg_pointer_exp_state): New variable. (internal_arg_pointer_based_exp_1, internal_arg_pointer_exp_scan): New functions. (internal_arg_pointer_based_exp): New function. (mem_overlaps_already_clobbered_arg_p): Use it. (expand_call): Free internal_arg_pointer_exp_state.cache vector and clear internal_arg_pointer_exp_state.scan_start. * gcc.c-torture/execute/pr51323.c: New test. Co-Authored-By: Eric Botcazou <ebotcazou@adacore.com> From-SVN: r182000
This commit is contained in:
parent
2adac2a72b
commit
5275901c43
4 changed files with 186 additions and 15 deletions
|
@ -1,3 +1,16 @@
|
|||
2011-12-05 Jakub Jelinek <jakub@redhat.com>
|
||||
Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
PR middle-end/51323
|
||||
PR middle-end/50074
|
||||
* calls.c (internal_arg_pointer_exp_state): New variable.
|
||||
(internal_arg_pointer_based_exp_1,
|
||||
internal_arg_pointer_exp_scan): New functions.
|
||||
(internal_arg_pointer_based_exp): New function.
|
||||
(mem_overlaps_already_clobbered_arg_p): Use it.
|
||||
(expand_call): Free internal_arg_pointer_exp_state.cache vector
|
||||
and clear internal_arg_pointer_exp_state.scan_start.
|
||||
|
||||
2011-12-04 Kaz Kojima <kkojima@gcc.gnu.org>
|
||||
|
||||
* config/sh/linux.h (TARGET_DEFAULT): Add MASK_SOFT_ATOMIC.
|
||||
|
|
146
gcc/calls.c
146
gcc/calls.c
|
@ -1658,6 +1658,129 @@ rtx_for_function_call (tree fndecl, tree addr)
|
|||
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 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, heap) *cache;
|
||||
} internal_arg_pointer_exp_state;
|
||||
|
||||
static rtx internal_arg_pointer_based_exp (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, 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 < VEC_length (rtx, internal_arg_pointer_exp_state.cache)
|
||||
&& (VEC_index (rtx, 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)
|
||||
{
|
||||
VEC_safe_grow_cleared (rtx, heap,
|
||||
internal_arg_pointer_exp_state.cache,
|
||||
idx + 1);
|
||||
VEC_replace (rtx, 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;
|
||||
}
|
||||
|
||||
/* Helper function for internal_arg_pointer_based_exp, called through
|
||||
for_each_rtx. Return 1 if *LOC is a register based on
|
||||
crtl->args.internal_arg_pointer. Return -1 if *LOC is not based on it
|
||||
and the subexpressions need not be examined. Otherwise return 0. */
|
||||
|
||||
static int
|
||||
internal_arg_pointer_based_exp_1 (rtx *loc, void *data ATTRIBUTE_UNUSED)
|
||||
{
|
||||
if (REG_P (*loc) && internal_arg_pointer_based_exp (*loc, false) != NULL_RTX)
|
||||
return 1;
|
||||
if (MEM_P (*loc))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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 (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 (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 < VEC_length (rtx, internal_arg_pointer_exp_state.cache))
|
||||
return VEC_index (rtx, internal_arg_pointer_exp_state.cache, idx);
|
||||
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
if (for_each_rtx (&rtl, internal_arg_pointer_based_exp_1, NULL))
|
||||
return pc_rtx;
|
||||
|
||||
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
|
||||
|
@ -1667,26 +1790,17 @@ static bool
|
|||
mem_overlaps_already_clobbered_arg_p (rtx addr, unsigned HOST_WIDE_INT size)
|
||||
{
|
||||
HOST_WIDE_INT i;
|
||||
rtx val;
|
||||
|
||||
if (sbitmap_empty_p (stored_args_map))
|
||||
return false;
|
||||
if (addr == crtl->args.internal_arg_pointer)
|
||||
i = 0;
|
||||
else if (GET_CODE (addr) == PLUS
|
||||
&& XEXP (addr, 0) == crtl->args.internal_arg_pointer
|
||||
&& CONST_INT_P (XEXP (addr, 1)))
|
||||
i = INTVAL (XEXP (addr, 1));
|
||||
/* Return true for arg pointer based indexed addressing. */
|
||||
else if (GET_CODE (addr) == PLUS
|
||||
&& (XEXP (addr, 0) == crtl->args.internal_arg_pointer
|
||||
|| XEXP (addr, 1) == crtl->args.internal_arg_pointer))
|
||||
return true;
|
||||
/* If the address comes in a register, we have no idea of its origin so
|
||||
give up and conservatively return true. */
|
||||
else if (REG_P(addr))
|
||||
val = internal_arg_pointer_based_exp (addr, true);
|
||||
if (val == NULL_RTX)
|
||||
return false;
|
||||
else if (val == pc_rtx)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
i = INTVAL (val);
|
||||
|
||||
#ifdef ARGS_GROW_DOWNWARD
|
||||
i = -i - size;
|
||||
|
@ -3294,6 +3408,8 @@ expand_call (tree exp, rtx target, int ignore)
|
|||
}
|
||||
|
||||
sbitmap_free (stored_args_map);
|
||||
internal_arg_pointer_exp_state.scan_start = NULL_RTX;
|
||||
VEC_free (rtx, heap, internal_arg_pointer_exp_state.cache);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
2011-12-05 Jakub Jelinek <jakub@redhat.com>
|
||||
Eric Botcazou <ebotcazou@adacore.com>
|
||||
|
||||
PR middle-end/51323
|
||||
PR middle-end/50074
|
||||
* gcc.c-torture/execute/pr51323.c: New test.
|
||||
|
||||
2011-12-04 Tobias Burnus <burnus@net-b.de>
|
||||
|
||||
PR fortran/51383
|
||||
|
|
35
gcc/testsuite/gcc.c-torture/execute/pr51323.c
Normal file
35
gcc/testsuite/gcc.c-torture/execute/pr51323.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
/* PR middle-end/51323 */
|
||||
|
||||
extern void abort (void);
|
||||
struct S { int a, b, c; };
|
||||
int v;
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
foo (int x, int y, int z)
|
||||
{
|
||||
if (x != v || y != 0 || z != 9)
|
||||
abort ();
|
||||
}
|
||||
|
||||
static inline int
|
||||
baz (const struct S *p)
|
||||
{
|
||||
return p->b;
|
||||
}
|
||||
|
||||
__attribute__((noinline, noclone)) void
|
||||
bar (int x, struct S y)
|
||||
{
|
||||
foo (baz (&y), 0, x);
|
||||
}
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
struct S s;
|
||||
v = 3; s.a = v - 1; s.b = v; s.c = v + 1;
|
||||
bar (9, s);
|
||||
v = 17; s.a = v - 1; s.b = v; s.c = v + 1;
|
||||
bar (9, s);
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue