diff mbox

Fix Eh delivery in partitioned functions

Message ID 20170718072624.GA52973@kam.mff.cuni.cz
State New
Headers show

Commit Message

Jan Hubicka July 18, 2017, 7:26 a.m. UTC
Hi,
this patch fixes wrong code issue with BB partitioning where sometimes EH
is not delivered.  This is very old issue that affect all release branches
with -fprofile-use, but recently surfaced as libstdc++ testsuite regression
because we now partition functions based on static profile prediction.

The problem is that EH tables are stored as offsets from start of functions.
In the record however value 0 is special and means that there is no landing
pad for a given region.  Normally this is safe because landing pads never
appear as very first label in function.  This is however no longer true with
partitining where cold partition is actually quite likely to start by landing
pad.

The change in except.c adds sanity check that no EH landing pads are very first
in the insn stream.  The change in bb-reorder makes reorder to chose
non-landing-pad BB as first trace for the cold partition. Such BB always exists
because landing pads must be in same partition as the instruction throwing them
and we never make BB both landing pad and reachable by normal control folow.
However I am not thrilled by the fix as it is bit fragile in case some
optimization happends after bb partitioning and code is moved away.  Also the
logic can be confused by asm statement which may result in no code (again
however the BB reachable from outside world should contain something that
produce EH that is a real instruction).

Ideas for better fix would be welcome then.  If the assert I added triggers
for valid reasons, we may just end up adding a NOP in the rare case we do
not suceed arranging cold partition to not start with landing pad.

Bootstrapped/regtested x86_64-linux, looks sane?

Honza

	PR middle-end/81331 
	* except.c (first_in_partition): New function.
	(dw2_output_call_site_table): Sanity check that landing pads are not
	very first in the partition.
	* bb-reorder.c (ok_to_be_first): New function.
	(connect_traces): Avoid traces that are !ok_to_be_first to start
	partitions.

Comments

Richard Biener July 18, 2017, 7:34 a.m. UTC | #1
On Tue, 18 Jul 2017, Jan Hubicka wrote:

> Hi,
> this patch fixes wrong code issue with BB partitioning where sometimes EH
> is not delivered.  This is very old issue that affect all release branches
> with -fprofile-use, but recently surfaced as libstdc++ testsuite regression
> because we now partition functions based on static profile prediction.
> 
> The problem is that EH tables are stored as offsets from start of functions.
> In the record however value 0 is special and means that there is no landing
> pad for a given region.  Normally this is safe because landing pads never
> appear as very first label in function.  This is however no longer true with
> partitining where cold partition is actually quite likely to start by landing
> pad.
> 
> The change in except.c adds sanity check that no EH landing pads are very first
> in the insn stream.  The change in bb-reorder makes reorder to chose
> non-landing-pad BB as first trace for the cold partition. Such BB always exists
> because landing pads must be in same partition as the instruction throwing them
> and we never make BB both landing pad and reachable by normal control folow.
> However I am not thrilled by the fix as it is bit fragile in case some
> optimization happends after bb partitioning and code is moved away.  Also the
> logic can be confused by asm statement which may result in no code (again
> however the BB reachable from outside world should contain something that
> produce EH that is a real instruction).
> 
> Ideas for better fix would be welcome then.  If the assert I added triggers
> for valid reasons, we may just end up adding a NOP in the rare case we do
> not suceed arranging cold partition to not start with landing pad.

Yeah, I'd rather pad the function start with a nop if it starts with a
landing pad.  How difficult would it be to arrange for this?  I suppose
we'd need to touch each and every target to accomplish this?  Or end up
using gen_nop in generic code?

Richard.

