diff mbox

Mark explicit decls as implicit when we've seen a prototype

Message ID alpine.LSU.2.11.1412041144520.8254@zhemvz.fhfr.qr
State New
Headers show

Commit Message

Richard Biener Dec. 4, 2014, 10:55 a.m. UTC
Currently even when I prototype

double exp10 (double);

this function is not available to optimizers for code generation if
they just check for builtin_decl_implicit (BUILT_IN_EXP10).
Curiously though the function is identified as BUILT_IN_EXP10 when
used though, thus the middle-end assumes it has expected exp10
semantics.  I see we already cheat with stpcpy and make it available
to optimizers by marking it implicit when we've seen a prototype.

The following patch proposed to do that for all builtins.

At least I can't see how interpreting exp10 as exp10 but then
not being allowed to use it as exp10 is sensible.

Now one could argue that declaring exp10 doesn't mean there is
an implementation available at link time (after all declaring
exp10 doesn't mean I use exp10 anywhere).  But that's true
for implicit decls as well - I might declare 'pow', not use
it and not link against libm.  So if the compiler now emits
a call to pow my link will break:

extern double pow (double, double);
double x;
int main ()
{
  return x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x;
}

links fine with -O0 but fails to link with -Os -ffast-math where
I have to supply -lm.

So the following patch extends the stpcpy assumption to all builtins.

Ok after bootstrap / regtest?

Thanks,
Richard.

2014-12-04  Richard Biener  <rguenther@suse.de>

	c/
	* c-decl.c (merge_decls): For explicit builtin functions mark
	them as implicit when we have seen a compatible prototype.

	cp/
	* decl.c (duplicate_decls): For explicit builtin functions mark
	them as implicit when we have seen a compatible prototype.

Comments

Alexander Monakov Dec. 4, 2014, 11:11 a.m. UTC | #1
On Thu, 4 Dec 2014, Richard Biener wrote:

> 
> Currently even when I prototype
> 
> double exp10 (double);
> 
> this function is not available to optimizers for code generation if
> they just check for builtin_decl_implicit (BUILT_IN_EXP10).
> Curiously though the function is identified as BUILT_IN_EXP10 when
> used though, thus the middle-end assumes it has expected exp10
> semantics.  I see we already cheat with stpcpy and make it available
> to optimizers by marking it implicit when we've seen a prototype.
> 
> The following patch proposed to do that for all builtins.
> 
> At least I can't see how interpreting exp10 as exp10 but then
> not being allowed to use it as exp10 is sensible.
> 
> Now one could argue that declaring exp10 doesn't mean there is
> an implementation available at link time (after all declaring
> exp10 doesn't mean I use exp10 anywhere).  But that's true
> for implicit decls as well - I might declare 'pow', not use
> it and not link against libm.  So if the compiler now emits
> a call to pow my link will break:
> 
> extern double pow (double, double);
> double x;
> int main ()
> {
>   return x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x;
> }
> 
> links fine with -O0 but fails to link with -Os -ffast-math where
> I have to supply -lm.
> 
> So the following patch extends the stpcpy assumption to all builtins.

I think it would be nice if -ffreestanding could be used to disable this kind
of transformations.  Compare with folding a loop to memset in a libc function
implementing memset itself.

Thanks.

Alexander
Jason Merrill Dec. 4, 2014, 2:05 p.m. UTC | #2
OK.

Jason
Joseph Myers Dec. 4, 2014, 3:05 p.m. UTC | #3
On Thu, 4 Dec 2014, Richard Biener wrote:

> Currently even when I prototype
> 
> double exp10 (double);
> 
> this function is not available to optimizers for code generation if
> they just check for builtin_decl_implicit (BUILT_IN_EXP10).
> Curiously though the function is identified as BUILT_IN_EXP10 when
> used though, thus the middle-end assumes it has expected exp10
> semantics.  I see we already cheat with stpcpy and make it available
> to optimizers by marking it implicit when we've seen a prototype.
> 
> The following patch proposed to do that for all builtins.
> 
> At least I can't see how interpreting exp10 as exp10 but then
> not being allowed to use it as exp10 is sensible.
> 
> Now one could argue that declaring exp10 doesn't mean there is
> an implementation available at link time (after all declaring
> exp10 doesn't mean I use exp10 anywhere).  But that's true
> for implicit decls as well - I might declare 'pow', not use
> it and not link against libm.  So if the compiler now emits
> a call to pow my link will break:

Logically I think the following should apply (no doubt there are various 
existing bugs in this area; at least, PR 46926 for sincos calls being 
generated in circumstances when that name is not reserved):

* If a function is assumed to have particular semantics, it can also be 
assumed to be available for code generation, *except* that implicitly 
introducing references to functions that may not be in libc is unsafe 
unless the user's program explicitly used a function from the containing 
library.  (Libraries for things that may not be in libc are as listed at 
<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html>; only 
libm for <math.h>, <complex.h> and <fenv.h> functions is likely to be 
relevant to GCC.  "explicitly used" is as in C11 6.9#5: "used in an 
expression (other than as part of the operand of a sizeof or _Alignof 
operator whose result is an integer constant)" (appropriately extended to 
cover GNU C extensions, such as typeof with non-variably-modified 
arguments).)

I don't think there's any existing infrastructure to avoid introducing 
e.g. calls to pow (in the absence of explicit calls to some libm function) 
in cases such as you suggest (and of course pow is an ISO C90 function so 
its semantics can always be assumed - the question is just whether libm 
will be used).

* If __builtin_foo (a built-in function where there is a corresponding 
function foo, standard or otherwise) is explicitly used, except maybe for 
calls with constant arguments expected to be optimized, the function foo 
may be assumed to be available and to have the expected semantics.  This 
applies regardless of what library foo is expected to be in, and 
regardless of whether foo is defined by any standard selected with -std, 
and regardless of any target-specific configuration information about what 
functions the target libraries provide (e.g. __builtin_sincos calls can be 
expanded to sincos whether or not the target has such a function).  
Furthermore, an explicit use of __builtin_foo for a libm function can be 
taken as meaning that libm will be linked in, except maybe for calls with 
constant arguments expected to be optimized.

(The point of the constant arguments exception is that calls to 
__builtin_nan (""), for example, are OK in static initializers, and maybe 
shouldn't be taken as meaning the nan library function is available or 
libm will be linked in.  The built-in functions for generating NaNs may be 
the only case for which this needs to apply.)

* As documented for -nostdlib, memcmp, memset, memcpy and memmove may 
always be assumed to be available, even with -ffreestanding, regardless of 
what explicit calls are or are not present.

* Built-in functions enabled by the selected -std (which in the default 
mode should mean all of them, but in modes such as -std=c11 is a smaller 
set) may always be assumed to be available in libraries linked in and to 
have the expected semantics, subject to (a) any target-specific 
configuration (targetm.libc_has_function) and (b) whether there are any 
explicit calls to functions in the relevant library (not generating calls 
to pow in the absence of any explicit libm function calls).

* Built-in functions reserved but not enabled by the selected -std (e.g. 
float and long double functions for -std=c90) may be treated the same as 
those enabled by the selected -std: it's never valid for the user to use 
them with any other semantics, and targetm.libc_has_function determines 
whether the function is available to generate calls to it (together with 
the presence of any explicit calls to libm functions).

* Built-in functions not reserved or enabled by the selected -std may be 
assumed to be available and to have the expected semantics (subject to 
some functions from the relevant library being explicitly called, in the 
case of libm functions) if declared *in a system header*.  So if you use 
-std=c11 -D_GNU_SOURCE and then include a header declaring exp10 or 
stpcpy, that implies you are using the _GNU_SOURCE library interface and 
so will not use those names for some other purpose.  Indeed, if you use 
_GNU_SOURCE before including any system header anywhere in your program 
you're arguably using the _GNU_SOURCE library interface and so reserving 
those names.  But if you only ever use system headers with feature test 
macros that don't reserve a given name, then you can use that name for 
some other incompatible purpose (so e.g. a strict ISO C program can use 
the exp10 or stpcpy names for its own purposes).
Richard Biener Dec. 4, 2014, 3:10 p.m. UTC | #4
On Thu, 4 Dec 2014, Joseph Myers wrote:

> On Thu, 4 Dec 2014, Richard Biener wrote:
> 
> > Currently even when I prototype
> > 
> > double exp10 (double);
> > 
> > this function is not available to optimizers for code generation if
> > they just check for builtin_decl_implicit (BUILT_IN_EXP10).
> > Curiously though the function is identified as BUILT_IN_EXP10 when
> > used though, thus the middle-end assumes it has expected exp10
> > semantics.  I see we already cheat with stpcpy and make it available
> > to optimizers by marking it implicit when we've seen a prototype.
> > 
> > The following patch proposed to do that for all builtins.
> > 
> > At least I can't see how interpreting exp10 as exp10 but then
> > not being allowed to use it as exp10 is sensible.
> > 
> > Now one could argue that declaring exp10 doesn't mean there is
> > an implementation available at link time (after all declaring
> > exp10 doesn't mean I use exp10 anywhere).  But that's true
> > for implicit decls as well - I might declare 'pow', not use
> > it and not link against libm.  So if the compiler now emits
> > a call to pow my link will break:
> 
> Logically I think the following should apply (no doubt there are various 
> existing bugs in this area; at least, PR 46926 for sincos calls being 
> generated in circumstances when that name is not reserved):
> 
> * If a function is assumed to have particular semantics, it can also be 
> assumed to be available for code generation, *except* that implicitly 
> introducing references to functions that may not be in libc is unsafe 
> unless the user's program explicitly used a function from the containing 
> library.  (Libraries for things that may not be in libc are as listed at 
> <http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html>; only 
> libm for <math.h>, <complex.h> and <fenv.h> functions is likely to be 
> relevant to GCC.  "explicitly used" is as in C11 6.9#5: "used in an 
> expression (other than as part of the operand of a sizeof or _Alignof 
> operator whose result is an integer constant)" (appropriately extended to 
> cover GNU C extensions, such as typeof with non-variably-modified 
> arguments).)
> 
> I don't think there's any existing infrastructure to avoid introducing 
> e.g. calls to pow (in the absence of explicit calls to some libm function) 
> in cases such as you suggest (and of course pow is an ISO C90 function so 
> its semantics can always be assumed - the question is just whether libm 
> will be used).
> 
> * If __builtin_foo (a built-in function where there is a corresponding 
> function foo, standard or otherwise) is explicitly used, except maybe for 
> calls with constant arguments expected to be optimized, the function foo 
> may be assumed to be available and to have the expected semantics.  This 
> applies regardless of what library foo is expected to be in, and 
> regardless of whether foo is defined by any standard selected with -std, 
> and regardless of any target-specific configuration information about what 
> functions the target libraries provide (e.g. __builtin_sincos calls can be 
> expanded to sincos whether or not the target has such a function).  
> Furthermore, an explicit use of __builtin_foo for a libm function can be 
> taken as meaning that libm will be linked in, except maybe for calls with 
> constant arguments expected to be optimized.
> 
> (The point of the constant arguments exception is that calls to 
> __builtin_nan (""), for example, are OK in static initializers, and maybe 
> shouldn't be taken as meaning the nan library function is available or 
> libm will be linked in.  The built-in functions for generating NaNs may be 
> the only case for which this needs to apply.)
> 
> * As documented for -nostdlib, memcmp, memset, memcpy and memmove may 
> always be assumed to be available, even with -ffreestanding, regardless of 
> what explicit calls are or are not present.
> 
> * Built-in functions enabled by the selected -std (which in the default 
> mode should mean all of them, but in modes such as -std=c11 is a smaller 
> set) may always be assumed to be available in libraries linked in and to 
> have the expected semantics, subject to (a) any target-specific 
> configuration (targetm.libc_has_function) and (b) whether there are any 
> explicit calls to functions in the relevant library (not generating calls 
> to pow in the absence of any explicit libm function calls).
> 
> * Built-in functions reserved but not enabled by the selected -std (e.g. 
> float and long double functions for -std=c90) may be treated the same as 
> those enabled by the selected -std: it's never valid for the user to use 
> them with any other semantics, and targetm.libc_has_function determines 
> whether the function is available to generate calls to it (together with 
> the presence of any explicit calls to libm functions).
> 
> * Built-in functions not reserved or enabled by the selected -std may be 
> assumed to be available and to have the expected semantics (subject to 
> some functions from the relevant library being explicitly called, in the 
> case of libm functions) if declared *in a system header*.  So if you use 
> -std=c11 -D_GNU_SOURCE and then include a header declaring exp10 or 
> stpcpy, that implies you are using the _GNU_SOURCE library interface and 
> so will not use those names for some other purpose.  Indeed, if you use 
> _GNU_SOURCE before including any system header anywhere in your program 
> you're arguably using the _GNU_SOURCE library interface and so reserving 
> those names.  But if you only ever use system headers with feature test 
> macros that don't reserve a given name, then you can use that name for 
> some other incompatible purpose (so e.g. a strict ISO C program can use 
> the exp10 or stpcpy names for its own purposes).

So what does this all mean in practice for optimization passes?
There are only two things they can easily check right now - look
at builtin_decl_implicit () and builtin_decl_explicit ().  It seems
that builtin_decl_explicit () is useless because a) the declaration
may not come from a system header, b) the function may not be
referenced and thus the relevant library may not be linked in.
Strictly speaking builtin_decl_implicit () is also not too useful
as b) applies there as well.

