diff mbox

[dataflow] PR47525 DCE fails to eliminate dead calls to pure functions

Message ID 1296255975.2625.41.camel@otta
State New
Headers show

Commit Message

Peter Bergner Jan. 28, 2011, 11:06 p.m. UTC
Tracking down some test suite failures while doing a --with-cpu=power7 build,
I noticed that DCE is no longer eliminating dead calls to const or pure
function calls.  This is due to all global registers being added to every
call's use and def chains, even though const functions won't reference them
at all and pure functions won't set them.

The following patch fixes that and has bootstrapped and regtested with
no regressions.  This is a regression since it works in gcc 4.3, but
fails in gcc 4.4, 4.5 and trunk, but I understand it only a performance
issue and not a correctness issue.

Is that patch OK?  If so, do we want this in mainline now or after 4.6
has branched?

Peter


	PR rtl-optimization/47525
	* df-scan.c: Update copyright years.
	(df_get_call_refs): Do not mark global registers as DF_REF_REG_USE
	and non-clobber DF_REF_REG_DEF for calls to const and pure functions.

Comments

Kenneth Zadeck Jan. 28, 2011, 11:09 p.m. UTC | #1
the patch is ok for inclusion in some version.

a release manager must approve it for 4.6.

Kenny

On 01/28/2011 06:06 PM, Peter Bergner wrote:
> Tracking down some test suite failures while doing a --with-cpu=power7 build,
> I noticed that DCE is no longer eliminating dead calls to const or pure
> function calls.  This is due to all global registers being added to every
> call's use and def chains, even though const functions won't reference them
> at all and pure functions won't set them.
>
> The following patch fixes that and has bootstrapped and regtested with
> no regressions.  This is a regression since it works in gcc 4.3, but
> fails in gcc 4.4, 4.5 and trunk, but I understand it only a performance
> issue and not a correctness issue.
>
> Is that patch OK?  If so, do we want this in mainline now or after 4.6
> has branched?
>
> Peter
>
>
> 	PR rtl-optimization/47525
> 	* df-scan.c: Update copyright years.
> 	(df_get_call_refs): Do not mark global registers as DF_REF_REG_USE
> 	and non-clobber DF_REF_REG_DEF for calls to const and pure functions.
>
> Index: df-scan.c
> ===================================================================
> --- df-scan.c	(revision 169365)
> +++ df-scan.c	(working copy)
> @@ -1,6 +1,6 @@
>   /* Scanning of rtl for dataflow analysis.
>      Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
> -   2008, 2009, 2010 Free Software Foundation, Inc.
> +   2008, 2009, 2010, 2011 Free Software Foundation, Inc.
>      Originally contributed by Michael P. Hayes
>                (m.hayes@elec.canterbury.ac.nz, mhayes@redhat.com)
>      Major rewrite contributed by Danny Berlin (dberlin@dberlin.org)
> @@ -3360,16 +3360,19 @@ df_get_call_refs (struct df_collection_r
>   		 NULL, bb, insn_info, DF_REF_REG_USE,
>   		 DF_REF_CALL_STACK_USAGE | flags);
>
> -  /* Calls may also reference any of the global registers,
> -     so they are recorded as used.  */
> -  for (i = 0; i<  FIRST_PSEUDO_REGISTER; i++)
> -    if (global_regs[i])
> -      {
> -	df_ref_record (DF_REF_BASE, collection_rec, regno_reg_rtx[i],
> -		       NULL, bb, insn_info, DF_REF_REG_USE, flags);
> -	df_ref_record (DF_REF_BASE, collection_rec, regno_reg_rtx[i],
> -		       NULL, bb, insn_info, DF_REF_REG_DEF, flags);
> -      }
> +  /* Calls to const functions cannot access any global registers and calls to
> +     pure functions cannot set them.  All other calls may reference any of the
> +     global registers, so they are recorded as used.  */
> +  if (!RTL_CONST_CALL_P (insn_info->insn))
> +    for (i = 0; i<  FIRST_PSEUDO_REGISTER; i++)
> +      if (global_regs[i])
> +	{
> +	  df_ref_record (DF_REF_BASE, collection_rec, regno_reg_rtx[i],
> +			 NULL, bb, insn_info, DF_REF_REG_USE, flags);
> +	  if (!RTL_PURE_CALL_P (insn_info->insn))
> +	    df_ref_record (DF_REF_BASE, collection_rec, regno_reg_rtx[i],
> +			   NULL, bb, insn_info, DF_REF_REG_DEF, flags);
> +	}
>
>     is_sibling_call = SIBLING_CALL_P (insn_info->insn);
>     EXECUTE_IF_SET_IN_BITMAP (regs_invalidated_by_call_regset, 0, ui, bi)
>
>
Paolo Bonzini Jan. 29, 2011, 10:54 a.m. UTC | #2
On Sat, Jan 29, 2011 at 00:06, Peter Bergner <bergner@vnet.ibm.com> wrote:
> Tracking down some test suite failures while doing a --with-cpu=power7 build,
> I noticed that DCE is no longer eliminating dead calls to const or pure
> function calls.  This is due to all global registers being added to every
> call's use and def chains, even though const functions won't reference them
> at all and pure functions won't set them.
>
> The following patch fixes that and has bootstrapped and regtested with
> no regressions.  This is a regression since it works in gcc 4.3, but
> fails in gcc 4.4, 4.5 and trunk, but I understand it only a performance
> issue and not a correctness issue.
>
> Is that patch OK?  If so, do we want this in mainline now or after 4.6
> has branched?

