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.

Reply via email to