https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68820
Jan Hubicka <hubicka at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Assignee|hubicka at gcc dot gnu.org |unassigned at gcc dot gnu.org --- Comment #10 from Jan Hubicka <hubicka at gcc dot gnu.org> --- OK, this reproduces for me. We get: Merging nodes for my_memcpy. Candidates: my_memcpy/4 (my_memcpy) @0x7ffff6cc7450 Type: function definition analyzed Visibility: force_output externally_visible public next sharing asm name: 36 References: Referring: Read from file: memops-asm-lib.o First run: 0 Function flags: Called by: Calls: *my_memcpy/36 (memcpy) @0x7ffff6cc9a10 Type: function Visibility: external public next sharing asm name: 35 previous sharing asm name: 4 References: Referring: Read from file: memops-asm.o First run: 0 Function flags: Called by: main_test/31 (1.00 per call) Calls: *my_memcpy/35 (__builtin_memcpy) @0x7ffff6cc9b80 Type: function Visibility: external public previous sharing asm name: 36 References: Referring: Read from file: memops-asm.o First run: 0 Function flags: Called by: main_test/31 (1.00 per call) Calls: Not merging decls; DECL_BUILT_IN mismatch Not merging decls; DECL_BUILT_IN mismatch which is expected, one memcpy and __builtin_memcpy are builtins while my_memcpy is not. Now at ltrans time we have: memcpy/8 (memcpy) @0x7ffff6ccb450 Type: function definition analyzed Visibility: externally_visible public References: inside_main/0 (read) Referring: Read from file: oo.ltrans0.o First run: 0 Function flags: Called by: Calls: abort/13 i.e. unused memcpy and my_memcpy/4 (my_memcpy) @0x7ffff6cc1e60 Type: function definition analyzed Visibility: force_output externally_visible public References: Referring: *my_memcpy/36 (alias) Read from file: oo.ltrans0.o First run: 0 Function flags: nonfreeing_fn Called by: Calls: *my_memcpy/36 (memcpy) @0x7ffff6cc1cf0 Type: function definition analyzed alias transparent_alias Visibility: externally_visible external public References: my_memcpy/4 (alias) Referring: Read from file: oo.ltrans0.o First run: 0 Function flags: Called by: main_test/31 (1.00 per call) main_test/31 (1.00 per call) Calls: i.e. used my_memcpy Then we get to: (gdb) bt #0 expand_builtin_memcpy_args (dest=0x7ffff6923fe0, src=0x7ffff6923ca0, len=0x7ffff6918b88, target=target@entry=0x7ffff69391e0, exp=exp@entry=0x7ffff692eab0) at ../../gcc/builtins.c:2904 #1 0x00000000005db286 in expand_builtin_memcpy (target=0x7ffff69391e0, exp=0x7ffff692eab0) at ../../gcc/builtins.c:2991 #2 expand_builtin (exp=0x7ffff692eab0, target=0x7ffff69391e0, subtarget=0x0, mode=DImode, ignore=0) at ../../gcc/builtins.c:5963 #3 0x00000000006c7bf4 in expand_expr_real_1 (exp=0x7ffff692eab0, target=<optimized out>, tmode=DImode, modifier=EXPAND_NORMAL, alt_rtl=<optimized out>, inner_reference_p=inner_reference_p@entry=false) at ../../gcc/expr.c:10563 #4 0x00000000006c94a9 in expand_expr_real (exp=exp@entry=0x7ffff692eab0, target=<optimized out>, tmode=<optimized out>, modifier=modifier@entry=EXPAND_NORMAL, alt_rtl=alt_rtl@entry=0x7fffffffe2b0, inner_reference_p=inner_reference_p@entry=false) at ../../gcc/expr.c:7947 #5 0x00000000006d070a in store_expr_with_bounds (exp=exp@entry=0x7ffff692eab0, target=target@entry=0x7ffff69391e0, call_param_p=call_param_p@entry=0, nontemporal=nontemporal@entry=false, reverse=reverse@entry=false, btarget=btarget@entry=0x7ffff6918bd0) at ../../gcc/expr.c:5406 #6 0x00000000006d1460 in expand_assignment (to=0x7ffff6918bd0, from=from@entry=0x7ffff692eab0, nontemporal=nontemporal@entry=false) at ../../gcc/expr.c:5175 #7 0x00000000005f5904 in expand_call_stmt (stmt=0x7ffff6cbcbe0) at ../../gcc/cfgexpand.c:2646 #8 expand_gimple_stmt_1 (stmt=0x7ffff6cbcbe0) at ../../gcc/cfgexpand.c:3536 #9 expand_gimple_stmt (stmt=stmt@entry=0x7ffff6cbcbe0) at ../../gcc/cfgexpand.c:3702 #10 0x00000000005f71fd in expand_gimple_basic_block (bb=<optimized out>, disable_tail_calls=disable_tail_calls@entry=false) at ../../gcc/cfgexpand.c:5708 #11 0x00000000005fc127 in (anonymous namespace)::pass_expand::execute (this=<optimized out>, fun=0x7ffff6cd2930) at ../../gcc/cfgexpand.c:6323 #12 0x0000000000865bbe in execute_one_pass (pass=pass@entry=0x199b720) at ../../gcc/passes.c:2336 #13 0x0000000000866178 in execute_pass_list_1 (pass=0x199b720) at ../../gcc/passes.c:2410 #14 0x00000000008661d5 in execute_pass_list (fn=0x7ffff6cd2930, pass=<optimized out>) at ../../gcc/passes.c:2421 #15 0x0000000000624943 in cgraph_node::expand (this=this@entry=0x7ffff6cc12e0) at ../../gcc/cgraphunit.c:1973 #16 0x0000000000625f36 in expand_all_functions () at ../../gcc/cgraphunit.c:2109 #17 symbol_table::compile (this=0x7ffff6adb0a8) at ../../gcc/cgraphunit.c:2465 #18 0x0000000000626256 in symbol_table::compile (this=<optimized out>) at ../../gcc/cgraphunit.c:2498 #19 0x00000000005b7b01 in lto_main () at ../../gcc/lto/lto.c:3327 #20 0x000000000091413f in compile_file () at ../../gcc/toplev.c:464 #21 0x000000000058e101 in do_compile () at ../../gcc/toplev.c:1988 #22 toplev::main (this=this@entry=0x7fffffffe840, argc=<optimized out>, argc@entry=30, argv=<optimized out>, argv@entry=0x7fffffffe948) at ../../gcc/toplev.c:2095 #23 0x00000000005902c7 in main (argc=30, argv=0x7fffffffe948) at ../../gcc/main.c:39 and the call target is still *my_memcpy and this goes to emit_block_move_via_libcall which dispatches to memcpy because init_block_move_fn decides so. In normal compilation the user name of memcpy is set by: #0 init_block_move_fn (asmspec=asmspec@entry=0x7ffff6bf0114 "my_memcpy") at ../../gcc/expr.c:1366 #1 0x0000000000665a6c in set_builtin_user_assembler_name (decl=decl@entry=0x7ffff6b5cd20, asmspec=asmspec@entry=0x7ffff6bf0114 "my_memcpy") at ../../gcc/builtins.c:9697 #2 0x00000000005ae27b in finish_decl (decl=decl@entry=0x7ffff6b5cd20, init_loc=init_loc@entry=0, init=<optimized out>, init@entry=0x0, origtype=origtype@entry=0x0, asmspec_tree=<optimized out>, asmspec_tree@entry=0x7ffff6bf0100) at ../../gcc/c/c-decl.c:4818 #3 0x00000000005db0be in c_parser_declaration_or_fndef (parser=parser@entry=0x7ffff6c00000, fndef_ok=false, fndef_ok@entry=true, static_assert_ok=static_assert_ok@entry=true, empty_ok=empty_ok@entry=true, nested=nested@entry=false, start_attr_ok=start_attr_ok@entry=true, objc_foreach_object_declaration=<optimized out>, omp_declare_simd_clauses=..., oacc_routine_clauses=<optimized out>) at ../../gcc/c/c-parser.c:1975 #4 0x00000000005f4c6e in c_parser_external_declaration (parser=0x7ffff6c00000) at ../../gcc/c/c-parser.c:1532 #5 0x00000000005f568a in c_parser_translation_unit (parser=<optimized out>) at ../../gcc/c/c-parser.c:1419 #6 c_parse_file () at ../../gcc/c/c-parser.c:17802 #7 0x0000000000639963 in c_common_parse_file () at ../../gcc/c-family/c-opts.c:1064 #8 0x00000000009a419f in compile_file () at ../../gcc/toplev.c:464 #9 0x000000000059a9b1 in do_compile () at ../../gcc/toplev.c:1988 #10 toplev::main (this=this@entry=0x7fffffffe950, argc=<optimized out>, argc@entry=19, argv=<optimized out>, argv@entry=0x7fffffffea58) at ../../gcc/toplev.c:2095 #11 0x000000000059cb47 in main (argc=19, argv=0x7fffffffea58) at ../../gcc/main.c:39 I think the testcase originally "worked" with LTO more or less by accident by losing DECL_BUILTIN_IN flag during the merging. I do not see how this machinery can work in LTO context: different translation units may have different user name overrriders for memcpy and we do not preserve enough context to known which one we want... Perhaps we could just disable LTO for those tests?