Since this is a regression, ok for 4.6 but please bootstrap it on an
x86 machine too just for the sake of coverage.

Paolo
Richard Biener Jan. 31, 2011, 12:21 p.m. UTC | #3
On Sat, Jan 29, 2011 at 11:54 AM, Paolo Bonzini <bonzini@gnu.org> wrote:
> On Sat, Jan 29, 2011 at 00:06, Peter Bergner <bergner@vnet.ibm.com> wrote:
>> Tracking down some test suite failures while doing a --with-cpu=power7 build,
>> I noticed that DCE is no longer eliminating dead calls to const or pure
>> function calls.  This is due to all global registers being added to every
>> call's use and def chains, even though const functions won't reference them
>> at all and pure functions won't set them.
>>
>> The following patch fixes that and has bootstrapped and regtested with
>> no regressions.  This is a regression since it works in gcc 4.3, but
>> fails in gcc 4.4, 4.5 and trunk, but I understand it only a performance
>> issue and not a correctness issue.
>>
>> Is that patch OK?  If so, do we want this in mainline now or after 4.6
>> has branched?
>
> Since this is a regression, ok for 4.6 but please bootstrap it on an
> x86 machine too just for the sake of coverage.

I don't think the testcase is valid.

extern int link_failure (int) __attribute__ ((pure));
extern void no_return (void) __attribute__ ((noreturn,pure));
int
main (void)
{
  if (link_failure (0) < 1)
    no_return ();
  return 0;
}

no_return might be implemented as

no_return() { while (1);}

which means we can't DCE either call.

Richard.

> Paolo
>
Richard Biener Jan. 31, 2011, 12:24 p.m. UTC | #4
On Mon, Jan 31, 2011 at 1:21 PM, Richard Guenther
<richard.guenther@gmail.com> wrote:
> On Sat, Jan 29, 2011 at 11:54 AM, Paolo Bonzini <bonzini@gnu.org> wrote:
>> On Sat, Jan 29, 2011 at 00:06, Peter Bergner <bergner@vnet.ibm.com> wrote:
>>> Tracking down some test suite failures while doing a --with-cpu=power7 build,
>>> I noticed that DCE is no longer eliminating dead calls to const or pure
>>> function calls.  This is due to all global registers being added to every
>>> call's use and def chains, even though const functions won't reference them
>>> at all and pure functions won't set them.
>>>
>>> The following patch fixes that and has bootstrapped and regtested with
>>> no regressions.  This is a regression since it works in gcc 4.3, but
>>> fails in gcc 4.4, 4.5 and trunk, but I understand it only a performance
>>> issue and not a correctness issue.
>>>
>>> Is that patch OK?  If so, do we want this in mainline now or after 4.6
>>> has branched?
>>
>> Since this is a regression, ok for 4.6 but please bootstrap it on an
>> x86 machine too just for the sake of coverage.
>
> I don't think the testcase is valid.
>
> extern int link_failure (int) __attribute__ ((pure));
> extern void no_return (void) __attribute__ ((noreturn,pure));
> int
> main (void)
> {
>  if (link_failure (0) < 1)
>    no_return ();
>  return 0;
> }
>
> no_return might be implemented as
>
> no_return() { while (1);}
>
> which means we can't DCE either call.

