On Wed, Jan 11, 2012 at 09:16:04AM +0100, Eric Botcazou wrote:
> > And for noreturn calls, it doesn't do anything wrong, the problem is that it
> > returns the old size for them. 
> 
> According to the head comment, that's precisely the problem, since it should 
> do 
> something for them, in particular put back the note.

You're right.  So how about this patch (untested so far) instead?
In the combiner it still needs to handle the case where REG_NORETURN note
hasn't been placed yet, because then fixup_args_size_notes doesn't consider
it being a noret call.

2012-01-11  Jakub Jelinek  <ja...@redhat.com>

        PR bootstrap/51796
        * combine.c (distribute_notes): If i3 is a noreturn call,
        allow old_size to be equal to args_size and make sure the
        noreturn call gets REG_ARGS_SIZE note.
        * expr.c (fixup_args_size_notes): Put REG_ARGS_SIZE notes
        on noreturn calls even when the delta is 0.

--- gcc/combine.c.jj    2011-12-09 15:21:20.000000000 +0100
+++ gcc/combine.c       2012-01-11 09:37:40.199961939 +0100
@@ -13281,8 +13281,30 @@ distribute_notes (rtx notes, rtx from_in
          if (!noop_move_p (i3))
            {
              int old_size, args_size = INTVAL (XEXP (note, 0));
+             bool noret_call = false;
              old_size = fixup_args_size_notes (PREV_INSN (i3), i3, args_size);
-             gcc_assert (old_size != args_size);
+             if (CALL_P (i3) && !ACCUMULATE_OUTGOING_ARGS)
+               {
+                 if (find_reg_note (i3, REG_NORETURN, NULL_RTX))
+                   noret_call = true;
+                 else
+                   {
+                     rtx n;
+                     for (n = next_note; n; n = XEXP (n, 1))
+                       if (REG_NOTE_KIND (n) == REG_NORETURN)
+                         {
+                           noret_call = true;
+                           break;
+                         }
+                   }
+               }
+             gcc_assert (old_size != args_size || noret_call);
+             /* emit_call_1 adds for !ACCUMULATE_OUTGOING_ARGS
+                REG_ARGS_SIZE note to all noreturn calls, so ensure
+                the notes stay on the noreturn call.  */
+             if (noret_call
+                 && find_reg_note (i3, REG_ARGS_SIZE, NULL_RTX) == NULL_RTX)
+               place = i3;
            }
          break;
 
--- gcc/expr.c.jj       2012-01-02 17:36:53.000000000 +0100
+++ gcc/expr.c  2012-01-11 09:30:08.549680295 +0100
@@ -3642,9 +3642,11 @@ mem_autoinc_base (rtx mem)
      (1) One or more auto-inc style memory references (aka pushes),
      (2) One or more addition/subtraction with the SP as destination,
      (3) A single move insn with the SP as destination,
-     (4) A call_pop insn.
+     (4) A call_pop insn,
+     (5) Noreturn call insns if !ACCUMULATE_OUTGOING_ARGS.
 
-   Insns in the sequence that do not modify the SP are ignored.
+   Insns in the sequence that do not modify the SP are ignored,
+   except for noreturn calls.
 
    The return value is the amount of adjustment that can be trivially
    verified, via immediate operand or auto-inc.  If the adjustment
@@ -3789,7 +3791,12 @@ fixup_args_size_notes (rtx prev, rtx las
 
       this_delta = find_args_size_adjust (insn);
       if (this_delta == 0)
-       continue;
+       {
+         if (!CALL_P (insn)
+             || ACCUMULATE_OUTGOING_ARGS
+             || find_reg_note (insn, REG_NORETURN, NULL_RTX) == NULL_RTX)
+           continue;
+       }
 
       gcc_assert (!saw_unknown);
       if (this_delta == HOST_WIDE_INT_MIN)
--- gcc/testsuite/gcc.dg/pr51796.c.jj   2012-01-10 16:43:00.494803970 +0100
+++ gcc/testsuite/gcc.dg/pr51796.c      2012-01-10 16:43:00.494803970 +0100
@@ -0,0 +1,15 @@
+/* PR bootstrap/51796 */
+/* { dg-do compile } */
+/* { dg-options "-Os -fno-omit-frame-pointer -fno-tree-dominator-opts 
-fno-tree-fre -fno-tree-pre" } */
+
+typedef void (*entry_func) (void) __attribute__ ((noreturn));
+extern entry_func entry_addr;
+static void bsd_boot_entry (void)
+{
+  stop ();
+}   
+void bsd_boot (void)
+{
+  entry_addr = (entry_func) bsd_boot_entry;
+  (*entry_addr) ();
+}


        Jakub

Reply via email to