diff mbox

Update BBs in cleanup_barriers pass (PR rtl-optimization/61058)

Message ID 20150122204317.GM1746@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Jan. 22, 2015, 8:43 p.m. UTC
Hi!

While the cleanup_barriers runs after cleaning up BLOCK_FOR_INSNs,
some targets like i?86/x86_64 choose to populate it again during machine
reorg and some target don't free it at the end of machine reorg.
This patch updates cleanup_barrier pass, so that it adjusts basic block
boundaries and BLOCK_FOR_INSNs in that case, so that we don't crash during
final pass.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2015-01-22  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/61058
	* jump.c (cleanup_barriers): Update basic block boundaries
	if BLOCK_FOR_INSN is non-NULL on PREV.

	* gcc.dg/pr61058.c: New test.


	Jakub

Comments

Eric Botcazou Jan. 26, 2015, 9:06 a.m. UTC | #1
> While the cleanup_barriers runs after cleaning up BLOCK_FOR_INSNs,
> some targets like i?86/x86_64 choose to populate it again during machine
> reorg and some target don't free it at the end of machine reorg.
> This patch updates cleanup_barrier pass, so that it adjusts basic block
> boundaries and BLOCK_FOR_INSNs in that case, so that we don't crash during
> final pass.

This isn't a recent regression so what about fixing it more "properly"?  For 
example, by calling free_bb_for_insn at the end of the machinre reorg passes 
which called compute_bb_for_insn at the beginning?  Or do the affected ports 
need the BB info all the way down to final?
Jakub Jelinek Jan. 26, 2015, 9:11 a.m. UTC | #2
On Mon, Jan 26, 2015 at 10:06:05AM +0100, Eric Botcazou wrote:
> > While the cleanup_barriers runs after cleaning up BLOCK_FOR_INSNs,
> > some targets like i?86/x86_64 choose to populate it again during machine
> > reorg and some target don't free it at the end of machine reorg.
> > This patch updates cleanup_barrier pass, so that it adjusts basic block
> > boundaries and BLOCK_FOR_INSNs in that case, so that we don't crash during
> > final pass.
> 
> This isn't a recent regression so what about fixing it more "properly"?  For 
> example, by calling free_bb_for_insn at the end of the machinre reorg passes 
> which called compute_bb_for_insn at the beginning?  Or do the affected ports 
> need the BB info all the way down to final?

Yes, they do, that is why it crashed during final.

	Jakub
Jakub Jelinek Jan. 26, 2015, 9:26 a.m. UTC | #3
On Mon, Jan 26, 2015 at 10:11:00AM +0100, Jakub Jelinek wrote:
> On Mon, Jan 26, 2015 at 10:06:05AM +0100, Eric Botcazou wrote:
> > > While the cleanup_barriers runs after cleaning up BLOCK_FOR_INSNs,
> > > some targets like i?86/x86_64 choose to populate it again during machine
> > > reorg and some target don't free it at the end of machine reorg.
> > > This patch updates cleanup_barrier pass, so that it adjusts basic block
> > > boundaries and BLOCK_FOR_INSNs in that case, so that we don't crash during
> > > final pass.
> > 
> > This isn't a recent regression so what about fixing it more "properly"?  For 
> > example, by calling free_bb_for_insn at the end of the machinre reorg passes 
> > which called compute_bb_for_insn at the beginning?  Or do the affected ports 
> > need the BB info all the way down to final?
> 
> Yes, they do, that is why it crashed during final.

In particular, all the i386/x86_64 atom tuning AGU stuff depends on it
heavily, but e.g. ix86_ok_to_clobber_flags and various others too.

	Jakub
Steven Bosscher Jan. 26, 2015, 11:35 a.m. UTC | #4
On Mon, Jan 26, 2015 at 10:11 AM, Jakub Jelinek wrote:
> On Mon, Jan 26, 2015 at 10:06:05AM +0100, Eric Botcazou wrote:
>> > While the cleanup_barriers runs after cleaning up BLOCK_FOR_INSNs,
>> > some targets like i?86/x86_64 choose to populate it again during machine
>> > reorg and some target don't free it at the end of machine reorg.
>> > This patch updates cleanup_barrier pass, so that it adjusts basic block
>> > boundaries and BLOCK_FOR_INSNs in that case, so that we don't crash during
>> > final pass.
>>
>> This isn't a recent regression so what about fixing it more "properly"?  For
>> example, by calling free_bb_for_insn at the end of the machinre reorg passes
>> which called compute_bb_for_insn at the beginning?  Or do the affected ports
>> need the BB info all the way down to final?
>
> Yes, they do, that is why it crashed during final.

And they should not do so. It cannot be relied upon, in general. Even
now, recomputing BLOCK_FOR_INSN only works because machine reorg is
the first pass after free_cfg (so nothing has changed yet to the insns
stream).

Some ports (including x86_64/i386, ia64, and most non-sched_dbr ports)
could simply do away with free_cfg and cleanup_barriers. But some
ports put things into the insns stream after free_cfg that
verify_flow_info chokes on, e.g. the fake insns for const pools for
ARM (that causes bugs elsewhere also, see e.g.
https://gcc.gnu.org/ml/gcc-patches/2011-07/msg02101.html). The current
situation is confusing and bound to give bugs sooner or later...

I had patches to have an "early" and "late" free_cfg pass -- I think I
even posted them and I still believe that's the right short-term
solution -- to make sure nobody can put something between free_cfg and
a target with a machine_reorg that needs the CFG, or at least
BLOCK_FOR_INSN.

Oh well...

Ciao!
Steven
Jakub Jelinek Jan. 26, 2015, 11:47 a.m. UTC | #5
On Mon, Jan 26, 2015 at 12:35:30PM +0100, Steven Bosscher wrote:
> On Mon, Jan 26, 2015 at 10:11 AM, Jakub Jelinek wrote:
> > On Mon, Jan 26, 2015 at 10:06:05AM +0100, Eric Botcazou wrote:
> >> > While the cleanup_barriers runs after cleaning up BLOCK_FOR_INSNs,
> >> > some targets like i?86/x86_64 choose to populate it again during machine
> >> > reorg and some target don't free it at the end of machine reorg.
> >> > This patch updates cleanup_barrier pass, so that it adjusts basic block
> >> > boundaries and BLOCK_FOR_INSNs in that case, so that we don't crash during
> >> > final pass.
> >>
> >> This isn't a recent regression so what about fixing it more "properly"?  For
> >> example, by calling free_bb_for_insn at the end of the machinre reorg passes
> >> which called compute_bb_for_insn at the beginning?  Or do the affected ports
> >> need the BB info all the way down to final?
> >
> > Yes, they do, that is why it crashed during final.
> 
> And they should not do so. It cannot be relied upon, in general. Even
> now, recomputing BLOCK_FOR_INSN only works because machine reorg is
> the first pass after free_cfg (so nothing has changed yet to the insns
> stream).
> 
> Some ports (including x86_64/i386, ia64, and most non-sched_dbr ports)
> could simply do away with free_cfg and cleanup_barriers. But some
> ports put things into the insns stream after free_cfg that
> verify_flow_info chokes on, e.g. the fake insns for const pools for
> ARM (that causes bugs elsewhere also, see e.g.
> https://gcc.gnu.org/ml/gcc-patches/2011-07/msg02101.html). The current
> situation is confusing and bound to give bugs sooner or later...
> 
> I had patches to have an "early" and "late" free_cfg pass -- I think I
> even posted them and I still believe that's the right short-term
> solution -- to make sure nobody can put something between free_cfg and
> a target with a machine_reorg that needs the CFG, or at least
> BLOCK_FOR_INSN.

Sure, we have targets which need cfg late, and targets which don't, and
targets which do need it only diring machine reorg and not afterwards.

pass_free_cfg doesn't do just free_bb_for_insn though, it also adds
a note for hot cold partitioning, and for DBR targets other stuff, though
DBR targets are likely helpless with keeping CFG till the end.

What my patch does is still compatible with removing that
free_bb_for_insn call from pass_free_cfg::execute if some flag is set
in targetm, it teaches the pass to handle cfg if it is around.

I agree that freeing the cfg and immediately computing it again doesn't make
sense, but I just don't see this patch being incompatible with that.

	Jakub
Richard Biener Jan. 26, 2015, 12:11 p.m. UTC | #6
On Mon, Jan 26, 2015 at 12:47 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Mon, Jan 26, 2015 at 12:35:30PM +0100, Steven Bosscher wrote:
>> On Mon, Jan 26, 2015 at 10:11 AM, Jakub Jelinek wrote:
>> > On Mon, Jan 26, 2015 at 10:06:05AM +0100, Eric Botcazou wrote:
>> >> > While the cleanup_barriers runs after cleaning up BLOCK_FOR_INSNs,
>> >> > some targets like i?86/x86_64 choose to populate it again during machine
>> >> > reorg and some target don't free it at the end of machine reorg.
>> >> > This patch updates cleanup_barrier pass, so that it adjusts basic block
>> >> > boundaries and BLOCK_FOR_INSNs in that case, so that we don't crash during
>> >> > final pass.
>> >>
>> >> This isn't a recent regression so what about fixing it more "properly"?  For
>> >> example, by calling free_bb_for_insn at the end of the machinre reorg passes
>> >> which called compute_bb_for_insn at the beginning?  Or do the affected ports
>> >> need the BB info all the way down to final?
>> >
>> > Yes, they do, that is why it crashed during final.
>>
>> And they should not do so. It cannot be relied upon, in general. Even
>> now, recomputing BLOCK_FOR_INSN only works because machine reorg is
>> the first pass after free_cfg (so nothing has changed yet to the insns
>> stream).
>>
>> Some ports (including x86_64/i386, ia64, and most non-sched_dbr ports)
>> could simply do away with free_cfg and cleanup_barriers. But some
>> ports put things into the insns stream after free_cfg that
>> verify_flow_info chokes on, e.g. the fake insns for const pools for
>> ARM (that causes bugs elsewhere also, see e.g.
>> https://gcc.gnu.org/ml/gcc-patches/2011-07/msg02101.html). The current
>> situation is confusing and bound to give bugs sooner or later...
>>
>> I had patches to have an "early" and "late" free_cfg pass -- I think I
>> even posted them and I still believe that's the right short-term
>> solution -- to make sure nobody can put something between free_cfg and
>> a target with a machine_reorg that needs the CFG, or at least
>> BLOCK_FOR_INSN.
>
> Sure, we have targets which need cfg late, and targets which don't, and
> targets which do need it only diring machine reorg and not afterwards.
>
> pass_free_cfg doesn't do just free_bb_for_insn though, it also adds
> a note for hot cold partitioning, and for DBR targets other stuff, though
> DBR targets are likely helpless with keeping CFG till the end.
>
> What my patch does is still compatible with removing that
> free_bb_for_insn call from pass_free_cfg::execute if some flag is set
> in targetm, it teaches the pass to handle cfg if it is around.
>
> I agree that freeing the cfg and immediately computing it again doesn't make
> sense, but I just don't see this patch being incompatible with that.

I wonder if handing over pass pipeline control to targets at
machine_reorg time (including free_cfg) makes sense...
(either giving control back for stuff like final() or make it call
into the middle-end again).

Richard.

>         Jakub
Jakub Jelinek Jan. 26, 2015, 1:34 p.m. UTC | #7
On Mon, Jan 26, 2015 at 01:11:01PM +0100, Richard Biener wrote:
> > I agree that freeing the cfg and immediately computing it again doesn't make
> > sense, but I just don't see this patch being incompatible with that.
> 
> I wonder if handing over pass pipeline control to targets at
> machine_reorg time (including free_cfg) makes sense...
> (either giving control back for stuff like final() or make it call
> into the middle-end again).

Perhaps, but not sure if such changes are desirable for stage4.
And certainly unsuitable for release branches.

	Jakub
Jeff Law Jan. 26, 2015, 6:45 p.m. UTC | #8
On 01/26/15 06:34, Jakub Jelinek wrote:
> On Mon, Jan 26, 2015 at 01:11:01PM +0100, Richard Biener wrote:
>>> I agree that freeing the cfg and immediately computing it again doesn't make
>>> sense, but I just don't see this patch being incompatible with that.
>>
>> I wonder if handing over pass pipeline control to targets at
>> machine_reorg time (including free_cfg) makes sense...
>> (either giving control back for stuff like final() or make it call
>> into the middle-end again).
>
> Perhaps, but not sure if such changes are desirable for stage4.
> And certainly unsuitable for release branches.
That would seem to take a big mistake (machine_reorg) and make it even 
worse.

Jeff
Eric Botcazou Jan. 27, 2015, 8:25 a.m. UTC | #9
> Yes, they do, that is why it crashed during final.

OK.  Why wouldn't it work to call reorder_insns instead of reorder_insns_nobb?
Jakub Jelinek Jan. 27, 2015, 8:41 a.m. UTC | #10
On Tue, Jan 27, 2015 at 09:25:32AM +0100, Eric Botcazou wrote:
> > Yes, they do, that is why it crashed during final.
> 
> OK.  Why wouldn't it work to call reorder_insns instead of reorder_insns_nobb?

Because reorder_insns doesn't handle the case of moving a barrier into a
middle of basic block.

      if (!BARRIER_P (from)
          && (bb2 = BLOCK_FOR_INSN (from)))
        {
          if (BB_END (bb2) == to)
            BB_END (bb2) = prev;
          df_set_bb_dirty (bb2);
        }
    
      if (BB_END (bb) == after)
        BB_END (bb) = to;

      for (x = from; x != NEXT_INSN (to); x = NEXT_INSN (x))
        if (!BARRIER_P (x))
          df_insn_change_bb (x, bb);

from == to is a BARRIER in this case, BB_END (bb) != after (BB_END
is actually PREV_INSN (from)), so this doesn't do anything at all.

While what we need is:

1) set BB_END to after
2) clear BLOCK_FOR_INSN on the notes after AFTER (after addition of
   barrier after FROM == TO) until former PREV_INSN (FROM) (inclusive)

	Jakub
Eric Botcazou Jan. 27, 2015, 8:59 a.m. UTC | #11
> Because reorder_insns doesn't handle the case of moving a barrier into a
> middle of basic block.

Right, I should have read the audit trail. :-)  The patch is OK then, but add 
a ??? note at the end of the comment saying that the proper thing to do here 
is probably not to run cleanup_barrier for this back-end.
diff mbox

Patch

--- gcc/jump.c.jj	2015-01-15 20:25:30.000000000 +0100
+++ gcc/jump.c	2015-01-22 16:32:11.677709401 +0100
@@ -168,7 +168,27 @@  cleanup_barriers (void)
 	  if (BARRIER_P (prev))
 	    delete_insn (insn);
 	  else if (prev != PREV_INSN (insn))
-	    reorder_insns_nobb (insn, insn, prev);
+	    {
+	      basic_block bb = BLOCK_FOR_INSN (prev);
+	      rtx_insn *end = PREV_INSN (insn);
+	      reorder_insns_nobb (insn, insn, prev);
+	      if (bb)
+		{
+		  /* If the backend called in machine reorg compute_bb_for_insn
+		     and didn't free_bb_for_insn again, preserve basic block
+		     boundaries.  Move the end of basic block to PREV since
+		     it is followed by a barrier now, and clear BLOCK_FOR_INSN
+		     on the following notes.  */
+		  BB_END (bb) = prev;
+		  do
+		    {
+		      prev = NEXT_INSN (prev);
+		      if (prev != insn && BLOCK_FOR_INSN (prev) == bb)
+			BLOCK_FOR_INSN (prev) = NULL;
+		    }
+		  while (prev != end);
+		}
+	    }
 	}
     }
   return 0;
--- gcc/testsuite/gcc.dg/pr61058.c.jj	2015-01-22 16:19:16.507023479 +0100
+++ gcc/testsuite/gcc.dg/pr61058.c	2015-01-22 16:19:16.507023479 +0100
@@ -0,0 +1,10 @@ 
+/* PR rtl-optimization/61058 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-additional-options "-fno-asynchronous-unwind-tables -mtune=atom" { target i?86-*-* x86_64-*-* } } */
+
+void
+foo (void)
+{
+  __builtin_unreachable ();
+}