Honza - you added that looping-const-or-pure stuff(?), I think we need
to treat pure and const annotated fns as looping (at least for functions
also marked noreturn).  OTOH, noreturn, pure does not make much
sense (it would just mean there's no side-effect apart from not returning).

Richard.

> Richard.
>
>> Paolo
>>
>
Kenneth Zadeck Jan. 31, 2011, 12:24 p.m. UTC | #5
On 01/31/2011 07:21 AM, Richard Guenther wrote:
> On Sat, Jan 29, 2011 at 11:54 AM, Paolo Bonzini<bonzini@gnu.org>  wrote:
>> On Sat, Jan 29, 2011 at 00:06, Peter Bergner<bergner@vnet.ibm.com>  wrote:
>>> Tracking down some test suite failures while doing a --with-cpu=power7 build,
>>> I noticed that DCE is no longer eliminating dead calls to const or pure
>>> function calls.  This is due to all global registers being added to every
>>> call's use and def chains, even though const functions won't reference them
>>> at all and pure functions won't set them.
>>>
>>> The following patch fixes that and has bootstrapped and regtested with
>>> no regressions.  This is a regression since it works in gcc 4.3, but
>>> fails in gcc 4.4, 4.5 and trunk, but I understand it only a performance
>>> issue and not a correctness issue.
>>>
>>> Is that patch OK?  If so, do we want this in mainline now or after 4.6
>>> has branched?
>> Since this is a regression, ok for 4.6 but please bootstrap it on an
>> x86 machine too just for the sake of coverage.
> I don't think the testcase is valid.
>
> extern int link_failure (int) __attribute__ ((pure));
> extern void no_return (void) __attribute__ ((noreturn,pure));
> int
> main (void)
> {
>    if (link_failure (0)<  1)
>      no_return ();
>    return 0;
> }
>
> no_return might be implemented as
>
> no_return() { while (1);}
>
> which means we can't DCE either call.
>
> Richard.
>
i think that i would argue that such an implementation of no_return 
should not have been marked as pure.   the point of pure is that you can 
remove them
>> Paolo
>>
Jan Hubicka Jan. 31, 2011, 12:30 p.m. UTC | #6
> Honza - you added that looping-const-or-pure stuff(?), I think we need

Kenny added them.

> to treat pure and const annotated fns as looping (at least for functions
> also marked noreturn).  OTOH, noreturn, pure does not make much
> sense (it would just mean there's no side-effect apart from not returning).

Well, "pure" function marked with the attribute is intedned to be removable.
looping-const-or-pure is for functions detected internally to have no memory
stores but to not be removable because they may not return.  
We have no "looping-pure" function attribute.

@item pure
@cindex @code{pure} function attribute
Many functions have no effects except the return value and their
return value depends only on the parameters and/or global variables.

Never returninging is an sice effect and the the testcase is invalid.

Honza
> 
> Richard.
> 
> > Richard.
> >
> >> Paolo
> >>
> >
Kenneth Zadeck Jan. 31, 2011, 12:34 p.m. UTC | #7
The truth is that this is a language lawyer question and not a question 
for the optimization people.  Because it is the job of optimization 
people to push the definitions as hard as possible.  From my point of 
view, when someone says pure, they are asking for the function to be 
removed under the proper conditions.

Kenny

On 01/31/2011 07:30 AM, Jan Hubicka wrote:
>> Honza - you added that looping-const-or-pure stuff(?), I think we need
> Kenny added them.
>
>> to treat pure and const annotated fns as looping (at least for functions
>> also marked noreturn).  OTOH, noreturn, pure does not make much
>> sense (it would just mean there's no side-effect apart from not returning).
> Well, "pure" function marked with the attribute is intedned to be removable.
> looping-const-or-pure is for functions detected internally to have no memory
> stores but to not be removable because they may not return.
> We have no "looping-pure" function attribute.
>
> @item pure
> @cindex @code{pure} function attribute
> Many functions have no effects except the return value and their
> return value depends only on the parameters and/or global variables.
>
> Never returninging is an sice effect and the the testcase is invalid.
>
> Honza
>> Richard.
>>
>>> Richard.
>>>
>>>> Paolo
>>>>
Jan Hubicka Jan. 31, 2011, 12:41 p.m. UTC | #8
> The truth is that this is a language lawyer question and not a question  
> for the optimization people.  Because it is the job of optimization  
> people to push the definitions as hard as possible.  From my point of  
> view, when someone says pure, they are asking for the function to be  
> removed under the proper conditions.

We seem to be arguing same way here.  "pure" function attribute means that
function is removable.
Internally detected pure flag in adition with looping-const-or-pure flag
means function is not removable.

What probably went wrong is that originally "pure" functions was implemented by
adding memory use and const flag on the call statement (to make RTL memory
analysis discover there are no side effects, but the statement reads all
memory) and by wrapping call within libcall notes (to make DCE discover that it
can remove it).

Internally detected pure&looping functions was implemented by only annotating the
call statement, but not building the libcall.  At that point RTL land never removed
non-libcall call.

Now when libcalls are gone and if DF based DCE was updated to remove call
statements by itself, we need to annotate those statements if they are looping
or not.  Alternatively, for 4.6, we can also just drop the annotations on
looping pure/consts and rely on GIMPLE land to do enough optimization here.
(this is probably something we would want to revisit later, since pure flag
is useful for scheduling)

Honza
Jan Hubicka Jan. 31, 2011, 12:45 p.m. UTC | #9
> > The truth is that this is a language lawyer question and not a question  
> > for the optimization people.  Because it is the job of optimization  
> > people to push the definitions as hard as possible.  From my point of  
> > view, when someone says pure, they are asking for the function to be  
> > removed under the proper conditions.
> 
> We seem to be arguing same way here.  "pure" function attribute means that
> function is removable.
> Internally detected pure flag in adition with looping-const-or-pure flag
> means function is not removable.
> 
> What probably went wrong is that originally "pure" functions was implemented by
> adding memory use and const flag on the call statement (to make RTL memory
> analysis discover there are no side effects, but the statement reads all
> memory) and by wrapping call within libcall notes (to make DCE discover that it
> can remove it).
> 
> Internally detected pure&looping functions was implemented by only annotating the
> call statement, but not building the libcall.  At that point RTL land never removed
> non-libcall call.
> 
> Now when libcalls are gone and if DF based DCE was updated to remove call
> statements by itself, we need to annotate those statements if they are looping
> or not.  Alternatively, for 4.6, we can also just drop the annotations on

Hmm, actually we have RTL_LOOPING_CONST_OR_PURE_CALL_P, so I see no problem.
I will try to look into the thread more to figure out what it is all about

Honza

> looping pure/consts and rely on GIMPLE land to do enough optimization here.
> (this is probably something we would want to revisit later, since pure flag
> is useful for scheduling)
> 
> Honza
Jan Hubicka Jan. 31, 2011, 12:50 p.m. UTC | #10
> Hmm, actually we have RTL_LOOPING_CONST_OR_PURE_CALL_P, so I see no problem.
> I will try to look into the thread more to figure out what it is all about

OK, so I think that Peter's patch is fine.  The testcase attached to 
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47525
is indeed nonsential.  I think noreturn flag there is needed only to avoid
GIMPLE optimizers to optimize the function away earlier.  With lack of unit
testing, we might try to come with testcase where GIMPLE optimizers miss the
transofrmation for other reason.

We might also add sanity checks into c-common.c to warn on such conflicting
combinations of attributes, like pure/const & noreturn.

Honza
> 
> Honza
> 
> > looping pure/consts and rely on GIMPLE land to do enough optimization here.
> > (this is probably something we would want to revisit later, since pure flag
> > is useful for scheduling)
> > 
> > Honza
Richard Biener Jan. 31, 2011, 1:10 p.m. UTC | #11
On Mon, Jan 31, 2011 at 1:50 PM, Jan Hubicka <hubicka@ucw.cz> wrote:
>> Hmm, actually we have RTL_LOOPING_CONST_OR_PURE_CALL_P, so I see no problem.
>> I will try to look into the thread more to figure out what it is all about
>
> OK, so I think that Peter's patch is fine.  The testcase attached to
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47525
> is indeed nonsential.  I think noreturn flag there is needed only to avoid
> GIMPLE optimizers to optimize the function away earlier.  With lack of unit
> testing, we might try to come with testcase where GIMPLE optimizers miss the
> transofrmation for other reason.
>
> We might also add sanity checks into c-common.c to warn on such conflicting
> combinations of attributes, like pure/const & noreturn.

Well, 1) an endless loop isn't a side-effect, 2) nor is not returning, 3) if
they were, pure + noreturn would be non-sensical - in which case we
can parse it as looping-const-or-pure (please).  From just looking at
the testcase (w/o bodies for the fns) it looks bogus to DCE the noreturn
call.

Richard.

> Honza
>>
>> Honza
>>
>> > looping pure/consts and rely on GIMPLE land to do enough optimization here.
>> > (this is probably something we would want to revisit later, since pure flag
>> > is useful for scheduling)
>> >
>> > Honza
>
Jan Hubicka Jan. 31, 2011, 2:01 p.m. UTC | #12
> On Mon, Jan 31, 2011 at 1:50 PM, Jan Hubicka <hubicka@ucw.cz> wrote:
> >> Hmm, actually we have RTL_LOOPING_CONST_OR_PURE_CALL_P, so I see no problem.
> >> I will try to look into the thread more to figure out what it is all about
> >
> > OK, so I think that Peter's patch is fine.  The testcase attached to
> > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47525
> > is indeed nonsential.  I think noreturn flag there is needed only to avoid
> > GIMPLE optimizers to optimize the function away earlier.  With lack of unit
> > testing, we might try to come with testcase where GIMPLE optimizers miss the
> > transofrmation for other reason.
> >
> > We might also add sanity checks into c-common.c to warn on such conflicting
> > combinations of attributes, like pure/const & noreturn.
> 
> Well, 1) an endless loop isn't a side-effect, 2) nor is not returning, 3) if

Well, if you define not returning as side effect than docs become less clear
(Looping pure function can also i.e. terminate the program and do other things.
Only what we ensure is that after returning, the memory is not modified)

Docs says:

  Many functions have no effects except the return value and their
  return value depends only on the parameters and/or global variables.
  
  Such a function can be subject
  to common subexpression elimination and loop optimization just as an
  arithmetic operator would be.  These functions should be declared
  with the attribute @code{pure}.  

It does not explicitely mention DCE, tought it is implicit in CSE to be useful.
Nothing of that makes sense on noreturn functions.

> they were, pure + noreturn would be non-sensical - in which case we
> can parse it as looping-const-or-pure (please).  From just looking at

I don't think silently adding looping flag in some cases (such as combination
with noreturn) is sound design and would just confuse users.
Nor we want to flip the default and declare all pure/const functions to be looping
since that would defeat purpose of the flag.

