Hi!

The barriers pass wants to put a BARRIER from after a noreturn call in
between the call and NOTE_INSN_CALL_ARG_LOCATION, but as the note no longer
is BB_END (the call is), it happens to extend BB_END to the BARRIER which
later breaks the md reorg pass.

dwarf2out.c seems to handle a BARRIER in between the call and related
NOTE_INSN_CALL_ARG_LOCATION resp. NOTE_INSN_VAR_LOCATION/c just fine,
only NOTE_INSN_CALL_ARG_LOCATION needs to go first.

My first fix was to the barriers pass to allow NOTE_INSN_CALL_ARG_LOCATION
in between the CALL_INSN and BARRIER, but I think I prefer to put the
BARRIER first from the beginning.

Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for
trunk?

2012-12-07  Jakub Jelinek  <ja...@redhat.com>

        PR middle-end/43631
        PR bootstrap/55615
        * var-tracking.c (emit_note_insn_var_location): If insn is followed
        by BARRIER, put note after the BARRIER.
        (next_non_note_insn_var_location): Skip over BARRIERs.
        (emit_notes_in_bb): If call is followed by BARRIER, put note after
        the BARRIER.

        * g++.dg/other/pr43631.C: New test.

--- gcc/var-tracking.c.jj       2012-12-06 15:37:30.000000000 +0100
+++ gcc/var-tracking.c  2012-12-07 13:00:32.713116052 +0100
@@ -8538,7 +8538,10 @@ emit_note_insn_var_location (void **varp
 
   if (where != EMIT_NOTE_BEFORE_INSN)
     {
-      note = emit_note_after (NOTE_INSN_VAR_LOCATION, insn);
+      rtx after = insn;
+      while (NEXT_INSN (after) && BARRIER_P (NEXT_INSN (after)))
+       after = NEXT_INSN (after);
+      note = emit_note_after (NOTE_INSN_VAR_LOCATION, after);
       if (where == EMIT_NOTE_AFTER_CALL_INSN)
        NOTE_DURING_CALL_P (note) = true;
     }
@@ -8892,9 +8895,11 @@ next_non_note_insn_var_location (rtx ins
   while (insn)
     {
       insn = NEXT_INSN (insn);
-      if (insn == 0
-         || !NOTE_P (insn)
-         || NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION)
+      if (insn == 0)
+       break;
+      if (BARRIER_P (insn))
+       continue;
+      if (!NOTE_P (insn) || NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION)
        break;
     }
 
@@ -8923,7 +8928,7 @@ emit_notes_in_bb (basic_block bb, datafl
            dataflow_set_clear_at_call (set);
            emit_notes_for_changes (insn, EMIT_NOTE_AFTER_CALL_INSN, set->vars);
            {
-             rtx arguments = mo->u.loc, *p = &arguments, note;
+             rtx arguments = mo->u.loc, *p = &arguments, note, after;
              while (*p)
                {
                  XEXP (XEXP (*p, 0), 1)
@@ -8947,7 +8952,10 @@ emit_notes_in_bb (basic_block bb, datafl
                  else
                    *p = XEXP (*p, 1);
                }
-             note = emit_note_after (NOTE_INSN_CALL_ARG_LOCATION, insn);
+             after = insn;
+             while (NEXT_INSN (after) && BARRIER_P (NEXT_INSN (after)))
+               after = NEXT_INSN (after);
+             note = emit_note_after (NOTE_INSN_CALL_ARG_LOCATION, after);
              NOTE_VAR_LOCATION (note) = arguments;
              /* If insn is BB_END of some bb, make sure the note
                 doesn't have BLOCK_FOR_INSN set.  The notes don't
--- gcc/testsuite/g++.dg/other/pr43631.C.jj     2012-12-07 12:12:35.557226106 
+0100
+++ gcc/testsuite/g++.dg/other/pr43631.C        2012-12-07 12:13:48.170822223 
+0100
@@ -0,0 +1,15 @@
+// PR middle-end/43631
+// { dg-do compile }
+// { dg-options "-g -O2" }
+// { dg-additional-options "-mtune=atom" { target i?86-*-* x86_64-*-* } }
+
+typedef void (*T) ();
+struct S { T t; };
+void bar (T) __attribute__ ((__noreturn__));
+S *p;
+
+void
+foo ()
+{
+  try { bar (p->t); } catch (...) { throw 1; }
+}

        Jakub

Reply via email to