aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/cfgcleanup.c19
-rw-r--r--gcc/expr.c236
-rw-r--r--gcc/rtl.h1
-rw-r--r--gcc/testsuite/gcc.dg/pr50132.c10
5 files changed, 163 insertions, 113 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1da50b4..df92093 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+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,
diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
index 7173013..396057c 100644
--- a/gcc/cfgcleanup.c
+++ b/gcc/cfgcleanup.c
@@ -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);
diff --git a/gcc/expr.c b/gcc/expr.c
index ee16b6a..a6746d1 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -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;
diff --git a/gcc/rtl.h b/gcc/rtl.h
index e8aa7ab..7f86389 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -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 */
diff --git a/gcc/testsuite/gcc.dg/pr50132.c b/gcc/testsuite/gcc.dg/pr50132.c
new file mode 100644
index 0000000..84a9c73
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr50132.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -fno-asynchronous-unwind-tables -g" } */
+
+void bar (long double n);
+
+void foo (int c)
+{
+ if (c)
+ bar (0);
+}