We can warn + drop the flag for sure, but I would not accept noreturn pures as
valid and try to behave sanely here.

Honza

> the testcase (w/o bodies for the fns) it looks bogus to DCE the noreturn
> call.
> 
> Richard.
> 
> > Honza
> >>
> >> Honza
> >>
> >> > looping pure/consts and rely on GIMPLE land to do enough optimization here.
> >> > (this is probably something we would want to revisit later, since pure flag
> >> > is useful for scheduling)
> >> >
> >> > Honza
> >
Jan Hubicka Jan. 31, 2011, 2:04 p.m. UTC | #13
> > On Mon, Jan 31, 2011 at 1:50 PM, Jan Hubicka <hubicka@ucw.cz> wrote:
> > >> Hmm, actually we have RTL_LOOPING_CONST_OR_PURE_CALL_P, so I see no problem.
> > >> I will try to look into the thread more to figure out what it is all about
> > >
> > > OK, so I think that Peter's patch is fine.  The testcase attached to
> > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47525
> > > is indeed nonsential.  I think noreturn flag there is needed only to avoid
> > > GIMPLE optimizers to optimize the function away earlier.  With lack of unit
> > > testing, we might try to come with testcase where GIMPLE optimizers miss the
> > > transofrmation for other reason.
> > >
> > > We might also add sanity checks into c-common.c to warn on such conflicting
> > > combinations of attributes, like pure/const & noreturn.
> > 
> > Well, 1) an endless loop isn't a side-effect, 2) nor is not returning, 3) if
> 
> Well, if you define not returning as side effect than docs become less clear
> (Looping pure function can also i.e. terminate the program and do other things.
> Only what we ensure is that after returning, the memory is not modified)

