OSDN Git Service

2012-01-10 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / cgraphunit.c
index 26c69ae..2c9c8dd 100644 (file)
@@ -1,6 +1,6 @@
 /* Callgraph based interprocedural optimizations.
    Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-   2011 Free Software Foundation, Inc.
+   2011, 2012 Free Software Foundation, Inc.
    Contributed by Jan Hubicka
 
 This file is part of GCC.
@@ -1249,6 +1249,21 @@ handle_alias_pairs (void)
          varpool_create_variable_alias (p->decl, target_vnode->decl);
          VEC_unordered_remove (alias_pair, alias_pairs, i);
        }
+      /* Weakrefs with target not defined in current unit are easy to handle; they
+        behave just as external variables except we need to note the alias flag
+        to later output the weakref pseudo op into asm file.  */
+      else if (lookup_attribute ("weakref", DECL_ATTRIBUTES (p->decl)) != NULL
+              && (TREE_CODE (p->decl) == FUNCTION_DECL
+                  ? (varpool_node_for_asm (p->target) == NULL)
+                  : (cgraph_node_for_asm (p->target) == NULL)))
+       {
+         if (TREE_CODE (p->decl) == FUNCTION_DECL)
+           cgraph_get_create_node (p->decl)->alias = true;
+         else
+           varpool_get_node (p->decl)->alias = true;
+         DECL_EXTERNAL (p->decl) = 1;
+         VEC_unordered_remove (alias_pair, alias_pairs, i);
+       }
       else
        {
          if (dump_file)
@@ -1679,7 +1694,6 @@ assemble_thunk (struct cgraph_node *node)
         VEC_quick_push (tree, vargs, arg);
       call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias), vargs);
       VEC_free (tree, heap, vargs);
-      gimple_call_set_cannot_inline (call, true);
       gimple_call_set_from_thunk (call, true);
       if (restmp)
         gimple_call_set_lhs (call, restmp);
@@ -2064,24 +2078,40 @@ ipa_passes (void)
   bitmap_obstack_release (NULL);
 }
 
+
+/* Return string alias is alias of.  */
+
+static tree
+get_alias_symbol (tree decl)
+{
+  tree alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl));
+  return get_identifier (TREE_STRING_POINTER
+                         (TREE_VALUE (TREE_VALUE (alias))));
+}
+
+
 /* Weakrefs may be associated to external decls and thus not output
    at expansion time.  Emit all neccesary aliases.  */
 
-void
+static void
 output_weakrefs (void)
 {
   struct cgraph_node *node;
   struct varpool_node *vnode;
   for (node = cgraph_nodes; node; node = node->next)
-    if (node->alias && node->thunk.alias && DECL_EXTERNAL (node->decl)
-        && !TREE_ASM_WRITTEN (node->decl))
+    if (node->alias && DECL_EXTERNAL (node->decl)
+        && !TREE_ASM_WRITTEN (node->decl)
+       && lookup_attribute ("weakref", DECL_ATTRIBUTES (node->decl)))
       assemble_alias (node->decl,
-                     DECL_ASSEMBLER_NAME (node->thunk.alias));
+                     node->thunk.alias ? DECL_ASSEMBLER_NAME (node->thunk.alias)
+                     : get_alias_symbol (node->decl));
   for (vnode = varpool_nodes; vnode; vnode = vnode->next)
-    if (vnode->alias && vnode->alias_of && DECL_EXTERNAL (vnode->decl)
-        && !TREE_ASM_WRITTEN (vnode->decl))
+    if (vnode->alias && DECL_EXTERNAL (vnode->decl)
+        && !TREE_ASM_WRITTEN (vnode->decl)
+       && lookup_attribute ("weakref", DECL_ATTRIBUTES (vnode->decl)))
       assemble_alias (vnode->decl,
-                     DECL_ASSEMBLER_NAME (vnode->alias_of));
+                     vnode->alias_of ? DECL_ASSEMBLER_NAME (vnode->alias_of)
+                     : get_alias_symbol (vnode->decl));
 }
 
 
@@ -2157,6 +2187,7 @@ cgraph_optimize (void)
 #endif
   bitmap_obstack_release (NULL);
   cgraph_mark_functions_to_output ();
+  output_weakrefs ();
 
   cgraph_state = CGRAPH_STATE_EXPANSION;
   if (!flag_toplevel_reorder)
@@ -2171,7 +2202,6 @@ cgraph_optimize (void)
       varpool_assemble_pending_decls ();
     }
 
-  output_weakrefs ();
   cgraph_process_new_functions ();
   cgraph_state = CGRAPH_STATE_FINISHED;
 
@@ -2243,7 +2273,7 @@ update_call_expr (struct cgraph_node *new_version)
    was copied to prevent duplications of calls that are dead
    in the clone.  */
 
-static struct cgraph_node *
+struct cgraph_node *
 cgraph_copy_node_for_versioning (struct cgraph_node *old_version,
                                 tree new_decl,
                                 VEC(cgraph_edge_p,heap) *redirect_callers,
@@ -2257,7 +2287,7 @@ cgraph_copy_node_for_versioning (struct cgraph_node *old_version,
 
    new_version = cgraph_create_node (new_decl);
 
-   new_version->analyzed = true;
+   new_version->analyzed = old_version->analyzed;
    new_version->local = old_version->local;
    new_version->local.externally_visible = false;
    new_version->local.local = true;
@@ -2287,6 +2317,8 @@ cgraph_copy_node_for_versioning (struct cgraph_node *old_version,
        cgraph_redirect_edge_callee (e, new_version);
      }
 
+   cgraph_call_node_duplication_hooks (old_version, new_version);
+
    return new_version;
  }
 
@@ -2337,6 +2369,10 @@ cgraph_function_versioning (struct cgraph_node *old_version_node,
   SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl));
   SET_DECL_RTL (new_decl, NULL);
 
+  /* When the old decl was a con-/destructor make sure the clone isn't.  */
+  DECL_STATIC_CONSTRUCTOR(new_decl) = 0;
+  DECL_STATIC_DESTRUCTOR(new_decl) = 0;
+
   /* Create the new version's call-graph node.
      and update the edges of the new node. */
   new_version_node =