diff mbox

Fix pr 50132 and 49864

Message ID 4E569C42.9080101@redhat.com
State New
Headers show

Commit Message

Richard Henderson Aug. 25, 2011, 7:02 p.m. UTC
These are both REG_ARGS_SIZE mis-match problems.

The 49864 problem is caused by cross-jumping doing the wrong
thing.  The 50132 problem is caused by fixup_args_size_notes
think-o where we failed to properly handle pops.

Techinically I should have split these changes apart, but I
tested them together and the splitting would have just been
make-work.

Tested on x86_64-linux.  Committed.


r~
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.
diff mbox

Patch

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 */