So - back to PR55848 - this testcase shows that we still handle builtins vs. non-builtins in a wrong way. If at compile-time we chose to use a non-builtin variant we have to preserve that (-fno-builtin) - easy to do at WPA stage by adjusting symbol merging. Now, at LTRANS stage somebody clever decided to skip symtab merging - but forgot to disable decl fixup. In this case decl fixup with un-merged builtin and non-builtin symtab entry choses the builtin if it happens to be first in the list of asm aliases.
The following patch fixes both issues, preserving runtime behavior of the weird testcase and avoiding the folding to cbrt as in the original report. LTO bootstrap and testing running on x86_64-unknown-linux-gnu (in stage3 already). Honza, does this look sane? Thanks, Richard. 2013-02-01 Richard Guenther <rguent...@suse.de> PR lto/56168 * lto-symtab.c (lto_symtab_merge_decls_1): Make non-builtin node prevail as last resort. (lto_symtab_merge_decls): Remove guard on LTRANS here. (lto_symtab_prevailing_decl): Builtins are their own prevailing decl. lto/ * lto.c (read_cgraph_and_symbols): Do not call lto_symtab_merge_decls or lto_fixup_decls at LTRANS time. * gcc.dg/lto/pr56168_0.c: New testcase. * gcc.dg/lto/pr56168_1.c: Likewise. Index: gcc/lto-symtab.c =================================================================== *** gcc/lto-symtab.c (revision 195641) --- gcc/lto-symtab.c (working copy) *************** lto_symtab_merge_decls_1 (symtab_node fi *** 439,450 **** && COMPLETE_TYPE_P (TREE_TYPE (e->symbol.decl))) prevailing = e; } ! /* For variables prefer the builtin if one is available. */ else if (TREE_CODE (prevailing->symbol.decl) == FUNCTION_DECL) { for (e = first; e; e = e->symbol.next_sharing_asm_name) if (TREE_CODE (e->symbol.decl) == FUNCTION_DECL ! && DECL_BUILT_IN (e->symbol.decl)) { prevailing = e; break; --- 439,450 ---- && COMPLETE_TYPE_P (TREE_TYPE (e->symbol.decl))) prevailing = e; } ! /* For variables prefer the non-builtin if one is available. */ else if (TREE_CODE (prevailing->symbol.decl) == FUNCTION_DECL) { for (e = first; e; e = e->symbol.next_sharing_asm_name) if (TREE_CODE (e->symbol.decl) == FUNCTION_DECL ! && !DECL_BUILT_IN (e->symbol.decl)) { prevailing = e; break; *************** lto_symtab_merge_decls (void) *** 507,518 **** { symtab_node node; - /* In ltrans mode we read merged cgraph, we do not really need to care - about resolving symbols again, we only need to replace duplicated declarations - read from the callgraph and from function sections. */ - if (flag_ltrans) - return; - /* Populate assembler name hash. */ symtab_initialize_asm_name_hash (); --- 507,512 ---- *************** lto_symtab_prevailing_decl (tree decl) *** 598,603 **** --- 592,602 ---- if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl)) return decl; + /* Likewise builtins are their own prevailing decl. This preserves + non-builtin vs. builtin uses from compile-time. */ + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl)) + return decl; + /* Ensure DECL_ASSEMBLER_NAME will not set assembler name. */ gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl)); Index: gcc/lto/lto.c =================================================================== *** gcc/lto/lto.c (revision 195641) --- gcc/lto/lto.c (working copy) *************** read_cgraph_and_symbols (unsigned nfiles *** 3033,3048 **** fprintf (stderr, "Merging declarations\n"); timevar_push (TV_IPA_LTO_DECL_MERGE); ! /* Merge global decls. */ ! lto_symtab_merge_decls (); ! /* If there were errors during symbol merging bail out, we have no ! good way to recover here. */ ! if (seen_error ()) ! fatal_error ("errors during merging of translation units"); ! /* Fixup all decls. */ ! lto_fixup_decls (all_file_decl_data); htab_delete (tree_with_vars); tree_with_vars = NULL; ggc_collect (); --- 3033,3054 ---- fprintf (stderr, "Merging declarations\n"); timevar_push (TV_IPA_LTO_DECL_MERGE); ! /* Merge global decls. In ltrans mode we read merged cgraph, we do not ! need to care about resolving symbols again, we only need to replace ! duplicated declarations read from the callgraph and from function ! sections. */ ! if (!flag_ltrans) ! { ! lto_symtab_merge_decls (); ! /* If there were errors during symbol merging bail out, we have no ! good way to recover here. */ ! if (seen_error ()) ! fatal_error ("errors during merging of translation units"); ! /* Fixup all decls. */ ! lto_fixup_decls (all_file_decl_data); ! } htab_delete (tree_with_vars); tree_with_vars = NULL; ggc_collect (); Index: gcc/testsuite/gcc.dg/lto/pr56168_0.c =================================================================== *** gcc/testsuite/gcc.dg/lto/pr56168_0.c (revision 0) --- gcc/testsuite/gcc.dg/lto/pr56168_0.c (working copy) *************** *** 0 **** --- 1,15 ---- + /* { dg-lto-do run } */ + /* { dg-lto-options { { -flto -O -ffast-math -fno-builtin } } } */ + + extern double pow(double, double); + extern void abort (void); + volatile double x = 1.0; + int main(int argc, char **argv) + { + double d1 = x; + double d2 = pow(d1, 1.0 / 3.0); + double d3 = d1 * d1; + if (d3 != 1.0 || d2 != 0.0) + abort (); + return 0; + } Index: gcc/testsuite/gcc.dg/lto/pr56168_1.c =================================================================== *** gcc/testsuite/gcc.dg/lto/pr56168_1.c (revision 0) --- gcc/testsuite/gcc.dg/lto/pr56168_1.c (working copy) *************** *** 0 **** --- 1,4 ---- + /* { dg-options "-fno-lto" } */ + + double __attribute__((noinline,noclone)) + pow (double x, double y) { return 0.0; }