I think when the possibility of infinite loops was discussed first time, they was
declared to be "runtime side effect"

Honza
Richard Biener Jan. 31, 2011, 2:43 p.m. UTC | #14
2011/1/31 Jan Hubicka <hubicka@ucw.cz>:
>> > On Mon, Jan 31, 2011 at 1:50 PM, Jan Hubicka <hubicka@ucw.cz> wrote:
>> > >> Hmm, actually we have RTL_LOOPING_CONST_OR_PURE_CALL_P, so I see no problem.
>> > >> I will try to look into the thread more to figure out what it is all about
>> > >
>> > > OK, so I think that Peter's patch is fine.  The testcase attached to
>> > > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47525
>> > > is indeed nonsential.  I think noreturn flag there is needed only to avoid
>> > > GIMPLE optimizers to optimize the function away earlier.  With lack of unit
>> > > testing, we might try to come with testcase where GIMPLE optimizers miss the
>> > > transofrmation for other reason.
>> > >
>> > > We might also add sanity checks into c-common.c to warn on such conflicting
>> > > combinations of attributes, like pure/const & noreturn.
>> >
>> > Well, 1) an endless loop isn't a side-effect, 2) nor is not returning, 3) if
>>
>> Well, if you define not returning as side effect than docs become less clear
>> (Looping pure function can also i.e. terminate the program and do other things.
>> Only what we ensure is that after returning, the memory is not modified)
>
> I think when the possibility of infinite loops was discussed first time, they was
> declared to be "runtime side effect"