When b) does not apply then the given stpcpy special-casing shows
that even then this is not enough.  So should that special-casing
and any extension of it add

  && in_system_header_at (DECL_SOURCE_LOCATION (newdecl))

?

As a check whether a function is used would need to be delayed
until after the cgraph is built (when we know all references via
calls and address-takens), the whole machinery would need to
move there.  But then we couldn't simply rely on builtin_decl_implicit
but would have to wrap middle-end uses for code generation in
some better abstraction.

Richard.
Richard Biener Dec. 4, 2014, 3:22 p.m. UTC | #5
On Thu, 4 Dec 2014, Joseph Myers wrote:

> On Thu, 4 Dec 2014, Richard Biener wrote:
> 
> > So what does this all mean in practice for optimization passes?
> 
> I don't know what it means in terms of how to fix the various existing 
> problems - it's simply how I think a fixed compiler should behave.
> 
> > When b) does not apply then the given stpcpy special-casing shows
> > that even then this is not enough.  So should that special-casing
> > and any extension of it add
> > 
> >   && in_system_header_at (DECL_SOURCE_LOCATION (newdecl))
> > 
> > ?
> 
> I think that would be logically correct (for allowing stpcpy calls to be 
> generated in optimization if the user included <string.h> with 
> _POSIX_C_SOURCE=200809L defined, for example, but not if they used 
> -std=c11 without feature test macros and declared their own stpcpy).  But 
> the same should apply to any optimization of stpcpy calls written by the 
> user - they can only be assumed to have standard stpcpy semantics if (a) 
> the selected standard includes stpcpy, e.g. -std=gnu11 or (b) stpcpy was 
> declared in a system header, not just by the user.

Yeah - it is that current difference that appears most odd to me.
We assume stpcpy semantics (stick BUILT_IN_STPCPY on the decl) as
soon as we see a (compatible?) decl but we do not allow us to
generate a call to it because semantics may be different(!?).

OTOH this also means the user cannot provide a conforming
implementation on his own and get that used by GCC without editing
system headers or including a header with -isystem or similar
tricks.

Richard.
Joseph Myers Dec. 4, 2014, 3:24 p.m. UTC | #6
On Thu, 4 Dec 2014, Richard Biener wrote:

> So what does this all mean in practice for optimization passes?

I don't know what it means in terms of how to fix the various existing 
problems - it's simply how I think a fixed compiler should behave.

> When b) does not apply then the given stpcpy special-casing shows
> that even then this is not enough.  So should that special-casing
> and any extension of it add
> 
>   && in_system_header_at (DECL_SOURCE_LOCATION (newdecl))
> 
> ?

I think that would be logically correct (for allowing stpcpy calls to be 
generated in optimization if the user included <string.h> with 
_POSIX_C_SOURCE=200809L defined, for example, but not if they used 
-std=c11 without feature test macros and declared their own stpcpy).  But 
the same should apply to any optimization of stpcpy calls written by the 
user - they can only be assumed to have standard stpcpy semantics if (a) 
the selected standard includes stpcpy, e.g. -std=gnu11 or (b) stpcpy was 
declared in a system header, not just by the user.
Joseph Myers Dec. 4, 2014, 3:44 p.m. UTC | #7
On Thu, 4 Dec 2014, Richard Biener wrote:

> OTOH this also means the user cannot provide a conforming
> implementation on his own and get that used by GCC without editing
> system headers or including a header with -isystem or similar
> tricks.

Well - you could have a pragma / attribute for that purpose (declaring 
"this program is providing a version of function X that has the semantics 
GCC expects for function X", so GCC can both generate and optimize calls).  
Such a pragma / attribute could also override targetm.libc_has_function 
(for the case of the user providing their own definition of something 
missing from their system's standard libraries).  A related case would be 
declaring somehow "I will be linking in libm, even though this translation 
unit doesn't appear to be using libm functions, so calls to libm functions 
can be implicitly generated", if GCC were made to avoid introducing uses 
of libm.  (Again, this would be a matter of providing a cleaner interface 
rather than something that currently can't be expressed at all - the 
proposed definition of what it means to use libm explicitly implies that 
"if (0) (void) sqrt (0);" says that libm is being used.)
Richard Biener Dec. 8, 2014, 12:24 p.m. UTC | #8
On Thu, 4 Dec 2014, Joseph Myers wrote:

> On Thu, 4 Dec 2014, Richard Biener wrote:
> 
> > OTOH this also means the user cannot provide a conforming
> > implementation on his own and get that used by GCC without editing
> > system headers or including a header with -isystem or similar
> > tricks.
> 
> Well - you could have a pragma / attribute for that purpose (declaring 
> "this program is providing a version of function X that has the semantics 
> GCC expects for function X", so GCC can both generate and optimize calls).  
> Such a pragma / attribute could also override targetm.libc_has_function 
> (for the case of the user providing their own definition of something 
> missing from their system's standard libraries).  A related case would be 
> declaring somehow "I will be linking in libm, even though this translation 
> unit doesn't appear to be using libm functions, so calls to libm functions 
> can be implicitly generated", if GCC were made to avoid introducing uses 
> of libm.  (Again, this would be a matter of providing a cleaner interface 
> rather than something that currently can't be expressed at all - the 
> proposed definition of what it means to use libm explicitly implies that 
> "if (0) (void) sqrt (0);" says that libm is being used.)

I tried to come up with a patch that adds extra checks but the existing
way of having 'implicit' vs. 'explicit' only available as a flag rather
than making the explicitely declared builtin decl available makes
it harder than necessary.  I also run into the issue that we
remove all cgraph edges during GIMPLE optimizations thus embedding
the "is there already a use of the builtin" in the new abstraction
doesn't fly.

This means the frontend has to provide a "used" flag to the middle-end
as well as a "declared" flag.  For providing a declared flag there
is already the place where we special-case STPCPY, for providing
a "used" flag I don't see any obvious place.

I'm not pushing this further for stage3, but for stage1 I'd like
to eventually address this by splitting up builtin_info_type's
'implicit_p' into a flags array providing implicit_p, declared_p,
used_p and maybe declared_in_system_header_p.  Would you be
willing to fill in the gap computing "used_p" in the C frontend?

My non-working abstraction for middle-end folders looks like

/* Return the decl for the builtin function FNCODE or NULL_TREE if it 
cannot
   be emitted by GCC.  */

tree
builtin_decl (enum built_in_function fncode)
{
  tree decl = builtin_decl_implicit (fncode);
  if (decl)
    return decl;

  decl = builtin_decl_explicit (fncode);
  if (!decl)
    return NULL_TREE;

  /* We cannot use a builtin that has not been declared explicitely.  */
  if (!(builtin_info.flags[fncode] & bif_declared_p))
    return NULL_TREE;

  /* We can use a builtin that has been declared explicitely only if
     the program contains a reference to it already.  */
  cgraph_node *node = cgraph_node::get_for_asmname (DECL_ASSEMBLER_NAME 
(decl));
  if (!node || !node->callers)
    return NULL_TREE;
  return decl;
}

which currently fails because of us having removing cgraph edges
at the points the function is called.  Thus the cgraph caller
check would be replaced by a check for 'used_p'.  We'd still
get __builtin_exp10 emitted instead of the user-declared "exp10"
variant (we don't have access to that decl).

Without the 'used_p' flag work the rest would be equivalent to
setting implicit_p for explicit declarations we see (the originally
proposed patch which follows the stpcpy example).

Thanks,
Richard.
Jakub Jelinek Dec. 8, 2014, 12:44 p.m. UTC | #9
On Mon, Dec 08, 2014 at 01:24:12PM +0100, Richard Biener wrote:
> I'm not pushing this further for stage3, but for stage1 I'd like
> to eventually address this by splitting up builtin_info_type's
> 'implicit_p' into a flags array providing implicit_p, declared_p,
> used_p and maybe declared_in_system_header_p.  Would you be
> willing to fill in the gap computing "used_p" in the C frontend?

The used_p thing might be problematic, I'd expect that several packages
use libm functions somewhere in dead code or when it is folded into
a constant and don't link with -lm, if those dead or optimized away
uses would be counted as uses nevertheless, then if optimizers create new
libm references because of those, I'd be afraid such programs wouldn't link
anymore.

	Jakub
Richard Biener Dec. 8, 2014, 12:54 p.m. UTC | #10
On Mon, 8 Dec 2014, Jakub Jelinek wrote:

> On Mon, Dec 08, 2014 at 01:24:12PM +0100, Richard Biener wrote:
> > I'm not pushing this further for stage3, but for stage1 I'd like
> > to eventually address this by splitting up builtin_info_type's
> > 'implicit_p' into a flags array providing implicit_p, declared_p,
> > used_p and maybe declared_in_system_header_p.  Would you be
> > willing to fill in the gap computing "used_p" in the C frontend?
> 
> The used_p thing might be problematic, I'd expect that several packages
> use libm functions somewhere in dead code or when it is folded into
> a constant and don't link with -lm, if those dead or optimized away
> uses would be counted as uses nevertheless, then if optimizers create new
> libm references because of those, I'd be afraid such programs wouldn't link
> anymore.

Same applies to your STPCPY special-casing, even without introducing
a use.

The alternative is to decide "used" in the middle-end at one point,
for example at the end of all_lowering_passes where hopefully
we have constant folded and removed dead code enough.  We can also
compute an overall "uses libm" flag to fix the testcase I reported
(of course we'd like to re-compute that at LTO time).

Do you think that's better?  It's of course less well-defined what
is a "use" of exp10 then (as opposed to what Joseph specified
with a reference outside of sizeof() and similar contexts).

Richard.
Jakub Jelinek Dec. 8, 2014, 1:04 p.m. UTC | #11
On Mon, Dec 08, 2014 at 01:54:21PM +0100, Richard Biener wrote:
> On Mon, 8 Dec 2014, Jakub Jelinek wrote:
> 
> > On Mon, Dec 08, 2014 at 01:24:12PM +0100, Richard Biener wrote:
> > > I'm not pushing this further for stage3, but for stage1 I'd like
> > > to eventually address this by splitting up builtin_info_type's
> > > 'implicit_p' into a flags array providing implicit_p, declared_p,
> > > used_p and maybe declared_in_system_header_p.  Would you be
> > > willing to fill in the gap computing "used_p" in the C frontend?
> > 
> > The used_p thing might be problematic, I'd expect that several packages
> > use libm functions somewhere in dead code or when it is folded into
> > a constant and don't link with -lm, if those dead or optimized away
> > uses would be counted as uses nevertheless, then if optimizers create new
> > libm references because of those, I'd be afraid such programs wouldn't link
> > anymore.
> 
> Same applies to your STPCPY special-casing, even without introducing
> a use.

Well, the important difference there is that stpcpy is in libc, not libm,
and you get the former by default usually (-nostdlib is very rare).

Yes, supposedly overall uses libc, uses libm flags would be reasonable.

> The alternative is to decide "used" in the middle-end at one point,
> for example at the end of all_lowering_passes where hopefully
> we have constant folded and removed dead code enough.  We can also
> compute an overall "uses libm" flag to fix the testcase I reported
> (of course we'd like to re-compute that at LTO time).
> 
> Do you think that's better?  It's of course less well-defined what
> is a "use" of exp10 then (as opposed to what Joseph specified
> with a reference outside of sizeof() and similar contexts).

	Jakub
Joseph Myers Dec. 8, 2014, 10:43 p.m. UTC | #12
On Mon, 8 Dec 2014, Richard Biener wrote:

> I'm not pushing this further for stage3, but for stage1 I'd like
> to eventually address this by splitting up builtin_info_type's
> 'implicit_p' into a flags array providing implicit_p, declared_p,
> used_p and maybe declared_in_system_header_p.  Would you be
> willing to fill in the gap computing "used_p" in the C frontend?

C_DECL_USED is the right notion of "used" with the front end, in standard 
terms (i.e. the notion that requires a definition of the function to be 
present somewhere), though as noted some people may be relying on calls 
being optimized out.  (Of course such people could get implicitly 
generated libm calls at present anyway; the point of checking "used" is to 
restrict call generation to cases where we know that some library with the 
function will be linked in, and that the function will have the right 
semantics.)
Joseph Myers Dec. 8, 2014, 10:47 p.m. UTC | #13
On Mon, 8 Dec 2014, Richard Biener wrote:

> The alternative is to decide "used" in the middle-end at one point,
> for example at the end of all_lowering_passes where hopefully
> we have constant folded and removed dead code enough.  We can also
> compute an overall "uses libm" flag to fix the testcase I reported
> (of course we'd like to re-compute that at LTO time).

If you do that, of course any optimizations before deciding "used" need to 
be conservative - assume that any function except the one you're 
optimizing a call of is not "used".
Richard Biener Dec. 9, 2014, 8:52 a.m. UTC | #14
On Mon, 8 Dec 2014, Joseph Myers wrote:

> On Mon, 8 Dec 2014, Richard Biener wrote:
> 
> > The alternative is to decide "used" in the middle-end at one point,
> > for example at the end of all_lowering_passes where hopefully
> > we have constant folded and removed dead code enough.  We can also
> > compute an overall "uses libm" flag to fix the testcase I reported
> > (of course we'd like to re-compute that at LTO time).
> 
> If you do that, of course any optimizations before deciding "used" need to 
> be conservative - assume that any function except the one you're 
> optimizing a call of is not "used".

Yes.  I guess I'm willing to consider a new langhook that for C evaluates
C_DECL_USED.  We still have to find a suitable point to query it -
with the earliest point is after parsing finished (thus when we
finalize the TU).  At that point all constant expression folding
should have happened (up to the point required by the language) - but
I suppose C_DECL_USED is still set even if all calls were constant
folded away.

Note that computing a middle-end "C_DECL_USED" can be done from
gimplification (possibly after folding the calls there once).
Same for a global "libm function used" flag (where at some point
we might need a target hook to allow specifying whether a call
is from libm).

Richard.
diff mbox

Patch

Index: gcc/c/c-decl.c
===================================================================
--- gcc/c/c-decl.c	(revision 218343)
+++ gcc/c/c-decl.c	(working copy)
@@ -2563,18 +2563,11 @@  merge_decls (tree newdecl, tree olddecl,
 	      if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL)
 		{
 		  enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl);
-		  switch (fncode)
-		    {
-		      /* If a compatible prototype of these builtin functions
-			 is seen, assume the runtime implements it with the
-			 expected semantics.  */
-		    case BUILT_IN_STPCPY:
-		      if (builtin_decl_explicit_p (fncode))
-			set_builtin_decl_implicit_p (fncode, true);
-		      break;
-		    default:
-		      break;
-		    }
+		  /* If a compatible prototype of a builtin function
+		     is seen, assume the runtime implements it with the
+		     expected semantics.  */
+		  if (builtin_decl_explicit_p (fncode))
+		    set_builtin_decl_implicit_p (fncode, true);
 		}
 	    }
 	  else
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c	(revision 218343)
+++ gcc/cp/decl.c	(working copy)
@@ -2288,18 +2288,11 @@  duplicate_decls (tree newdecl, tree oldd
 	  if (DECL_BUILT_IN_CLASS (newdecl) == BUILT_IN_NORMAL)
 	    {
 	      enum built_in_function fncode = DECL_FUNCTION_CODE (newdecl);
-	      switch (fncode)
-		{
-		  /* If a compatible prototype of these builtin functions
-		     is seen, assume the runtime implements it with the
-		     expected semantics.  */
-		case BUILT_IN_STPCPY:
-		  if (builtin_decl_explicit_p (fncode))
-		    set_builtin_decl_implicit_p (fncode, true);
-		  break;
-		default:
-		  break;
-		}
+	      /* If a compatible prototype of a builtin function
+		 is seen, assume the runtime implements it with the
+		 expected semantics.  */
+	      if (builtin_decl_explicit_p (fncode))
+		set_builtin_decl_implicit_p (fncode, true);
 	    }
 	}
       if (new_defines_function)