OSDN Git Service

PR c++/55877
[pf3gnuchains/gcc-fork.git] / gcc / ipa.c
index 28e6872..4955408 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -1,5 +1,5 @@
 /* Basic IPA optimizations and utilities.
-   Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010
+   Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -259,7 +259,7 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
     {
       vnode->next_needed = NULL;
       vnode->prev_needed = NULL;
-      if (vnode->analyzed
+      if ((vnode->analyzed || vnode->force_output)
          && !varpool_can_remove_if_no_refs (vnode))
        {
          vnode->needed = false;
@@ -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;
@@ -655,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;
@@ -662,7 +676,9 @@ 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
@@ -719,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.
@@ -816,16 +844,34 @@ 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))
         {
+         if (!node->analyzed)
+           continue;
+         /* 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)
@@ -839,6 +885,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))
@@ -847,6 +895,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
@@ -1466,10 +1521,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];
@@ -1478,7 +1536,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,
@@ -1498,7 +1561,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;
@@ -1533,6 +1596,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;
@@ -1618,7 +1691,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);
     }
 }