Well, I think at least the docs for pure/const should be amended to
mention dead-code elimination (in case the return value is not used,
in which case a void function as in the testcase doesn't make much
sense).  The docs should also mention that the compiler assumes
a pure / const function always returns normally even when
noreturn or throw is specified (which both is weird).

Richard.

> Honza
>
Peter Bergner Jan. 31, 2011, 3:24 p.m. UTC | #15
On Mon, 2011-01-31 at 13:21 +0100, Richard Guenther wrote:
> I don't think the testcase is valid.
> 
> extern int link_failure (int) __attribute__ ((pure));
> extern void no_return (void) __attribute__ ((noreturn,pure));
> int
> main (void)
> {
>   if (link_failure (0) < 1)
>     no_return ();
>   return 0;
> }

I originally hit this bug on testsuite/gcc.dg/pr42461.c which looks like:

  extern int link_failure (int) __attribute__ ((pure));
  int main (void)
  {
    if (link_failure (0) < 1)
      __builtin_unreachable ();
    return 0;
  }

I tried rewriting it without the __builtin_unreachable() call so that
I could compile it on older gcc's (4.3 and 4.4) where the unreachable
builtin isn't defined.  So the no_return() was just my poor man's
__builtin_unreachable() substitute.

Peter
Peter Bergner Jan. 31, 2011, 3:44 p.m. UTC | #16
On Mon, 2011-01-31 at 13:21 +0100, Richard Guenther wrote:
> no_return might be implemented as
> 
> no_return() { while (1);}
> 
> which means we can't DCE either call.

I'll also note that my patch doesn't modify DCE at all, so current
and older GCCs will happily DCE both calls today.  My problem is that
when I add the -maltivec option, we add a register to global_regs[],
so that the function calls we can DCE without -maltivec, we can no
longer DCE.

My point is that const and pure functions shouldn't be messing with
global registers and that is all my patch deals with.

Whether we should even be DCE'ing const or pure functions is a question
for the DCE pass and not related to this patch.... although I agree
with Kenny and one of your later posts that we should allow DCE of
these types of functions and the documentation should be updated to
explicitly mention DCE is allowed.

Peter
Jan Hubicka Jan. 31, 2011, 4:30 p.m. UTC | #17
> > I think when the possibility of infinite loops was discussed first time, they was
> > declared to be "runtime side effect"
> 
> Well, I think at least the docs for pure/const should be amended to
> mention dead-code elimination (in case the return value is not used,

Yes. We should probably replace "loop optimization" by "code motion"
since pure/consts can be subject of PRE.

I don't like much defining the meaning of pureness of function by listing
what optimizations are performed. On the other hand it is probably more
practical approach than "proper" definition. I can't think of any other
optimization we do or want to do that can not be seen as consequence of
CSE/DCE/code motion.

> in which case a void function as in the testcase doesn't make much
> sense).  The docs should also mention that the compiler assumes
> a pure / const function always returns normally even when
> noreturn or throw is specified (which both is weird).

DCE on noreturn functions is very undefined thing. We have no idea where to
place the new fallthrough edge.  I would expect normal DCE to not remove such
statement since it is a control flow and control flow statements are not
removed even when they have no side effects.  I am very surprised RTL DCE
manages to take that statement away without ICEing.

Also note that const&pure functions can throw (same way as normal operations
can).

