Commit 42aa5124 by Richard Henderson Committed by Richard Henderson

re PR debug/50132 (ICE: in maybe_record_trace_start, at dwarf2cfi.c:2234 with…

re PR debug/50132 (ICE: in maybe_record_trace_start, at dwarf2cfi.c:2234 with -fno-asynchronous-unwind-tables and long double)

PR 50132
PR 49864
        * cfgcleanup.c (old_insns_match_p): Don't allow cross-jump for
        non-constant stack adjutment.
        * expr.c (find_args_size_adjust): Break out from ...
        (fixup_args_size_notes): ... here.
        * rtl.h (find_args_size_adjust): Declare.

From-SVN: r178084
parent 0ab71f30
2011-08-25 Richard Henderson <rth@redhat.com>
PR 50132
PR 49864
* cfgcleanup.c (old_insns_match_p): Don't allow cross-jump for
non-constant stack adjutment.
* expr.c (find_args_size_adjust): Break out from ...
(fixup_args_size_notes): ... here.
* rtl.h (find_args_size_adjust): Declare.
2011-08-25 Uros Bizjak <ubizjak@gmail.com>
* config/i386/i386.md (isa): Add sse2, sse2_noavx, sse3,
......
......@@ -1081,11 +1081,20 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2)
/* ??? Do not allow cross-jumping between different stack levels. */
p1 = find_reg_note (i1, REG_ARGS_SIZE, NULL);
p2 = find_reg_note (i2, REG_ARGS_SIZE, NULL);
if (p1)
p1 = XEXP (p1, 0);
if (p2)
p2 = XEXP (p2, 0);
if (!rtx_equal_p (p1, p2))
if (p1 && p2)
{
p1 = XEXP (p1, 0);
p2 = XEXP (p2, 0);
if (!rtx_equal_p (p1, p2))
return dir_none;
/* ??? Worse, this adjustment had better be constant lest we
have differing incoming stack levels. */
if (!frame_pointer_needed
&& find_args_size_adjust (i1) == HOST_WIDE_INT_MIN)
return dir_none;
}
else if (p1 || p2)
return dir_none;
p1 = PATTERN (i1);
......
......@@ -3548,131 +3548,151 @@ mem_autoinc_base (rtx mem)
verified, via immediate operand or auto-inc. If the adjustment
cannot be trivially extracted, the return value is INT_MIN. */
int
fixup_args_size_notes (rtx prev, rtx last, int end_args_size)
HOST_WIDE_INT
find_args_size_adjust (rtx insn)
{
int args_size = end_args_size;
bool saw_unknown = false;
rtx insn;
rtx dest, set, pat;
int i;
for (insn = last; insn != prev; insn = PREV_INSN (insn))
{
rtx dest, set, pat;
HOST_WIDE_INT this_delta = 0;
int i;
pat = PATTERN (insn);
set = NULL;
if (!NONDEBUG_INSN_P (insn))
continue;
pat = PATTERN (insn);
set = NULL;
/* Look for a call_pop pattern. */
if (CALL_P (insn))
{
/* We have to allow non-call_pop patterns for the case
of emit_single_push_insn of a TLS address. */
if (GET_CODE (pat) != PARALLEL)
return 0;
/* Look for a call_pop pattern. */
if (CALL_P (insn))
/* All call_pop have a stack pointer adjust in the parallel.
The call itself is always first, and the stack adjust is
usually last, so search from the end. */
for (i = XVECLEN (pat, 0) - 1; i > 0; --i)
{
/* We have to allow non-call_pop patterns for the case
of emit_single_push_insn of a TLS address. */
if (GET_CODE (pat) != PARALLEL)
continue;
/* All call_pop have a stack pointer adjust in the parallel.
The call itself is always first, and the stack adjust is
usually last, so search from the end. */
for (i = XVECLEN (pat, 0) - 1; i > 0; --i)
{
set = XVECEXP (pat, 0, i);
if (GET_CODE (set) != SET)
continue;
dest = SET_DEST (set);
if (dest == stack_pointer_rtx)
break;
}
/* We'd better have found the stack pointer adjust. */
if (i == 0)
set = XVECEXP (pat, 0, i);
if (GET_CODE (set) != SET)
continue;
/* Fall through to process the extracted SET and DEST
as if it was a standalone insn. */
dest = SET_DEST (set);
if (dest == stack_pointer_rtx)
break;
}
else if (GET_CODE (pat) == SET)
set = pat;
else if ((set = single_set (insn)) != NULL)
;
else if (GET_CODE (pat) == PARALLEL)
/* We'd better have found the stack pointer adjust. */
if (i == 0)
return 0;
/* Fall through to process the extracted SET and DEST
as if it was a standalone insn. */
}
else if (GET_CODE (pat) == SET)
set = pat;
else if ((set = single_set (insn)) != NULL)
;
else if (GET_CODE (pat) == PARALLEL)
{
/* ??? Some older ports use a parallel with a stack adjust
and a store for a PUSH_ROUNDING pattern, rather than a
PRE/POST_MODIFY rtx. Don't force them to update yet... */
/* ??? See h8300 and m68k, pushqi1. */
for (i = XVECLEN (pat, 0) - 1; i >= 0; --i)
{
/* ??? Some older ports use a parallel with a stack adjust
and a store for a PUSH_ROUNDING pattern, rather than a
PRE/POST_MODIFY rtx. Don't force them to update yet... */
/* ??? See h8300 and m68k, pushqi1. */
for (i = XVECLEN (pat, 0) - 1; i >= 0; --i)
{
set = XVECEXP (pat, 0, i);
if (GET_CODE (set) != SET)
continue;
dest = SET_DEST (set);
if (dest == stack_pointer_rtx)
break;
/* We do not expect an auto-inc of the sp in the parallel. */
gcc_checking_assert (mem_autoinc_base (dest)
!= stack_pointer_rtx);
gcc_checking_assert (mem_autoinc_base (SET_SRC (set))
!= stack_pointer_rtx);
}
if (i < 0)
set = XVECEXP (pat, 0, i);
if (GET_CODE (set) != SET)
continue;
dest = SET_DEST (set);
if (dest == stack_pointer_rtx)
break;
/* We do not expect an auto-inc of the sp in the parallel. */
gcc_checking_assert (mem_autoinc_base (dest) != stack_pointer_rtx);
gcc_checking_assert (mem_autoinc_base (SET_SRC (set))
!= stack_pointer_rtx);
}
if (i < 0)
return 0;
}
else
return 0;
dest = SET_DEST (set);
/* Look for direct modifications of the stack pointer. */
if (REG_P (dest) && REGNO (dest) == STACK_POINTER_REGNUM)
{
/* Look for a trivial adjustment, otherwise assume nothing. */
/* Note that the SPU restore_stack_block pattern refers to
the stack pointer in V4SImode. Consider that non-trivial. */
if (SCALAR_INT_MODE_P (GET_MODE (dest))
&& GET_CODE (SET_SRC (set)) == PLUS
&& XEXP (SET_SRC (set), 0) == stack_pointer_rtx
&& CONST_INT_P (XEXP (SET_SRC (set), 1)))
return INTVAL (XEXP (SET_SRC (set), 1));
/* ??? Reload can generate no-op moves, which will be cleaned
up later. Recognize it and continue searching. */
else if (rtx_equal_p (dest, SET_SRC (set)))
return 0;
else
continue;
dest = SET_DEST (set);
/* Look for direct modifications of the stack pointer. */
if (REG_P (dest) && REGNO (dest) == STACK_POINTER_REGNUM)
{
gcc_assert (!saw_unknown);
/* Look for a trivial adjustment, otherwise assume nothing. */
/* Note that the SPU restore_stack_block pattern refers to
the stack pointer in V4SImode. Consider that non-trivial. */
if (SCALAR_INT_MODE_P (GET_MODE (dest))
&& GET_CODE (SET_SRC (set)) == PLUS
&& XEXP (SET_SRC (set), 0) == stack_pointer_rtx
&& CONST_INT_P (XEXP (SET_SRC (set), 1)))
this_delta = INTVAL (XEXP (SET_SRC (set), 1));
/* ??? Reload can generate no-op moves, which will be cleaned
up later. Recognize it and continue searching. */
else if (rtx_equal_p (dest, SET_SRC (set)))
this_delta = 0;
else
saw_unknown = true;
}
return HOST_WIDE_INT_MIN;
}
else
{
rtx mem, addr;
/* Otherwise only think about autoinc patterns. */
else if (mem_autoinc_base (dest) == stack_pointer_rtx)
if (mem_autoinc_base (dest) == stack_pointer_rtx)
{
rtx addr = XEXP (dest, 0);
gcc_assert (!saw_unknown);
switch (GET_CODE (addr))
{
case PRE_INC:
case POST_INC:
this_delta = GET_MODE_SIZE (GET_MODE (dest));
break;
case PRE_DEC:
case POST_DEC:
this_delta = -GET_MODE_SIZE (GET_MODE (dest));
break;
case PRE_MODIFY:
case POST_MODIFY:
addr = XEXP (addr, 1);
gcc_assert (GET_CODE (addr) == PLUS);
gcc_assert (XEXP (addr, 0) == stack_pointer_rtx);
gcc_assert (CONST_INT_P (XEXP (addr, 1)));
this_delta = INTVAL (XEXP (addr, 1));
break;
default:
gcc_unreachable ();
}
mem = dest;
gcc_checking_assert (mem_autoinc_base (SET_SRC (set))
!= stack_pointer_rtx);
}
else if (mem_autoinc_base (SET_SRC (set)) == stack_pointer_rtx)
mem = SET_SRC (set);
else
return 0;
addr = XEXP (mem, 0);
switch (GET_CODE (addr))
{
case PRE_INC:
case POST_INC:
return GET_MODE_SIZE (GET_MODE (mem));
case PRE_DEC:
case POST_DEC:
return -GET_MODE_SIZE (GET_MODE (mem));
case PRE_MODIFY:
case POST_MODIFY:
addr = XEXP (addr, 1);
gcc_assert (GET_CODE (addr) == PLUS);
gcc_assert (XEXP (addr, 0) == stack_pointer_rtx);
gcc_assert (CONST_INT_P (XEXP (addr, 1)));
return INTVAL (XEXP (addr, 1));
default:
gcc_unreachable ();
}
}
}
int
fixup_args_size_notes (rtx prev, rtx last, int end_args_size)
{
int args_size = end_args_size;
bool saw_unknown = false;
rtx insn;
for (insn = last; insn != prev; insn = PREV_INSN (insn))
{
HOST_WIDE_INT this_delta;
if (!NONDEBUG_INSN_P (insn))
continue;
this_delta = find_args_size_adjust (insn);
if (this_delta == 0)
continue;
gcc_assert (!saw_unknown);
if (this_delta == HOST_WIDE_INT_MIN)
saw_unknown = true;
add_reg_note (insn, REG_ARGS_SIZE, GEN_INT (args_size));
#ifdef STACK_GROWS_DOWNWARD
this_delta = -this_delta;
......
......@@ -2508,6 +2508,7 @@ extern void emit_jump (rtx);
/* In expr.c */
extern rtx move_by_pieces (rtx, rtx, unsigned HOST_WIDE_INT,
unsigned int, int);
extern HOST_WIDE_INT find_args_size_adjust (rtx);
extern int fixup_args_size_notes (rtx, rtx, int);
/* In cfgrtl.c */
......
/* { dg-do compile } */
/* { dg-options "-Os -fno-asynchronous-unwind-tables -g" } */
void bar (long double n);
void foo (int c)
{
if (c)
bar (0);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment