OSDN Git Service

PR testsuite/46230
[pf3gnuchains/gcc-fork.git] / gcc / ipa.c
index 3742f84..fa39f92 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -428,10 +428,8 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
                        node->clone_of->clones = node->next_sibling_clone;
                      if (node->next_sibling_clone)
                        node->next_sibling_clone->prev_sibling_clone = node->prev_sibling_clone;
-#ifdef ENABLE_CHECKING
                      if (node->clone_of)
                        node->former_clone_of = node->clone_of->decl;
-#endif
                      node->clone_of = NULL;
                      node->next_sibling_clone = NULL;
                      node->prev_sibling_clone = NULL;
@@ -588,6 +586,56 @@ ipa_discover_readonly_nonaddressable_vars (void)
     fprintf (dump_file, "\n");
 }
 
+/* Return true when there is a reference to node and it is not vtable.  */
+static bool
+cgraph_address_taken_from_non_vtable_p (struct cgraph_node *node)
+{
+  int i;
+  struct ipa_ref *ref;
+  for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++)
+    {
+      struct varpool_node *node;
+      if (ref->refered_type == IPA_REF_CGRAPH)
+       return true;
+      node = ipa_ref_varpool_node (ref);
+      if (!DECL_VIRTUAL_P (node->decl))
+       return true;
+    }
+  return false;
+}
+
+/* COMDAT functions must be shared only if they have address taken,
+   otherwise we can produce our own private implementation with
+   -fwhole-program.  
+   Return true when turning COMDAT functoin static can not lead to wrong
+   code when the resulting object links with a library defining same COMDAT.
+
+   Virtual functions do have their addresses taken from the vtables,
+   but in C++ there is no way to compare their addresses for equality.  */
+
+bool
+cgraph_comdat_can_be_unshared_p (struct cgraph_node *node)
+{
+  if ((cgraph_address_taken_from_non_vtable_p (node)
+       && !DECL_VIRTUAL_P (node->decl))
+      || !node->analyzed)
+    return false;
+  if (node->same_comdat_group)
+    {
+      struct cgraph_node *next;
+
+      /* If more than one function is in the same COMDAT group, it must
+         be shared even if just one function in the comdat group has
+         address taken.  */
+      for (next = node->same_comdat_group;
+          next != node; next = next->same_comdat_group)
+       if (cgraph_address_taken_from_non_vtable_p (node)
+           && !DECL_VIRTUAL_P (next->decl))
+         return false;
+    }
+  return true;
+}
+
 /* Return true when function NODE should be considered externally visible.  */
 
 static bool
@@ -605,6 +653,22 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool
   if (aliased)
     return true;
 
+  /* Do not try to localize built-in functions yet.  One of problems is that we
+     end up mangling their asm for WHOPR that makes it impossible to call them
+     using the implicit built-in declarations anymore.  Similarly this enables
+     us to remove them as unreachable before actual calls may appear during
+     expansion or folding.  */
+  if (DECL_BUILT_IN (node->decl))
+    return true;
+
+  /* FIXME: We get wrong symbols with asm aliases in callgraph and LTO.
+     This is because very little of code knows that assembler name needs to
+     mangled.  Avoid touching declarations with user asm name set to mask
+     some of the problems.  */
+  if (DECL_ASSEMBLER_NAME_SET_P (node->decl)
+      && IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (node->decl))[0]=='*')
+    return true;
+
   /* If linker counts on us, we must preserve the function.  */
   if (cgraph_used_from_object_file_p (node))
     return true;
@@ -612,6 +676,17 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool
     return true;
   if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl)))
     return true;
+  if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
+      && lookup_attribute ("dllexport", DECL_ATTRIBUTES (node->decl)))
+    return true;
+  /* When doing LTO or whole program, we can bring COMDAT functoins static.
+     This improves code quality and we know we will duplicate them at most twice
+     (in the case that we are not using plugin and link with object file
+      implementing same COMDAT)  */
+  if ((in_lto_p || whole_program)
+      && DECL_COMDAT (node->decl)
+      && cgraph_comdat_can_be_unshared_p (node))
+    return false;
 
   /* See if we have linker information about symbol not being used or
      if we need to make guess based on the declaration.
@@ -635,27 +710,6 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool
     ;
   else if (!whole_program)
     return true;
-  /* COMDAT functions must be shared only if they have address taken,
-     otherwise we can produce our own private implementation with
-     -fwhole-program.  */
-  else if (DECL_COMDAT (node->decl))
-    {
-      if (node->address_taken || !node->analyzed)
-       return true;
-      if (node->same_comdat_group)
-       {
-         struct cgraph_node *next;
-
-         /* If more than one function is in the same COMDAT group, it must
-            be shared even if just one function in the comdat group has
-            address taken.  */
-         for (next = node->same_comdat_group;
-              next != node;
-              next = next->same_comdat_group)
-           if (next->address_taken || !next->analyzed)
-             return true;
-       }
-    }
 
   if (MAIN_NAME_P (DECL_NAME (node->decl)))
     return true;
@@ -681,11 +735,23 @@ varpool_externally_visible_p (struct varpool_node *vnode, bool aliased)
   if (varpool_used_from_object_file_p (vnode))
     return true;
 
+  /* FIXME: We get wrong symbols with asm aliases in callgraph and LTO.
+     This is because very little of code knows that assembler name needs to
+     mangled.  Avoid touching declarations with user asm name set to mask
+     some of the problems.  */
+  if (DECL_ASSEMBLER_NAME_SET_P (vnode->decl)
+      && IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (vnode->decl))[0]=='*')
+    return true;
+
   if (DECL_PRESERVE_P (vnode->decl))
     return true;
   if (lookup_attribute ("externally_visible",
                        DECL_ATTRIBUTES (vnode->decl)))
     return true;
+  if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
+      && lookup_attribute ("dllexport",
+                          DECL_ATTRIBUTES (vnode->decl)))
+    return true;
 
   /* See if we have linker information about symbol not being used or
      if we need to make guess based on the declaration.
@@ -701,6 +767,16 @@ varpool_externally_visible_p (struct varpool_node *vnode, bool aliased)
   if (!alias && vnode->resolution == LDPR_PREVAILING_DEF_IRONLY)
     return false;
 
+  /* As a special case, the COMDAT virutal tables can be unshared.
+     In LTO mode turn vtables into static variables.  The variable is readonly,
+     so this does not enable more optimization, but referring static var
+     is faster for dynamic linking.  Also this match logic hidding vtables
+     from LTO symbol tables.  */
+  if ((in_lto_p || flag_whole_program)
+      && !vnode->force_output
+      && DECL_COMDAT (vnode->decl) && DECL_VIRTUAL_P (vnode->decl))
+    return false;
+
   /* When doing link time optimizations, hidden symbols become local.  */
   if (in_lto_p
       && (DECL_VISIBILITY (vnode->decl) == VISIBILITY_HIDDEN
@@ -768,16 +844,32 @@ function_and_variable_visibility (bool whole_program)
                IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (p->decl)),
                IDENTIFIER_POINTER (p->target));
                
-      if ((node = cgraph_node_for_asm (p->target)) != NULL)
+      if ((node = cgraph_node_for_asm (p->target)) != NULL
+         && !DECL_EXTERNAL (node->decl))
         {
+         /* Weakrefs alias symbols from other compilation unit.  In the case
+            the destination of weakref became available because of LTO, we must
+            mark it as needed.  */
+         if (in_lto_p
+             && lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl))
+             && !node->needed)
+           cgraph_mark_needed_node (node);
          gcc_assert (node->needed);
          pointer_set_insert (aliased_nodes, node);
          if (dump_file)
            fprintf (dump_file, "  node %s/%i",
                     cgraph_node_name (node), node->uid);
         }
-      else if ((vnode = varpool_node_for_asm (p->target)) != NULL)
+      else if ((vnode = varpool_node_for_asm (p->target)) != NULL
+              && !DECL_EXTERNAL (vnode->decl))
         {
+         /* Weakrefs alias symbols from other compilation unit.  In the case
+            the destination of weakref became available because of LTO, we must
+            mark it as needed.  */
+         if (in_lto_p
+             && lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl))
+             && !vnode->needed)
+           varpool_mark_needed_node (vnode);
          gcc_assert (vnode->needed);
          pointer_set_insert (aliased_vnodes, vnode);
          if (dump_file)
@@ -791,6 +883,8 @@ function_and_variable_visibility (bool whole_program)
   for (node = cgraph_nodes; node; node = node->next)
     {
       int flags = flags_from_decl_or_type (node->decl);
+
+      /* Optimize away PURE and CONST constructors and destructors.  */
       if (optimize
          && (flags & (ECF_CONST | ECF_PURE))
          && !(flags & ECF_LOOPING_CONST_OR_PURE))
@@ -799,6 +893,13 @@ function_and_variable_visibility (bool whole_program)
          DECL_STATIC_DESTRUCTOR (node->decl) = 0;
        }
 
+      /* Frontends and alias code marks nodes as needed before parsing is finished.
+        We may end up marking as node external nodes where this flag is meaningless
+        strip it.  */
+      if (node->needed
+         && (DECL_EXTERNAL (node->decl) || !node->analyzed))
+       node->needed = 0;
+
       /* C++ FE on lack of COMDAT support create local COMDAT functions
         (that ought to be shared but can not due to object format
         limitations).  It is neccesary to keep the flag to make rest of C++ FE
@@ -1418,10 +1519,13 @@ struct ipa_opt_pass_d pass_ipa_profile =
 /* Generate and emit a static constructor or destructor.  WHICH must
    be one of 'I' (for a constructor) or 'D' (for a destructor).  BODY
    is a STATEMENT_LIST containing GENERIC statements.  PRIORITY is the
-   initialization priority for this constructor or destructor.  */
+   initialization priority for this constructor or destructor. 
 
-void
-cgraph_build_static_cdtor (char which, tree body, int priority)
+   FINAL specify whether the externally visible name for collect2 should
+   be produced. */
+
+static void
+cgraph_build_static_cdtor_1 (char which, tree body, int priority, bool final)
 {
   static int counter = 0;
   char which_buf[16];
@@ -1430,7 +1534,12 @@ cgraph_build_static_cdtor (char which, tree body, int priority)
   /* The priority is encoded in the constructor or destructor name.
      collect2 will sort the names and arrange that they are called at
      program startup.  */
-  sprintf (which_buf, "%c_%.5d_%d", which, priority, counter++);
+  if (final)
+    sprintf (which_buf, "%c_%.5d_%d", which, priority, counter++);
+  else
+  /* Proudce sane name but one not recognizable by collect2, just for the
+     case we fail to inline the function.  */
+    sprintf (which_buf, "sub_%c_%.5d_%d", which, priority, counter++);
   name = get_file_function_name (which_buf);
 
   decl = build_decl (input_location, FUNCTION_DECL, name,
@@ -1450,7 +1559,7 @@ cgraph_build_static_cdtor (char which, tree body, int priority)
   DECL_ARTIFICIAL (decl) = 1;
   DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
   DECL_SAVED_TREE (decl) = body;
-  if (!targetm.have_ctors_dtors)
+  if (!targetm.have_ctors_dtors && final)
     {
       TREE_PUBLIC (decl) = 1;
       DECL_PRESERVE_P (decl) = 1;
@@ -1485,6 +1594,16 @@ cgraph_build_static_cdtor (char which, tree body, int priority)
   current_function_decl = NULL;
 }
 
+/* Generate and emit a static constructor or destructor.  WHICH must
+   be one of 'I' (for a constructor) or 'D' (for a destructor).  BODY
+   is a STATEMENT_LIST containing GENERIC statements.  PRIORITY is the
+   initialization priority for this constructor or destructor.  */
+
+void
+cgraph_build_static_cdtor (char which, tree body, int priority)
+{
+  cgraph_build_static_cdtor_1 (which, body, priority, false);
+}
 
 /* A vector of FUNCTION_DECLs declared as static constructors.  */
 static VEC(tree, heap) *static_ctors;
@@ -1570,7 +1689,7 @@ build_cdtor (bool ctor_p, VEC (tree, heap) *cdtors)
       gcc_assert (body != NULL_TREE);
       /* Generate a function to call all the function of like
         priority.  */
-      cgraph_build_static_cdtor (ctor_p ? 'I' : 'D', body, priority);
+      cgraph_build_static_cdtor_1 (ctor_p ? 'I' : 'D', body, priority, true);
     }
 }