I am not sure if "return normally" is well defined and understandable by user,
but I guess we could write that function must always either "return normally or
by exception handling".  It would be similar to what we already have in
leaf attribute definition:
  Calls to external functions with this attribute must return to the current
  compilation unit only by return or by exception handling.

I can think of function whose body is infinite loop without side effects
except for throwing exception after finitely many iterations.  Such function is
technically noreturn & pure. Still I would preffer to just warn as such flag
combination makes no sense in sane code.  I would also mention in docs
that const/pure functions should not be noreturn or returns_twice since those
flags imply side effects not allowed by definition of const&pure functions.

Honza
> 
> Richard.
> 
> > Honza
> >
Peter Bergner Feb. 1, 2011, 8:18 p.m. UTC | #18
On Sat, 2011-01-29 at 11:54 +0100, Paolo Bonzini wrote:
> On Sat, Jan 29, 2011 at 00:06, Peter Bergner <bergner@vnet.ibm.com> wrote:
> > Is that patch OK?  If so, do we want this in mainline now or after 4.6
> > has branched?
> 
> Since this is a regression, ok for 4.6 but please bootstrap it on an
> x86 machine too just for the sake of coverage.

Ok, this passed bootstrap and reg testing on x86_64-linux too with no
regressions.  I'll commit this tomorrow unless one of the RMs objects
and wants this to wait for 4.7.

Peter
Peter Bergner Feb. 2, 2011, 8:10 p.m. UTC | #19
On Tue, 2011-02-01 at 14:18 -0600, Peter Bergner wrote:
> On Sat, 2011-01-29 at 11:54 +0100, Paolo Bonzini wrote:
> > On Sat, Jan 29, 2011 at 00:06, Peter Bergner <bergner@vnet.ibm.com> wrote:
> > > Is that patch OK?  If so, do we want this in mainline now or after 4.6
> > > has branched?
> > 
> > Since this is a regression, ok for 4.6 but please bootstrap it on an
> > x86 machine too just for the sake of coverage.
> 
> Ok, this passed bootstrap and reg testing on x86_64-linux too with no
> regressions.  I'll commit this tomorrow unless one of the RMs objects
> and wants this to wait for 4.7.

Committed as revision 169768.  Thanks everyone.

Peter
diff mbox

Patch

Index: df-scan.c
===================================================================
--- df-scan.c	(revision 169365)
+++ df-scan.c	(working copy)
@@ -1,6 +1,6 @@ 
 /* Scanning of rtl for dataflow analysis.
    Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-   2008, 2009, 2010 Free Software Foundation, Inc.
+   2008, 2009, 2010, 2011 Free Software Foundation, Inc.
    Originally contributed by Michael P. Hayes
              (m.hayes@elec.canterbury.ac.nz, mhayes@redhat.com)
    Major rewrite contributed by Danny Berlin (dberlin@dberlin.org)
@@ -3360,16 +3360,19 @@  df_get_call_refs (struct df_collection_r
 		 NULL, bb, insn_info, DF_REF_REG_USE,
 		 DF_REF_CALL_STACK_USAGE | flags);
 
-  /* Calls may also reference any of the global registers,
-     so they are recorded as used.  */
-  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-    if (global_regs[i])
-      {
-	df_ref_record (DF_REF_BASE, collection_rec, regno_reg_rtx[i],
-		       NULL, bb, insn_info, DF_REF_REG_USE, flags);
-	df_ref_record (DF_REF_BASE, collection_rec, regno_reg_rtx[i],
-		       NULL, bb, insn_info, DF_REF_REG_DEF, flags);
-      }
+  /* Calls to const functions cannot access any global registers and calls to
+     pure functions cannot set them.  All other calls may reference any of the
+     global registers, so they are recorded as used.  */
+  if (!RTL_CONST_CALL_P (insn_info->insn))
+    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+      if (global_regs[i])
+	{
+	  df_ref_record (DF_REF_BASE, collection_rec, regno_reg_rtx[i],
+			 NULL, bb, insn_info, DF_REF_REG_USE, flags);
+	  if (!RTL_PURE_CALL_P (insn_info->insn))
+	    df_ref_record (DF_REF_BASE, collection_rec, regno_reg_rtx[i],
+			   NULL, bb, insn_info, DF_REF_REG_DEF, flags);
+	}
 
   is_sibling_call = SIBLING_CALL_P (insn_info->insn);
   EXECUTE_IF_SET_IN_BITMAP (regs_invalidated_by_call_regset, 0, ui, bi)