diff mbox

Fix PR middle-end/61141

Message ID BLU0-SMTP43F10F32286A327F4C627297330@phx.gbl
State New
Headers show

Commit Message

John David Anglin May 18, 2014, 3:33 p.m. UTC
The attached change appears to fix PR middle-end/61141.  On PA, we can  
get
deleted insn notes in call sequences.  The attached change checks to  
make sure we have
a valid insn before calling reset_insn_used_flags and  
verify_insn_sharing.

Tested on hppa-unknown-linux-gnu, hppa2.0w-hp-hpux11.11 and hppa64-hp- 
hpux11.11.

OK for trunk?

Dave
--
John David Anglin	dave.anglin@bell.net
2014-05-18  John David Anglin  <danglin@gcc.gnu.org>

	PR middle-end/61141
	* emit-rtl.c (reset_all_used_flags): In a sequence, check that
	XVECEXP (pat, 0, i) is an INSN before calling reset_insn_used_flags.
	(verify_rtl_sharing): Likewise.

Comments

Jeff Law May 19, 2014, 5:51 p.m. UTC | #1
On 05/18/14 09:33, John David Anglin wrote:
> The attached change appears to fix PR middle-end/61141.  On PA, we can get
> deleted insn notes in call sequences.  The attached change checks to
> make sure we have
> a valid insn before calling reset_insn_used_flags and verify_insn_sharing.
>
> Tested on hppa-unknown-linux-gnu, hppa2.0w-hp-hpux11.11 and
> hppa64-hp-hpux11.11.
>
> OK for trunk?
Maybe :-)

c#1 you incluide a blob of RTL, but it's not clear where insn 238 was to 
begin with.  ie, was it inside a SEQUENCE or somewhere else?

In c#2 you indicate we can get this stuff when an insn in a delay slot 
sequence is deleted.  Where/when are those insns being deleted? 
Presumably the backends know enough to handle deleted insns in delay 
slot sequences?!?  It's been a long time since I looked at that code in 
detail, so if you already know it's safe, just say "it's safe" and I'll 
believe you :-)  Otherwise a bit of digging may be needed.

My preference would be to remove these insns from the RTL chain, but if 
that's not going to be reasonably feasible, then we'll probably need to 
go with something like your patch.


Jeff
John David Anglin May 19, 2014, 9:20 p.m. UTC | #2
Hi Jeff,

On 19-May-14, at 1:51 PM, Jeff Law wrote:

> On 05/18/14 09:33, John David Anglin wrote:
>> The attached change appears to fix PR middle-end/61141.  On PA, we  
>> can get
>> deleted insn notes in call sequences.  The attached change checks to
>> make sure we have
>> a valid insn before calling reset_insn_used_flags and  
>> verify_insn_sharing.
>>
>> Tested on hppa-unknown-linux-gnu, hppa2.0w-hp-hpux11.11 and
>> hppa64-hp-hpux11.11.
>>
>> OK for trunk?
> Maybe :-)
>
> c#1 you incluide a blob of RTL, but it's not clear where insn 238  
> was to begin with.  ie, was it inside a SEQUENCE or somewhere else?

Yes, it was inside a SEQUENCE.

The problem compiling c-common.c is very hard to debug.  These  
routines are called intensively and the ICE occurs after several  
million calls.
It takes a couple of hours of running under gdb to reach the failing  
call to reset_insn_used_flags just counting calls up to ICE.

The problem is more apparent with 64-bit compiler due to way PIC  
register is saved and restored.

>
> In c#2 you indicate we can get this stuff when an insn in a delay  
> slot sequence is deleted.  Where/when are those insns being deleted?  
> Presumably the backends know enough to handle deleted insns in delay  
> slot sequences?!?  It's been a long time since I looked at that code  
> in detail, so if you already know it's safe, just say "it's safe"  
> and I'll believe you :-)  Otherwise a bit of digging may be needed.

I believe that the backend must handle the deleted insns in the delay  
slot as there are are no compilation errors or regressions.
However, like you, I'm not 100% certain this done correctly.

>
> My preference would be to remove these insns from the RTL chain, but  
> if that's not going to be reasonably feasible, then we'll probably  
> need to go with something like your patch.


Something has changed.  Either these insns aren't being removed from  
RTL chain as they were before or they are being deleted
at a much later stage.  The same code is present in 4.9 and the  
problem doesn't seem to occur there.  Possibly, a regression search
would pin point this.

Still, we shouldn't call reset_insn_used_flags  or verify_insn_sharing  
with a note.

Dave
--
John David Anglin	dave.anglin@bell.net
Jeff Law May 20, 2014, 9:23 p.m. UTC | #3
On 05/19/14 15:20, John David Anglin wrote:
> The problem compiling c-common.c is very hard to debug.  These routines
> are called intensively and the ICE occurs after several million calls.
> It takes a couple of hours of running under gdb to reach the failing
> call to reset_insn_used_flags just counting calls up to ICE.
I'd suggest getting a suitable .i/.ii file and debugging it with a 
cross-debugger ;-)  Then again, if you've got a breakpoint that is 
triggering a million times, it may still take hours to hit when 
debugging with a cross.


>
> The problem is more apparent with 64-bit compiler due to way PIC
> register is saved and restored.
Yea, that makes sense.

>
>>
>> In c#2 you indicate we can get this stuff when an insn in a delay slot
>> sequence is deleted.  Where/when are those insns being deleted?
>> Presumably the backends know enough to handle deleted insns in delay
>> slot sequences?!?  It's been a long time since I looked at that code
>> in detail, so if you already know it's safe, just say "it's safe" and
>> I'll believe you :-)  Otherwise a bit of digging may be needed.
>
> I believe that the backend must handle the deleted insns in the delay
> slot as there are are no compilation errors or regressions.
> However, like you, I'm not 100% certain this done correctly.
I'm pretty sure we're getting this wrong in the backend.   In fact, the 
more I think about it, a NOTE_INSN_DELETED in a delay slot is just 
asking for all kinds of trouble.

In general, if we have an insn with a filled delay slot, then we will 
emit the two insns independently of each other (most of the time, there 
are exceptions).

A NOTE_INSN_DELETED in a delay slot still looks like a filled slot.  So 
the target code isn't going to emit a NOP or anything like that.  It's 
going to leave it up to the generic code to emit the insn with the delay 
slot and the delay slot insn itself (the NOTE_INSN_DELETED in this case).

Of course we don't output anything for a NOTE_INSN_DELETED.  So the net 
result is we, in essence, fill the delay slot with whatever random 
instruction happens to fall next in the insn chain.

Amazingly, nothing seems to be failing, but I've seen far worse bugs go 
unnoticed for a long time.

Sadly,I think we need to start digging deeper to find out what's 
deleting those insns and take corrective action.

Perhaps writing a little routine to peek at all the filled delay slots 
and squawk if it finds a NOTE_INSN_DELETED.  Then call it after each RTL 
pass that follows reorg in the pass manager.  That'd at least narrow it 
down to a pass that's mucking things up.

> Something has changed.  Either these insns aren't being removed from RTL
> chain as they were before or they are being deleted
> at a much later stage.  The same code is present in 4.9 and the problem
> doesn't seem to occur there.  Possibly, a regression search
> would pin point this.
Probably just gone latent.

>
> Still, we shouldn't call reset_insn_used_flags  or verify_insn_sharing
> with a note.
Agreed, but at least in this instance, it's the symptom of a deeper 
problem I think.

jeff
John David Anglin May 24, 2014, 6:39 p.m. UTC | #4
On 20-May-14, at 5:23 PM, Jeff Law wrote:

