Hi,
GCC's alias support follows how C level alias attributes work: function
bodies/variable initializers are associated with particular symbols and other
aliases are separate symbol referring to the one they are aliasing.

In ELF implementation and by my understanding of BFD also everywher else
the aliases are just symbols pointing to the same place as the symbol they
are aliasing.

This has different semanting WRT interposing.  In GCC vision, when you interpose
the alias target, the alias itself is retargetted to new destination. In ELF
implementation this does not happen and it is used common for the internal
aliases within shared libraries.

This patch makes GCC to follow ELF semantic in the visibility code and inlining.
Other IPA passes needs further updating and so does the lto-symtab code where
interposition is implemented in the wrong way.

Bootstrapped/regtested x86_64-linux and ppc64-linux, will commit it shortly.

Honza

        * gcc.dg/tree-ssa/attr-alias.c: New testcase.

        * ipa-inline.c (update_caller_keys): Fix availability test.
        (update_callee_keys): Likewise.
        * symtab.c (symtab_alias_ultimate_target): Make availaiblity logic
        to follow ELF standard.
Index: testsuite/gcc.dg/tree-ssa/attr-alias.c
===================================================================
*** testsuite/gcc.dg/tree-ssa/attr-alias.c      (revision 0)
--- testsuite/gcc.dg/tree-ssa/attr-alias.c      (revision 0)
***************
*** 0 ****
--- 1,29 ----
+ /* { dg-do compile } */
+ /* { dg-require-alias "" } */
+ /* { dg-options "-O2 -fdump-tree-optimized" } */
+ void abort (void);
+ __attribute__ ((weak))
+ int test() 
+ {
+    return 0;
+ }
+ static int test2() __attribute__ ((alias("test")));
+ static int test3() __attribute__ ((weakref)) __attribute__ ((alias("test2")));
+ static int test4() __attribute__ ((weakref)) __attribute__ ((alias("test")));
+ main()
+ {
+   test();
+   test2();
+   test3();
+   test4();
+ }
+ 
+ /* calls to test1 and test2 can be inlined and optmized away. Calls
+    to test and test4 are overwritable.  */
+ 
+ /* { dg-final { scan-tree-dump-times "test (" 2 "optimized" } } */
+ /* { dg-final { scan-tree-dump-times "test4 (" 1 "optimized" } } */
+ /* { dg-final { scan-tree-dump-not "test1 (" "optimized" } } */
+ /* { dg-final { scan-tree-dump-not "test2 (" "optimized" } } */
+ /* { dg-final { cleanup-tree-dump "optimized" } } */
+ 
Index: ipa-inline.c
===================================================================
*** ipa-inline.c        (revision 199591)
--- ipa-inline.c        (working copy)
*************** update_caller_keys (fibheap_t heap, stru
*** 1101,1107 ****
    struct ipa_ref *ref;
  
    if ((!node->symbol.alias && !inline_summary (node)->inlinable)
-       || cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE
        || node->global.inlined_to)
      return;
    if (!bitmap_set_bit (updated_nodes, node->uid))
--- 1101,1106 ----
*************** update_callee_keys (fibheap_t heap, stru
*** 1162,1168 ****
        if (e->inline_failed
            && (callee = cgraph_function_or_thunk_node (e->callee, &avail))
            && inline_summary (callee)->inlinable
!           && cgraph_function_body_availability (callee) >= AVAIL_AVAILABLE
            && !bitmap_bit_p (updated_nodes, callee->uid))
          {
            if (can_inline_edge_p (e, false)
--- 1161,1167 ----
        if (e->inline_failed
            && (callee = cgraph_function_or_thunk_node (e->callee, &avail))
            && inline_summary (callee)->inlinable
!           && avail >= AVAIL_AVAILABLE
            && !bitmap_bit_p (updated_nodes, callee->uid))
          {
            if (can_inline_edge_p (e, false)
Index: symtab.c
===================================================================
*** symtab.c    (revision 199591)
--- symtab.c    (working copy)
*************** symtab_node_availability (symtab_node no
*** 834,852 ****
  symtab_node
  symtab_alias_ultimate_target (symtab_node node, enum availability 
*availability)
  {
    if (availability)
!     *availability = symtab_node_availability (node);
    while (node)
      {
        if (node->symbol.alias && node->symbol.analyzed)
        node = symtab_alias_target (node);
        else
!       return node;
!       if (node && availability)
        {
          enum availability a = symtab_node_availability (node);
          if (a < *availability)
            *availability = a;
        }
      }
    if (availability)
--- 834,897 ----
  symtab_node
  symtab_alias_ultimate_target (symtab_node node, enum availability 
*availability)
  {
+   bool weakref_p = false;
+ 
+   if (!node->symbol.alias)
+     {
+       if (availability)
+         *availability = symtab_node_availability (node);
+       return node;
+     }
+ 
+   /* To determine visibility of the target, we follow ELF semantic of aliases.
+      Here alias is an alternative assembler name of a given definition. Its
+      availablity prevails the availablity of its target (i.e. static alias of
+      weak definition is available.
+ 
+      Weakref is a different animal (and not part of ELF per se). It is just
+      alternative name of a given symbol used within one complation unit
+      and is translated prior hitting the object file.  It inherits the
+      visibility of its target (i.e. weakref of non-overwritable definition
+      is non-overwritable, while weakref of weak definition is weak).
+ 
+      If we ever get into supporting targets with different semantics, a target
+      hook will be needed here.  */
+ 
    if (availability)
!     {
!       weakref_p = DECL_EXTERNAL (node->symbol.decl) && node->symbol.alias;
!       if (!weakref_p)
!         *availability = symtab_node_availability (node);
!       else
!       *availability = AVAIL_LOCAL;
!     }
    while (node)
      {
        if (node->symbol.alias && node->symbol.analyzed)
        node = symtab_alias_target (node);
        else
!       {
!         if (!availability)
!           ;
!         else if (node->symbol.analyzed)
!           {
!             if (weakref_p)
!               {
!                 enum availability a = symtab_node_availability (node);
!                 if (a < *availability)
!                   *availability = a;
!               }
!           }
!         else
!           *availability = AVAIL_NOT_AVAILABLE;
!         return node;
!       }
!       if (node && availability && weakref_p)
        {
          enum availability a = symtab_node_availability (node);
          if (a < *availability)
            *availability = a;
+           weakref_p = DECL_EXTERNAL (node->symbol.decl) && node->symbol.alias;
        }
      }
    if (availability)

Reply via email to