http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59626

--- Comment #13 from Richard Biener <rguenth at gcc dot gnu.org> ---
(In reply to Markus Trippelsdorf from comment #12)
> Created attachment 32210 [details]
> Unreduced testcase
> 
> Here's the unreduced testcase:
> 
> markus@x4 coreutils % gcc -std=gnu99 -flto -O2 cp.i copy.i areadlinkat.i
> careadlinkat.i linkat.i
> /usr/include/bits/unistd.h: In function ‘careadlinkat.constprop’:
> /usr/include/bits/unistd.h:173:42: error: inlining failed in call to
> always_inline ‘readlinkat’: recursive inlining
>  __NTH (readlinkat (int __fd, const char *__restrict __path,
>                                           ^
> /usr/include/bits/unistd.h:185:3: error: called from here
>    return __readlinkat_alias (__fd, __path, __buf, __len);
>    ^
> lto-wrapper: /usr/x86_64-pc-linux-gnu/gcc-bin/4.9.0/gcc returned 1 exit
> status
> /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.0/../../../../x86_64-pc-linux-gnu/bin/
> ld: fatal error: lto-wrapper failed
> collect2: error: ld returned 1 exit status

Confirmed with that testcase.  (it doesn't link though - files are missing?)

cgraph merging does

Replacing cgraph node __readlinkat_alias/183 by readlinkat/181 for symbol
readlinkat

I think it's caused by IPA-CP which does

Evaluating opportunities for careadlinkat/187.
 - Creating a specialized node of careadlinkat/187 for all known contexts.
    replacing param fd with const -100
    replacing param buffer with const 0B
    replacing param buffer_size with const 0
    replacing param alloc with const 0B
    replacing param preadlinkat with const readlinkat
                Accounting size:45.00, time:231.11 on predicate:(true)
                Accounting size:3.00, time:2.00 on new predicate:(not inlined)
     the new node is careadlinkat.constprop.5/106.
ipa-prop: Discovered an indirect call to a known target
(careadlinkat.constprop.5/106 -> readlinkat/181), for stmt with uid 2

and then IPA inlining decides

Considering readlinkat with 27 size
   Estimating body: readlinkat/181
   Known to be false: not inlined
   size:24 time:19
 to be inlined into careadlinkat.constprop.5 in unknown:-1
 Estimated growth after inlined into all is +36 insns.
 Estimated badness is -2147483648, frequency 16.39.
                Accounting size:4.00, time:55.21 on predicate:(true)
Processing frequency readlinkat
  Called by careadlinkat.constprop.5 that is normal or hot
  enqueuing call readlinkat/130 -> readlinkat/181, badness -2147483648

(!)

So it is IPA inlining that follows aliases bogously.  The alias target
is _not_ the non-prevailing extern inline function.

OTOH coreutils is walking on shaking grounds (or glibc is) as it takes
the address of an always-inline function.  That address-taking should
probably refer to an extern decl instead (and we are wrong to identify
it with the readlinkat variant with body at LTO time).

Btw, the LTO symbol table looks good to me.  Still somehow the inline
body prevails ... :/

  /* If there's not a prevailing symbol yet it's an external reference.
     Happens a lot during ltrans.  Choose the first symbol with a
     cgraph or a varpool node.  */
  if (!prevailing)
    {
...
      /* For variables prefer the non-builtin if one is available.  */
      else if (TREE_CODE (prevailing->decl) == FUNCTION_DECL)
        {
          for (e = first; e; e = e->next_sharing_asm_name)
            if (TREE_CODE (e->decl) == FUNCTION_DECL
                && !DECL_BUILT_IN (e->decl)
                && lto_symtab_symbol_p (e))
              {
                prevailing = e;
                break;
              }

Now it is readlinkat

$22 = {type = SYMTAB_FUNCTION, resolution = LDPR_RESOLVED_DYN, definition = 1, 
  alias = 0, weakref = 0, cpp_implicit_alias = 0, analyzed = 1, 
  externally_visible = 0, force_output = 0, forced_by_abi = 0, 
  unique_name = 0, used_from_other_partition = 0, in_other_partition = 0, 
  address_taken = 1, order = 777, decl = 0x7ffff6dfc300, 
  next = 0x7ffff6e19668, previous = 0x7ffff6e19a40, 
  next_sharing_asm_name = 0x7ffff6e19b88, previous_sharing_asm_name = 0x0, 
  same_comdat_group = 0x0, ref_list = {references = 0x0, referring = {
      m_vec = 0x1ddfe00}}, alias_target = 0x0, lto_file_data = 0x7ffff7fe1000, 
  aux = 0x0}

that prevails, not the alias

$23 = {type = SYMTAB_FUNCTION, resolution = LDPR_UNKNOWN, definition = 0, 
  alias = 0, weakref = 0, cpp_implicit_alias = 0, analyzed = 0, 
  externally_visible = 0, force_output = 0, forced_by_abi = 0, 
  unique_name = 0, used_from_other_partition = 0, in_other_partition = 0, 
  address_taken = 0, order = 792, decl = 0x7ffff6dfc500, 
  next = 0x7ffff6e19a40, previous = 0x7ffff6e19cd0, 
  next_sharing_asm_name = 0x0, previous_sharing_asm_name = 0x7ffff6e198f8, 
  same_comdat_group = 0x0, ref_list = {references = 0x0, referring = {
      m_vec = 0x0}}, alias_target = 0x0, lto_file_data = 0x7ffff7fe1000, 
  aux = 0x0}

and we replace its cgraph node

*readlinkat/792 (__readlinkat_alias) @0x7ffff6e19b88
  Type: function
  Visibility: external public
  previous sharing asm name: 777
  References: 
  Referring: 
  Read from file: areadlinkat.o
  First run: 0
  Function flags:
  Called by: readlinkat/777 (0.68 per call) 
  Calls: 

by

readlinkat/777 (readlinkat) @0x7ffff6e198f8
  Type: function definition analyzed
  Visibility: resolved_dyn external public
  next sharing asm name: 792
  Address is taken.
  References: 
  Referring: areadlinkat/786 (addr)
  Read from file: areadlinkat.o
  First run: 0
  Function flags:
  Called by: 
  Calls: *readlinkat/792 (0.68 per call) *__readlinkat_chk/791 (0.14 per call)
*__readlinkat_chk/791 (0.18 per call) __builtin_constant_p/789 (0.86 per call)
__builtin_object_size/788 (1.00 per call) 

Note that I think the resolved_dyn should be on the alias, not the inline
body (wouldn't help here I guess, but at least we could choose the one
the linker chose ...).

Index: gcc/lto/lto-symtab.c
===================================================================
--- gcc/lto/lto-symtab.c        (revision 208114)
+++ gcc/lto/lto-symtab.c        (working copy)
@@ -476,7 +476,8 @@ lto_symtab_merge_decls_1 (symtab_node *f
          for (e = first; e; e = e->next_sharing_asm_name)
            if (TREE_CODE (e->decl) == FUNCTION_DECL
                && !DECL_BUILT_IN (e->decl)
-               && lto_symtab_symbol_p (e))
+               && lto_symtab_symbol_p (e)
+               && !e->analyzed)
              {
                prevailing = e;
                break;

fixes it in an awkward way (don't prevail a function with body that wasn't
chosen by the linker).  Not sure if we have to add a fallback then.
(I'd rather chose the symbol with LDPR_RESOLVED_DYN but that's the wrong one
...?).

Reply via email to