>> I believe that the backend must handle the deleted insns in the delay
>> slot as there are are no compilation errors or regressions.
>> However, like you, I'm not 100% certain this done correctly.
> I'm pretty sure we're getting this wrong in the backend.   In fact,  
> the more I think about it, a NOTE_INSN_DELETED in a delay slot is  
> just asking for all kinds of trouble.
>
> In general, if we have an insn with a filled delay slot, then we  
> will emit the two insns independently of each other (most of the  
> time, there are exceptions).
>
> A NOTE_INSN_DELETED in a delay slot still looks like a filled slot.   
> So the target code isn't going to emit a NOP or anything like that.   
> It's going to leave it up to the generic code to emit the insn with  
> the delay slot and the delay slot insn itself (the NOTE_INSN_DELETED  
> in this case).
>
> Of course we don't output anything for a NOTE_INSN_DELETED.  So the  
> net result is we, in essence, fill the delay slot with whatever  
> random instruction happens to fall next in the insn chain.
>
> Amazingly, nothing seems to be failing, but I've seen far worse bugs  
> go unnoticed for a long time.
>
> Sadly,I think we need to start digging deeper to find out what's  
> deleting those insns and take corrective action.
>
> Perhaps writing a little routine to peek at all the filled delay  
> slots and squawk if it finds a NOTE_INSN_DELETED.  Then call it  
> after each RTL pass that follows reorg in the pass manager.  That'd  
> at least narrow it down to a pass that's mucking things up.

The insns are being deleted in "final" after the assembly output has  
being done.  So, for example, pa_output_call is
never called with a delayed branch sequence containing a  
NOTE_INSN_DELETED.

It would seem to me that this "cleanup" should be done before the  
"dbr" pass.

If dbr_sequence() ignored notes, we would emit the nop.  However, it  
doesn't look like it does.  It fairly
easy to check for this case but I hesitate to add code to handle cases  
that aren't supposed to happen.

Dave
--
John David Anglin	dave.anglin@bell.net
Jeff Law June 4, 2014, 7:38 a.m. UTC | #5
On 05/24/14 12:39, John David Anglin wrote:
>
> The insns are being deleted in "final" after the assembly output has
> being done.  So, for example, pa_output_call is
> never called with a delayed branch sequence containing a NOTE_INSN_DELETED.
OK.  That's good to know.  I scanned final and final_scan_insn and see a 
couple places where we delete insns, but if I'm reading the code 
correctly, they would result in seeing the NOTE_INSN_DELETED rather than 
a real insn in the output routines.

So what code during final is deleting these insns?
Jeff
John David Anglin June 8, 2014, 6:06 p.m. UTC | #6
On 4-Jun-14, at 3:38 AM, Jeff Law wrote:

> On 05/24/14 12:39, John David Anglin wrote:
>>
>> The insns are being deleted in "final" after the assembly output has
>> being done.  So, for example, pa_output_call is
>> never called with a delayed branch sequence containing a  
>> NOTE_INSN_DELETED.
> OK.  That's good to know.  I scanned final and final_scan_insn and  
> see a couple places where we delete insns, but if I'm reading the  
> code correctly, they would result in seeing the NOTE_INSN_DELETED  
> rather than a real insn in the output routines.
>
> So what code during final is deleting these insns?

It's the PA backend.  For example,

          /* If this isn't a sibcall, we put the load of %r27 into the
             delay slot.  We can't do this in a sibcall as we don't
             have a second call-clobbered scratch register available.   
*/
          if (seq_length != 0
              && ! JUMP_P (NEXT_INSN (insn))
              && !sibcall)
            {
              final_scan_insn (NEXT_INSN (insn), asm_out_file,
                               optimize, 0, NULL);

              /* Now delete the delay insn.  */
              SET_INSN_DELETED (NEXT_INSN (insn));
              delay_insn_deleted = 1;
            }

The insn is deleted so that it won't be emitted again.  This is done  
in a bunch
of places.

What's new is the verification after assembly output.

