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.