> Bootstrapped/regtested x86_64-linux, looks sane?
> 
> Honza
> 
> 	PR middle-end/81331 
> 	* except.c (first_in_partition): New function.
> 	(dw2_output_call_site_table): Sanity check that landing pads are not
> 	very first in the partition.
> 	* bb-reorder.c (ok_to_be_first): New function.
> 	(connect_traces): Avoid traces that are !ok_to_be_first to start
> 	partitions.
> Index: except.c
> ===================================================================
> --- except.c	(revision 250226)
> +++ except.c	(working copy)
> @@ -2724,6 +2724,23 @@ sjlj_size_of_call_site_table (void)
>    return size;
>  }
>  
> +/* Return true if L will appear as very first in its partition.  */
> +
> +bool
> +first_in_partition (rtx_insn *l)
> +{
> +  while (l != NULL_RTX)
> +    {
> +      if (active_insn_p (l))
> +	return false;
> +      else if (GET_CODE (l) == NOTE
> +	       && NOTE_KIND (l) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
> +	return true;
> +      l = PREV_INSN (l);
> +    }
> +  return true;
> +}
> +
>  static void
>  dw2_output_call_site_table (int cs_format, int section)
>  {
> @@ -2749,8 +2766,14 @@ dw2_output_call_site_table (int cs_forma
>        ASM_GENERATE_INTERNAL_LABEL (reg_end_lab, "LEHE", call_site_base + i);
>  
>        if (cs->landing_pad)
> -	ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L",
> -				     CODE_LABEL_NUMBER (cs->landing_pad));
> +	{
> +	  ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L",
> +				       CODE_LABEL_NUMBER (cs->landing_pad));
> +	  /* Be sure that the offset will not be 0 as that would make EH
> +	     delivery code to think that there is no landing pad.  */
> +	  gcc_checking_assert (!first_in_partition
> +				   (as_a <rtx_insn *> (cs->landing_pad)));
> +	}
>  
>        /* ??? Perhaps use insn length scaling if the assembler supports
>  	 generic arithmetic.  */
> Index: bb-reorder.c
> ===================================================================
> --- bb-reorder.c	(revision 250226)
> +++ bb-reorder.c	(working copy)
> @@ -1066,6 +1066,21 @@ connect_better_edge_p (const_edge e, boo
>    return is_better_edge;
>  }
>  
> +/* If we place EH landing pad as very first BB in the partition, its offset
> +   from start of function is 0 which is special cased by the eh table to mean
> +   no landing pad.  For this reason such BBs can not appear as very first in
> +   the partition.  */
> +static bool
> +ok_to_be_first (struct trace *t)
> +{
> +  edge e;
> +  edge_iterator ei;
> +  FOR_EACH_EDGE (e, ei, t->first->preds)
> +    if (e->flags & EDGE_EH)
> +      return false;
> +  return true;
> +}
> +
>  /* Connect traces in array TRACES, N_TRACES is the count of traces.  */
>  
>  static void
> @@ -1080,6 +1095,7 @@ connect_traces (int n_traces, struct tra
>    int freq_threshold;
>    gcov_type count_threshold;
>    bool for_size = optimize_function_for_size_p (cfun);
> +  bool first_in_partition;
>  
>    freq_threshold = max_entry_frequency * DUPLICATION_THRESHOLD / 1000;
>    if (max_entry_count.to_gcov_type () < INT_MAX / 1000)
> @@ -1092,6 +1108,7 @@ connect_traces (int n_traces, struct tra
>    current_pass = 1;
>    current_partition = BB_PARTITION (traces[0].first);
>    two_passes = false;
> +  first_in_partition = true;
>  
>    if (crtl->has_bb_partition)
>      for (i = 0; i < n_traces && !two_passes; i++)
> @@ -1116,6 +1133,7 @@ connect_traces (int n_traces, struct tra
>  	    current_partition = BB_COLD_PARTITION;
>  	  else
>  	    current_partition = BB_HOT_PARTITION;
> +	  first_in_partition = true;
>  	}
>  
>        if (connected[t])
> @@ -1125,6 +1143,9 @@ connect_traces (int n_traces, struct tra
>  	  && BB_PARTITION (traces[t].first) != current_partition)
>  	continue;
>  
> +      if (first_in_partition && !ok_to_be_first (&traces[t]))
> +	continue;
> +
>        connected[t] = true;
>  
>        /* Find the predecessor traces.  */
> @@ -1143,7 +1164,9 @@ connect_traces (int n_traces, struct tra
>  		  && bbd[si].end_of_trace >= 0
>  		  && !connected[bbd[si].end_of_trace]
>  		  && (BB_PARTITION (e->src) == current_partition)
> -		  && connect_better_edge_p (e, true, best_len, best, traces))
> +		  && connect_better_edge_p (e, true, best_len, best, traces)
> +		  && (!first_in_partition
> +		      || ok_to_be_first (&traces[bbd[si].end_of_trace])))
>  		{
>  		  best = e;
>  		  best_len = traces[bbd[si].end_of_trace].length;
> @@ -1151,6 +1174,8 @@ connect_traces (int n_traces, struct tra
>  	    }
>  	  if (best)
>  	    {
> +	      gcc_checking_assert (BB_PARTITION (best->src)
> +				   == BB_PARTITION (best->dest));
>  	      best->src->aux = best->dest;
>  	      t2 = bbd[best->src->index].end_of_trace;
>  	      connected[t2] = true;
> @@ -1166,8 +1191,13 @@ connect_traces (int n_traces, struct tra
>  	}
>  
>        if (last_trace >= 0)
> -	traces[last_trace].last->aux = traces[t2].first;
> +	{
> +	  gcc_checking_assert (!first_in_partition
> +			       || ok_to_be_first (&traces[t2]));
> +	  traces[last_trace].last->aux = traces[t2].first;
> +	}
>        last_trace = t;
> +      first_in_partition = false;
>  
>        /* Find the successor traces.  */
>        while (1)
> @@ -1226,6 +1256,8 @@ connect_traces (int n_traces, struct tra
>  		fprintf (dump_file, "Connection: %d %d\n",
>  			 best->src->index, best->dest->index);
>  
> +	      gcc_checking_assert (BB_PARTITION (best->dest)
> +				   == BB_PARTITION (best->src));
>  	      t = bbd[best->dest->index].start_of_trace;
>  	      traces[last_trace].last->aux = traces[t].first;
>  	      connected[t] = true;
> @@ -1238,6 +1270,8 @@ connect_traces (int n_traces, struct tra
>  		  fprintf (dump_file, "Connection: %d %d\n",
>  			   best->src->index, best->dest->index);
>  		}
> +	      gcc_checking_assert (BB_PARTITION (best->dest)
> +				   == BB_PARTITION (best->src));
>  	      t = bbd[best->dest->index].start_of_trace;
>  	      traces[last_trace].last->aux = traces[t].first;
>  	      connected[t] = true;
> 
>
Jan Hubicka July 18, 2017, 7:44 a.m. UTC | #2
> On Tue, 18 Jul 2017, Jan Hubicka wrote:
> 
> > Hi,
> > this patch fixes wrong code issue with BB partitioning where sometimes EH
> > is not delivered.  This is very old issue that affect all release branches
> > with -fprofile-use, but recently surfaced as libstdc++ testsuite regression
> > because we now partition functions based on static profile prediction.
> > 
> > The problem is that EH tables are stored as offsets from start of functions.
> > In the record however value 0 is special and means that there is no landing
> > pad for a given region.  Normally this is safe because landing pads never
> > appear as very first label in function.  This is however no longer true with
> > partitining where cold partition is actually quite likely to start by landing
> > pad.
> > 
> > The change in except.c adds sanity check that no EH landing pads are very first
> > in the insn stream.  The change in bb-reorder makes reorder to chose
> > non-landing-pad BB as first trace for the cold partition. Such BB always exists
> > because landing pads must be in same partition as the instruction throwing them
> > and we never make BB both landing pad and reachable by normal control folow.
> > However I am not thrilled by the fix as it is bit fragile in case some
> > optimization happends after bb partitioning and code is moved away.  Also the
> > logic can be confused by asm statement which may result in no code (again
> > however the BB reachable from outside world should contain something that
> > produce EH that is a real instruction).
> > 
> > Ideas for better fix would be welcome then.  If the assert I added triggers
> > for valid reasons, we may just end up adding a NOP in the rare case we do
> > not suceed arranging cold partition to not start with landing pad.
> 
> Yeah, I'd rather pad the function start with a nop if it starts with a
> landing pad.  How difficult would it be to arrange for this?  I suppose
> we'd need to touch each and every target to accomplish this?  Or end up
> using gen_nop in generic code?

I think we could just output from generic code - I think it can be done by
final_scan_insn. I don't know however if we have a way to tell if the section
starts with a landing pad?

Honza
> 
> Richard.
> 
> > Bootstrapped/regtested x86_64-linux, looks sane?
> > 
> > Honza
> > 
> > 	PR middle-end/81331 
> > 	* except.c (first_in_partition): New function.
> > 	(dw2_output_call_site_table): Sanity check that landing pads are not
> > 	very first in the partition.
> > 	* bb-reorder.c (ok_to_be_first): New function.
> > 	(connect_traces): Avoid traces that are !ok_to_be_first to start
> > 	partitions.
> > Index: except.c
> > ===================================================================
> > --- except.c	(revision 250226)
> > +++ except.c	(working copy)
> > @@ -2724,6 +2724,23 @@ sjlj_size_of_call_site_table (void)
> >    return size;
> >  }
> >  
> > +/* Return true if L will appear as very first in its partition.  */
> > +
> > +bool
> > +first_in_partition (rtx_insn *l)
> > +{
> > +  while (l != NULL_RTX)
> > +    {
> > +      if (active_insn_p (l))
> > +	return false;
> > +      else if (GET_CODE (l) == NOTE
> > +	       && NOTE_KIND (l) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
> > +	return true;
> > +      l = PREV_INSN (l);
> > +    }
> > +  return true;
> > +}
> > +
> >  static void
> >  dw2_output_call_site_table (int cs_format, int section)
> >  {
> > @@ -2749,8 +2766,14 @@ dw2_output_call_site_table (int cs_forma
> >        ASM_GENERATE_INTERNAL_LABEL (reg_end_lab, "LEHE", call_site_base + i);
> >  
> >        if (cs->landing_pad)
> > -	ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L",
> > -				     CODE_LABEL_NUMBER (cs->landing_pad));
> > +	{
> > +	  ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L",
> > +				       CODE_LABEL_NUMBER (cs->landing_pad));
> > +	  /* Be sure that the offset will not be 0 as that would make EH
> > +	     delivery code to think that there is no landing pad.  */
> > +	  gcc_checking_assert (!first_in_partition
> > +				   (as_a <rtx_insn *> (cs->landing_pad)));
> > +	}
> >  
> >        /* ??? Perhaps use insn length scaling if the assembler supports
> >  	 generic arithmetic.  */
> > Index: bb-reorder.c
> > ===================================================================
> > --- bb-reorder.c	(revision 250226)
> > +++ bb-reorder.c	(working copy)
> > @@ -1066,6 +1066,21 @@ connect_better_edge_p (const_edge e, boo
> >    return is_better_edge;
> >  }
> >  
> > +/* If we place EH landing pad as very first BB in the partition, its offset
> > +   from start of function is 0 which is special cased by the eh table to mean
> > +   no landing pad.  For this reason such BBs can not appear as very first in
> > +   the partition.  */
> > +static bool
> > +ok_to_be_first (struct trace *t)
> > +{
> > +  edge e;
> > +  edge_iterator ei;
> > +  FOR_EACH_EDGE (e, ei, t->first->preds)
> > +    if (e->flags & EDGE_EH)
> > +      return false;
> > +  return true;
> > +}
> > +
> >  /* Connect traces in array TRACES, N_TRACES is the count of traces.  */
> >  
> >  static void
> > @@ -1080,6 +1095,7 @@ connect_traces (int n_traces, struct tra
> >    int freq_threshold;
> >    gcov_type count_threshold;
> >    bool for_size = optimize_function_for_size_p (cfun);
> > +  bool first_in_partition;
> >  
> >    freq_threshold = max_entry_frequency * DUPLICATION_THRESHOLD / 1000;
> >    if (max_entry_count.to_gcov_type () < INT_MAX / 1000)
> > @@ -1092,6 +1108,7 @@ connect_traces (int n_traces, struct tra
> >    current_pass = 1;
> >    current_partition = BB_PARTITION (traces[0].first);
> >    two_passes = false;
> > +  first_in_partition = true;
> >  
> >    if (crtl->has_bb_partition)
> >      for (i = 0; i < n_traces && !two_passes; i++)
> > @@ -1116,6 +1133,7 @@ connect_traces (int n_traces, struct tra
> >  	    current_partition = BB_COLD_PARTITION;
> >  	  else
> >  	    current_partition = BB_HOT_PARTITION;
> > +	  first_in_partition = true;
> >  	}
> >  
> >        if (connected[t])
> > @@ -1125,6 +1143,9 @@ connect_traces (int n_traces, struct tra
> >  	  && BB_PARTITION (traces[t].first) != current_partition)
> >  	continue;
> >  
> > +      if (first_in_partition && !ok_to_be_first (&traces[t]))
> > +	continue;
> > +
> >        connected[t] = true;
> >  
> >        /* Find the predecessor traces.  */
> > @@ -1143,7 +1164,9 @@ connect_traces (int n_traces, struct tra
> >  		  && bbd[si].end_of_trace >= 0
> >  		  && !connected[bbd[si].end_of_trace]
> >  		  && (BB_PARTITION (e->src) == current_partition)
> > -		  && connect_better_edge_p (e, true, best_len, best, traces))
> > +		  && connect_better_edge_p (e, true, best_len, best, traces)
> > +		  && (!first_in_partition
> > +		      || ok_to_be_first (&traces[bbd[si].end_of_trace])))
> >  		{
> >  		  best = e;
> >  		  best_len = traces[bbd[si].end_of_trace].length;
> > @@ -1151,6 +1174,8 @@ connect_traces (int n_traces, struct tra
> >  	    }
> >  	  if (best)
> >  	    {
> > +	      gcc_checking_assert (BB_PARTITION (best->src)
> > +				   == BB_PARTITION (best->dest));
> >  	      best->src->aux = best->dest;
> >  	      t2 = bbd[best->src->index].end_of_trace;
> >  	      connected[t2] = true;
> > @@ -1166,8 +1191,13 @@ connect_traces (int n_traces, struct tra
> >  	}
> >  
> >        if (last_trace >= 0)
> > -	traces[last_trace].last->aux = traces[t2].first;
> > +	{
> > +	  gcc_checking_assert (!first_in_partition
> > +			       || ok_to_be_first (&traces[t2]));
> > +	  traces[last_trace].last->aux = traces[t2].first;
> > +	}
> >        last_trace = t;
> > +      first_in_partition = false;
> >  
> >        /* Find the successor traces.  */
> >        while (1)
> > @@ -1226,6 +1256,8 @@ connect_traces (int n_traces, struct tra
> >  		fprintf (dump_file, "Connection: %d %d\n",
> >  			 best->src->index, best->dest->index);
> >  
> > +	      gcc_checking_assert (BB_PARTITION (best->dest)
> > +				   == BB_PARTITION (best->src));
> >  	      t = bbd[best->dest->index].start_of_trace;
> >  	      traces[last_trace].last->aux = traces[t].first;
> >  	      connected[t] = true;
> > @@ -1238,6 +1270,8 @@ connect_traces (int n_traces, struct tra
> >  		  fprintf (dump_file, "Connection: %d %d\n",
> >  			   best->src->index, best->dest->index);
> >  		}
> > +	      gcc_checking_assert (BB_PARTITION (best->dest)
> > +				   == BB_PARTITION (best->src));
> >  	      t = bbd[best->dest->index].start_of_trace;
> >  	      traces[last_trace].last->aux = traces[t].first;
> >  	      connected[t] = true;
> > 
> > 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)
Richard Biener July 18, 2017, 7:45 a.m. UTC | #3
On Tue, 18 Jul 2017, Jan Hubicka wrote:

> > On Tue, 18 Jul 2017, Jan Hubicka wrote:
> > 
> > > Hi,
> > > this patch fixes wrong code issue with BB partitioning where sometimes EH
> > > is not delivered.  This is very old issue that affect all release branches
> > > with -fprofile-use, but recently surfaced as libstdc++ testsuite regression
> > > because we now partition functions based on static profile prediction.
> > > 
> > > The problem is that EH tables are stored as offsets from start of functions.
> > > In the record however value 0 is special and means that there is no landing
> > > pad for a given region.  Normally this is safe because landing pads never
> > > appear as very first label in function.  This is however no longer true with
> > > partitining where cold partition is actually quite likely to start by landing
> > > pad.
> > > 
> > > The change in except.c adds sanity check that no EH landing pads are very first
> > > in the insn stream.  The change in bb-reorder makes reorder to chose
> > > non-landing-pad BB as first trace for the cold partition. Such BB always exists
> > > because landing pads must be in same partition as the instruction throwing them
> > > and we never make BB both landing pad and reachable by normal control folow.
> > > However I am not thrilled by the fix as it is bit fragile in case some
> > > optimization happends after bb partitioning and code is moved away.  Also the
> > > logic can be confused by asm statement which may result in no code (again
> > > however the BB reachable from outside world should contain something that
> > > produce EH that is a real instruction).
> > > 
> > > Ideas for better fix would be welcome then.  If the assert I added triggers
> > > for valid reasons, we may just end up adding a NOP in the rare case we do
> > > not suceed arranging cold partition to not start with landing pad.
> > 
> > Yeah, I'd rather pad the function start with a nop if it starts with a
> > landing pad.  How difficult would it be to arrange for this?  I suppose
> > we'd need to touch each and every target to accomplish this?  Or end up
> > using gen_nop in generic code?
> 
> I think we could just output from generic code - I think it can be done by
> final_scan_insn. I don't know however if we have a way to tell if the section
> starts with a landing pad?

Not sure either -- some insn note / bb note?  Some flag on the label?
At least the latter should be easy to add if it's not there already.

Richard.

> Honza
> > 
> > Richard.
> > 
> > > Bootstrapped/regtested x86_64-linux, looks sane?
> > > 
> > > Honza
> > > 
> > > 	PR middle-end/81331 
> > > 	* except.c (first_in_partition): New function.
> > > 	(dw2_output_call_site_table): Sanity check that landing pads are not
> > > 	very first in the partition.
> > > 	* bb-reorder.c (ok_to_be_first): New function.
> > > 	(connect_traces): Avoid traces that are !ok_to_be_first to start
> > > 	partitions.
> > > Index: except.c
> > > ===================================================================
> > > --- except.c	(revision 250226)
> > > +++ except.c	(working copy)
> > > @@ -2724,6 +2724,23 @@ sjlj_size_of_call_site_table (void)
> > >    return size;
> > >  }
> > >  
> > > +/* Return true if L will appear as very first in its partition.  */
> > > +
> > > +bool
> > > +first_in_partition (rtx_insn *l)
> > > +{
> > > +  while (l != NULL_RTX)
> > > +    {
> > > +      if (active_insn_p (l))
> > > +	return false;
> > > +      else if (GET_CODE (l) == NOTE
> > > +	       && NOTE_KIND (l) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
> > > +	return true;
> > > +      l = PREV_INSN (l);
> > > +    }
> > > +  return true;
> > > +}
> > > +
> > >  static void
> > >  dw2_output_call_site_table (int cs_format, int section)
> > >  {
> > > @@ -2749,8 +2766,14 @@ dw2_output_call_site_table (int cs_forma
> > >        ASM_GENERATE_INTERNAL_LABEL (reg_end_lab, "LEHE", call_site_base + i);
> > >  
> > >        if (cs->landing_pad)
> > > -	ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L",
> > > -				     CODE_LABEL_NUMBER (cs->landing_pad));
> > > +	{
> > > +	  ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L",
> > > +				       CODE_LABEL_NUMBER (cs->landing_pad));
> > > +	  /* Be sure that the offset will not be 0 as that would make EH
> > > +	     delivery code to think that there is no landing pad.  */
> > > +	  gcc_checking_assert (!first_in_partition
> > > +				   (as_a <rtx_insn *> (cs->landing_pad)));
> > > +	}
> > >  
> > >        /* ??? Perhaps use insn length scaling if the assembler supports
> > >  	 generic arithmetic.  */
> > > Index: bb-reorder.c
> > > ===================================================================
> > > --- bb-reorder.c	(revision 250226)
> > > +++ bb-reorder.c	(working copy)
> > > @@ -1066,6 +1066,21 @@ connect_better_edge_p (const_edge e, boo
> > >    return is_better_edge;
> > >  }
> > >  
> > > +/* If we place EH landing pad as very first BB in the partition, its offset
> > > +   from start of function is 0 which is special cased by the eh table to mean
> > > +   no landing pad.  For this reason such BBs can not appear as very first in
> > > +   the partition.  */
> > > +static bool
> > > +ok_to_be_first (struct trace *t)
> > > +{
> > > +  edge e;
> > > +  edge_iterator ei;
> > > +  FOR_EACH_EDGE (e, ei, t->first->preds)
> > > +    if (e->flags & EDGE_EH)
> > > +      return false;
> > > +  return true;
> > > +}
> > > +
> > >  /* Connect traces in array TRACES, N_TRACES is the count of traces.  */
> > >  
> > >  static void
> > > @@ -1080,6 +1095,7 @@ connect_traces (int n_traces, struct tra
> > >    int freq_threshold;
> > >    gcov_type count_threshold;
> > >    bool for_size = optimize_function_for_size_p (cfun);
> > > +  bool first_in_partition;
> > >  
> > >    freq_threshold = max_entry_frequency * DUPLICATION_THRESHOLD / 1000;
> > >    if (max_entry_count.to_gcov_type () < INT_MAX / 1000)
> > > @@ -1092,6 +1108,7 @@ connect_traces (int n_traces, struct tra
> > >    current_pass = 1;
> > >    current_partition = BB_PARTITION (traces[0].first);
> > >    two_passes = false;
> > > +  first_in_partition = true;
> > >  
> > >    if (crtl->has_bb_partition)
> > >      for (i = 0; i < n_traces && !two_passes; i++)
> > > @@ -1116,6 +1133,7 @@ connect_traces (int n_traces, struct tra
> > >  	    current_partition = BB_COLD_PARTITION;
> > >  	  else
> > >  	    current_partition = BB_HOT_PARTITION;
> > > +	  first_in_partition = true;
> > >  	}
> > >  
> > >        if (connected[t])
> > > @@ -1125,6 +1143,9 @@ connect_traces (int n_traces, struct tra
> > >  	  && BB_PARTITION (traces[t].first) != current_partition)
> > >  	continue;
> > >  
> > > +      if (first_in_partition && !ok_to_be_first (&traces[t]))
> > > +	continue;
> > > +
> > >        connected[t] = true;
> > >  
> > >        /* Find the predecessor traces.  */
> > > @@ -1143,7 +1164,9 @@ connect_traces (int n_traces, struct tra
> > >  		  && bbd[si].end_of_trace >= 0
> > >  		  && !connected[bbd[si].end_of_trace]
> > >  		  && (BB_PARTITION (e->src) == current_partition)
> > > -		  && connect_better_edge_p (e, true, best_len, best, traces))
> > > +		  && connect_better_edge_p (e, true, best_len, best, traces)
> > > +		  && (!first_in_partition
> > > +		      || ok_to_be_first (&traces[bbd[si].end_of_trace])))
> > >  		{
> > >  		  best = e;
> > >  		  best_len = traces[bbd[si].end_of_trace].length;
> > > @@ -1151,6 +1174,8 @@ connect_traces (int n_traces, struct tra
> > >  	    }
> > >  	  if (best)
> > >  	    {
> > > +	      gcc_checking_assert (BB_PARTITION (best->src)
> > > +				   == BB_PARTITION (best->dest));
> > >  	      best->src->aux = best->dest;
> > >  	      t2 = bbd[best->src->index].end_of_trace;
> > >  	      connected[t2] = true;
> > > @@ -1166,8 +1191,13 @@ connect_traces (int n_traces, struct tra
> > >  	}
> > >  
> > >        if (last_trace >= 0)
> > > -	traces[last_trace].last->aux = traces[t2].first;
> > > +	{
> > > +	  gcc_checking_assert (!first_in_partition
> > > +			       || ok_to_be_first (&traces[t2]));
> > > +	  traces[last_trace].last->aux = traces[t2].first;
> > > +	}
> > >        last_trace = t;
> > > +      first_in_partition = false;
> > >  
> > >        /* Find the successor traces.  */
> > >        while (1)
> > > @@ -1226,6 +1256,8 @@ connect_traces (int n_traces, struct tra
> > >  		fprintf (dump_file, "Connection: %d %d\n",
> > >  			 best->src->index, best->dest->index);
> > >  
> > > +	      gcc_checking_assert (BB_PARTITION (best->dest)
> > > +				   == BB_PARTITION (best->src));
> > >  	      t = bbd[best->dest->index].start_of_trace;
> > >  	      traces[last_trace].last->aux = traces[t].first;
> > >  	      connected[t] = true;
> > > @@ -1238,6 +1270,8 @@ connect_traces (int n_traces, struct tra
> > >  		  fprintf (dump_file, "Connection: %d %d\n",
> > >  			   best->src->index, best->dest->index);
> > >  		}
> > > +	      gcc_checking_assert (BB_PARTITION (best->dest)
> > > +				   == BB_PARTITION (best->src));
> > >  	      t = bbd[best->dest->index].start_of_trace;
> > >  	      traces[last_trace].last->aux = traces[t].first;
> > >  	      connected[t] = true;
> > > 
> > > 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)
> 
>
diff mbox

Patch

Index: except.c
===================================================================
--- except.c	(revision 250226)
+++ except.c	(working copy)
@@ -2724,6 +2724,23 @@  sjlj_size_of_call_site_table (void)
   return size;
 }
 
+/* Return true if L will appear as very first in its partition.  */
+
+bool
+first_in_partition (rtx_insn *l)
+{
+  while (l != NULL_RTX)
+    {
+      if (active_insn_p (l))
+	return false;
+      else if (GET_CODE (l) == NOTE
+	       && NOTE_KIND (l) == NOTE_INSN_SWITCH_TEXT_SECTIONS)
+	return true;
+      l = PREV_INSN (l);
+    }
+  return true;
+}
+
 static void
 dw2_output_call_site_table (int cs_format, int section)
 {
@@ -2749,8 +2766,14 @@  dw2_output_call_site_table (int cs_forma
       ASM_GENERATE_INTERNAL_LABEL (reg_end_lab, "LEHE", call_site_base + i);
 
       if (cs->landing_pad)
-	ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L",
-				     CODE_LABEL_NUMBER (cs->landing_pad));
+	{
+	  ASM_GENERATE_INTERNAL_LABEL (landing_pad_lab, "L",
+				       CODE_LABEL_NUMBER (cs->landing_pad));
+	  /* Be sure that the offset will not be 0 as that would make EH
+	     delivery code to think that there is no landing pad.  */
+	  gcc_checking_assert (!first_in_partition
+				   (as_a <rtx_insn *> (cs->landing_pad)));
+	}
 
       /* ??? Perhaps use insn length scaling if the assembler supports
 	 generic arithmetic.  */
Index: bb-reorder.c
===================================================================
--- bb-reorder.c	(revision 250226)
+++ bb-reorder.c	(working copy)
@@ -1066,6 +1066,21 @@  connect_better_edge_p (const_edge e, boo
   return is_better_edge;
 }
 
+/* If we place EH landing pad as very first BB in the partition, its offset
+   from start of function is 0 which is special cased by the eh table to mean
+   no landing pad.  For this reason such BBs can not appear as very first in
+   the partition.  */
+static bool
+ok_to_be_first (struct trace *t)
+{
+  edge e;
+  edge_iterator ei;
+  FOR_EACH_EDGE (e, ei, t->first->preds)
+    if (e->flags & EDGE_EH)
+      return false;
+  return true;
+}
+
 /* Connect traces in array TRACES, N_TRACES is the count of traces.  */
 
 static void
@@ -1080,6 +1095,7 @@  connect_traces (int n_traces, struct tra
   int freq_threshold;
   gcov_type count_threshold;
   bool for_size = optimize_function_for_size_p (cfun);
+  bool first_in_partition;
 
   freq_threshold = max_entry_frequency * DUPLICATION_THRESHOLD / 1000;
   if (max_entry_count.to_gcov_type () < INT_MAX / 1000)
@@ -1092,6 +1108,7 @@  connect_traces (int n_traces, struct tra
   current_pass = 1;
   current_partition = BB_PARTITION (traces[0].first);
   two_passes = false;
+  first_in_partition = true;
 
   if (crtl->has_bb_partition)
     for (i = 0; i < n_traces && !two_passes; i++)
@@ -1116,6 +1133,7 @@  connect_traces (int n_traces, struct tra
 	    current_partition = BB_COLD_PARTITION;
 	  else
 	    current_partition = BB_HOT_PARTITION;
+	  first_in_partition = true;
 	}
 
       if (connected[t])
@@ -1125,6 +1143,9 @@  connect_traces (int n_traces, struct tra
 	  && BB_PARTITION (traces[t].first) != current_partition)
 	continue;
 
+      if (first_in_partition && !ok_to_be_first (&traces[t]))
+	continue;
+
       connected[t] = true;
 
       /* Find the predecessor traces.  */
@@ -1143,7 +1164,9 @@  connect_traces (int n_traces, struct tra
 		  && bbd[si].end_of_trace >= 0
 		  && !connected[bbd[si].end_of_trace]
 		  && (BB_PARTITION (e->src) == current_partition)
-		  && connect_better_edge_p (e, true, best_len, best, traces))
+		  && connect_better_edge_p (e, true, best_len, best, traces)
+		  && (!first_in_partition
+		      || ok_to_be_first (&traces[bbd[si].end_of_trace])))
 		{
 		  best = e;
 		  best_len = traces[bbd[si].end_of_trace].length;
@@ -1151,6 +1174,8 @@  connect_traces (int n_traces, struct tra
 	    }
 	  if (best)
 	    {
+	      gcc_checking_assert (BB_PARTITION (best->src)
+				   == BB_PARTITION (best->dest));
 	      best->src->aux = best->dest;
 	      t2 = bbd[best->src->index].end_of_trace;
 	      connected[t2] = true;
@@ -1166,8 +1191,13 @@  connect_traces (int n_traces, struct tra
 	}
 
       if (last_trace >= 0)
-	traces[last_trace].last->aux = traces[t2].first;
+	{
+	  gcc_checking_assert (!first_in_partition
+			       || ok_to_be_first (&traces[t2]));
+	  traces[last_trace].last->aux = traces[t2].first;
+	}
       last_trace = t;
+      first_in_partition = false;
 
       /* Find the successor traces.  */
       while (1)
@@ -1226,6 +1256,8 @@  connect_traces (int n_traces, struct tra
 		fprintf (dump_file, "Connection: %d %d\n",
 			 best->src->index, best->dest->index);
 
+	      gcc_checking_assert (BB_PARTITION (best->dest)
+				   == BB_PARTITION (best->src));
 	      t = bbd[best->dest->index].start_of_trace;
 	      traces[last_trace].last->aux = traces[t].first;
 	      connected[t] = true;
@@ -1238,6 +1270,8 @@  connect_traces (int n_traces, struct tra
 		  fprintf (dump_file, "Connection: %d %d\n",
 			   best->src->index, best->dest->index);
 		}
+	      gcc_checking_assert (BB_PARTITION (best->dest)
+				   == BB_PARTITION (best->src));
 	      t = bbd[best->dest->index].start_of_trace;
 	      traces[last_trace].last->aux = traces[t].first;
 	      connected[t] = true;