Dave
--
John David Anglin	dave.anglin@bell.net
Jeff Law June 8, 2014, 6:48 p.m. UTC | #7
On 06/08/14 12:06, John David Anglin wrote:
> On 4-Jun-14, at 3:38 AM, Jeff Law wrote:
>
>> On 05/24/14 12:39, John David Anglin wrote:
>>>
>>> The insns are being deleted in "final" after the assembly output has
>>> being done.  So, for example, pa_output_call is
>>> never called with a delayed branch sequence containing a
>>> NOTE_INSN_DELETED.
>> OK.  That's good to know.  I scanned final and final_scan_insn and see
>> a couple places where we delete insns, but if I'm reading the code
>> correctly, they would result in seeing the NOTE_INSN_DELETED rather
>> than a real insn in the output routines.
>>
>> So what code during final is deleting these insns?
>
> It's the PA backend.  For example,
>
>           /* If this isn't a sibcall, we put the load of %r27 into the
>              delay slot.  We can't do this in a sibcall as we don't
>              have a second call-clobbered scratch register available.  */
>           if (seq_length != 0
>               && ! JUMP_P (NEXT_INSN (insn))
>               && !sibcall)
>             {
>               final_scan_insn (NEXT_INSN (insn), asm_out_file,
>                                optimize, 0, NULL);
>
>               /* Now delete the delay insn.  */
>               SET_INSN_DELETED (NEXT_INSN (insn));
>               delay_insn_deleted = 1;
>             }
>
> The insn is deleted so that it won't be emitted again.  This is done in
> a bunch
> of places.
>
> What's new is the verification after assembly output.
Ah.  OK.  Glad to see I wasn't missing something in final.c.  Let me 
review things again, but I'm a *lot* less worried now :-)

Thanks for digging into this!

jeff
Jeff Law June 9, 2014, 4:41 p.m. UTC | #8
On 06/08/14 12:06, John David Anglin wrote:
> On 4-Jun-14, at 3:38 AM, Jeff Law wrote:
>
>> On 05/24/14 12:39, John David Anglin wrote:
>>>
>>> The insns are being deleted in "final" after the assembly output has
>>> being done.  So, for example, pa_output_call is
>>> never called with a delayed branch sequence containing a
>>> NOTE_INSN_DELETED.
>> OK.  That's good to know.  I scanned final and final_scan_insn and see
>> a couple places where we delete insns, but if I'm reading the code
>> correctly, they would result in seeing the NOTE_INSN_DELETED rather
>> than a real insn in the output routines.
>>
>> So what code during final is deleting these insns?
>
> It's the PA backend.  For example,
>
>           /* If this isn't a sibcall, we put the load of %r27 into the
>              delay slot.  We can't do this in a sibcall as we don't
>              have a second call-clobbered scratch register available.  */
>           if (seq_length != 0
>               && ! JUMP_P (NEXT_INSN (insn))
>               && !sibcall)
>             {
>               final_scan_insn (NEXT_INSN (insn), asm_out_file,
>                                optimize, 0, NULL);
>
>               /* Now delete the delay insn.  */
>               SET_INSN_DELETED (NEXT_INSN (insn));
>               delay_insn_deleted = 1;
>             }
>
> The insn is deleted so that it won't be emitted again.  This is done in
> a bunch
> of places.
>
> What's new is the verification after assembly output.
Right.  Thanks for the analysis.  I know it takes significant time.

The original patch is fine and I've installed it on your behalf.

Thanks again,
Jeff
John David Anglin June 9, 2014, 5:06 p.m. UTC | #9
On 6/9/2014 12:41 PM, Jeff Law wrote:
>> What's new is the verification after assembly output.
> Right.  Thanks for the analysis.  I know it takes significant time.
Not a problem.  Thanks for installing the change.

Dave
diff mbox

Patch

Index: emit-rtl.c
===================================================================
--- emit-rtl.c	(revision 210323)
+++ emit-rtl.c	(working copy)
@@ -2698,7 +2698,11 @@ 
 	  {
 	    gcc_assert (REG_NOTES (p) == NULL);
 	    for (int i = 0; i < XVECLEN (pat, 0); i++)
-	      reset_insn_used_flags (XVECEXP (pat, 0, i));
+	      {
+		rtx insn = XVECEXP (pat, 0, i);
+		if (INSN_P (insn))
+		  reset_insn_used_flags (insn);
+	      }
 	  }
       }
 }
@@ -2735,7 +2739,11 @@ 
 	  verify_insn_sharing (p);
 	else
 	  for (int i = 0; i < XVECLEN (pat, 0); i++)
-	    verify_insn_sharing (XVECEXP (pat, 0, i));
+	      {
+		rtx insn = XVECEXP (pat, 0, i);
+		if (INSN_P (insn))
+		  verify_insn_sharing (insn);
+	      }
       }
 
   reset_all_used_flags ();