lto-symtab.c (lto_symtab_entry_def): Add guessed field.
authorJan Hubicka <jh@suse.cz>
Fri, 24 Sep 2010 21:47:59 +0000 (23:47 +0200)
committerJan Hubicka <hubicka@gcc.gnu.org>
Fri, 24 Sep 2010 21:47:59 +0000 (21:47 +0000)
* lto-symtab.c (lto_symtab_entry_def): Add guessed field.
(lto_symtab_resolve_symbols): Set it.
(lto_symtab_merge_decls_1): Do not compute used_from_object_file;
store resolution field in cgraph/varpool.
* cgraph.c (cgraph_same_body_alias, cgraph_add_thunk): Return node.
(cgraph_get_node_or_alias, cgraph_get_node_or_alias): Constify.
(cgraph_dump_node): Drop used_from_object_file.
(cgraph_clone_node, cgraph_create_virtual_clone): Likewise.
(cgraph_function_body_availability): Use decl_replaceable_p.
(cgraph_make_node_local): Set resolution to LDPR_PREVAILING_DEF_IRONLY.
(cgraph_can_remove_if_no_direct_calls_and_refs): Use
cgraph_used_from_object_file_p.
(cgraph_will_be_removed_from_program_if_no_direct_calls): Use
cgraph_used_from_object_file_p.
(resolution_used_from_other_file_p): New functoin.
(cgraph_used_from_object_file_p): New predicate.
* cgraph.h: Include plugin-api.h
(struct cgraph_local_info): Remove used_from_object_file.
(struct cgraph_node): Add resolution field.
(struct varpool_node): Likewise; remove used_from_object_file;
reove const_value_known.
(cgraph_get_node, cgraph_get_node_or_alias, cgraph_node,
cgraph_same_body_alias, cgraph_add_thunk): Update prototypes.
(resolution_used_from_other_file_p, cgraph_used_from_object_file_p,
varpool_used_from_object_file_p): Declare.
(varpool_get_node, varpool_extra_name_alias): Update prototype.
* tree.h (DECL_REPLACEABLE_P): Remove.
(decl_replaceable_p, decl_binds_to_current_def_p): Declare.
* final.c (rest_of_clean_state): Use decl_binds_to_current_def_p.
* lto-cgraph.c (lto_output_node, lto_output_varpool_node,
input_overwrite_node, input_node, input_varpool_node): Stream
resolution.
* expr.c (expand_expr_real_1): Use const_value_known_p
* ipa.c (ipa_discover_readonly_nonaddressable_var): Do not set
const_value_known.
(cgraph_externally_visible_p): Use cgraph_used_from_object_file_p.
(function_and_variable_visibility): Set resolution for local vars
and functions.
use varpool_used_from_object_file_p.
* varasm.c (resolution_to_local_definition_p, resolution_local_p): New
static functions.
(default_binds_local_p_1): Use resolutoin info.
(decl_binds_to_current_def_p, decl_replaceable_p): New functions.
* varpool.c (varpool_get_node): Constify.
(const_value_known_p): Do not use vnode->const_value_known;
use decl_replaceable_p.
(varpool_finalize_decl): Do not set const_value_known.
(cgraph_variable_initializer_availability): Use decl_replaceable_p
(varpool_extra_name_alias): Return new node.
(varpool_used_from_object_file_p): New function.

* decl.c (finish_function): Use decl_replaceable_p
* method.c (make_alias_for_thunk): Update call of cgraph_same_body_alias.

* lto.c (lto_promote_cross_file_statics): Use const_value_known_p.

From-SVN: r164610

17 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/cgraph.c
gcc/cgraph.h
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/method.c
gcc/expr.c
gcc/final.c
gcc/ipa.c
gcc/lto-cgraph.c
gcc/lto-symtab.c
gcc/lto/ChangeLog
gcc/lto/lto.c
gcc/tree.h
gcc/varasm.c
gcc/varpool.c

index 012757ebaa2655583f9c4643e20165bc4443da60..2bd82c19dfac3312d1895ccc23f9a9b67fb68f4f 100644 (file)
@@ -1,3 +1,56 @@
+2010-09-24  Jan Hubicka  <jh@suse.cz>
+
+       * lto-symtab.c (lto_symtab_entry_def): Add guessed field.
+       (lto_symtab_resolve_symbols): Set it.
+       (lto_symtab_merge_decls_1): Do not compute used_from_object_file;
+       store resolution field in cgraph/varpool.
+       * cgraph.c (cgraph_same_body_alias, cgraph_add_thunk): Return node.
+       (cgraph_get_node_or_alias, cgraph_get_node_or_alias): Constify.
+       (cgraph_dump_node): Drop used_from_object_file.
+       (cgraph_clone_node, cgraph_create_virtual_clone): Likewise.
+       (cgraph_function_body_availability): Use decl_replaceable_p.
+       (cgraph_make_node_local): Set resolution to LDPR_PREVAILING_DEF_IRONLY.
+       (cgraph_can_remove_if_no_direct_calls_and_refs): Use
+       cgraph_used_from_object_file_p.
+       (cgraph_will_be_removed_from_program_if_no_direct_calls): Use
+       cgraph_used_from_object_file_p.
+       (resolution_used_from_other_file_p): New functoin.
+       (cgraph_used_from_object_file_p): New predicate.
+       * cgraph.h: Include plugin-api.h
+       (struct cgraph_local_info): Remove used_from_object_file.
+       (struct cgraph_node): Add resolution field.
+       (struct varpool_node): Likewise; remove used_from_object_file;
+       reove const_value_known.
+       (cgraph_get_node, cgraph_get_node_or_alias, cgraph_node,
+       cgraph_same_body_alias, cgraph_add_thunk): Update prototypes.
+       (resolution_used_from_other_file_p, cgraph_used_from_object_file_p,
+       varpool_used_from_object_file_p): Declare.
+       (varpool_get_node, varpool_extra_name_alias): Update prototype.
+       * tree.h (DECL_REPLACEABLE_P): Remove.
+       (decl_replaceable_p, decl_binds_to_current_def_p): Declare.
+       * final.c (rest_of_clean_state): Use decl_binds_to_current_def_p.
+       * lto-cgraph.c (lto_output_node, lto_output_varpool_node,
+       input_overwrite_node, input_node, input_varpool_node): Stream
+       resolution.
+       * expr.c (expand_expr_real_1): Use const_value_known_p
+       * ipa.c (ipa_discover_readonly_nonaddressable_var): Do not set
+       const_value_known.
+       (cgraph_externally_visible_p): Use cgraph_used_from_object_file_p.
+       (function_and_variable_visibility): Set resolution for local vars
+       and functions.
+       use varpool_used_from_object_file_p.
+       * varasm.c (resolution_to_local_definition_p, resolution_local_p): New
+       static functions.
+       (default_binds_local_p_1): Use resolutoin info.
+       (decl_binds_to_current_def_p, decl_replaceable_p): New functions.
+       * varpool.c (varpool_get_node): Constify.
+       (const_value_known_p): Do not use vnode->const_value_known;
+       use decl_replaceable_p.
+       (varpool_finalize_decl): Do not set const_value_known.
+       (cgraph_variable_initializer_availability): Use decl_replaceable_p
+       (varpool_extra_name_alias): Return new node.
+       (varpool_used_from_object_file_p): New function.
+
 2010-09-24  Richard Henderson  <rth@redhat.com>
 
        * config/ia64/ia64.c (ia64_dwarf_handle_frame_unspec): New.
index 0243accac6005206dfa69da73c0f67a3c89fd91f..383ddba8f5485dd6ca8fa7f0e4aeb0d422e904f0 100644 (file)
@@ -915,7 +915,7 @@ IPA_UTILS_H = ipa-utils.h $(TREE_H) $(CGRAPH_H)
 IPA_REFERENCE_H = ipa-reference.h $(BITMAP_H) $(TREE_H)
 IPA_TYPE_ESCAPE_H = ipa-type-escape.h $(TREE_H)
 CGRAPH_H = cgraph.h $(VEC_H) $(TREE_H) $(BASIC_BLOCK_H) $(FUNCTION_H) \
-       cif-code.def ipa-ref.h ipa-ref-inline.h
+       cif-code.def ipa-ref.h ipa-ref-inline.h $(LINKER_PLUGIN_API_H)
 DF_H = df.h $(BITMAP_H) $(REGSET_H) sbitmap.h $(BASIC_BLOCK_H) \
        alloc-pool.h $(TIMEVAR_H)
 RESOURCE_H = resource.h hard-reg-set.h $(DF_H)
index 470fb5a78fb4afa66cfb628290fc04243f39d062..7293b6dee03ae6f882859ca9c19a6bf1c7dc120a 100644 (file)
@@ -555,24 +555,29 @@ cgraph_same_body_alias_1 (tree alias, tree decl)
   return alias_node;
 }
 
-/* Attempt to mark ALIAS as an alias to DECL.  Return TRUE if successful.
+/* Attempt to mark ALIAS as an alias to DECL.  Return alias node if successful
+   and NULL otherwise. 
    Same body aliases are output whenever the body of DECL is output,
    and cgraph_node (ALIAS) transparently returns cgraph_node (DECL).   */
 
-bool
+struct cgraph_node *
 cgraph_same_body_alias (tree alias, tree decl)
 {
 #ifndef ASM_OUTPUT_DEF
   /* If aliases aren't supported by the assembler, fail.  */
-  return false;
+  return NULL;
 #endif
 
   /*gcc_assert (!assembler_name_hash);*/
 
-  return cgraph_same_body_alias_1 (alias, decl) != NULL;
+  return cgraph_same_body_alias_1 (alias, decl);
 }
 
-void
+/* Add thunk alias into callgraph.  The alias declaration is ALIAS and it
+   alises DECL with an adjustments made into the first parameter.
+   See comments in thunk_adjust for detail on the parameters.  */
+
+struct cgraph_node *
 cgraph_add_thunk (tree alias, tree decl, bool this_adjusting,
                  HOST_WIDE_INT fixed_offset, HOST_WIDE_INT virtual_value,
                  tree virtual_offset,
@@ -599,13 +604,14 @@ cgraph_add_thunk (tree alias, tree decl, bool this_adjusting,
   node->thunk.virtual_offset_p = virtual_offset != NULL;
   node->thunk.alias = real_alias;
   node->thunk.thunk_p = true;
+  return node;
 }
 
 /* Returns the cgraph node assigned to DECL or NULL if no cgraph node
    is assigned.  */
 
 struct cgraph_node *
-cgraph_get_node_or_alias (tree decl)
+cgraph_get_node_or_alias (const_tree decl)
 {
   struct cgraph_node key, *node = NULL, **slot;
 
@@ -614,7 +620,7 @@ cgraph_get_node_or_alias (tree decl)
   if (!cgraph_hash)
     return NULL;
 
-  key.decl = decl;
+  key.decl = CONST_CAST2 (tree, const_tree, decl);
 
   slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key,
                                                 NO_INSERT);
@@ -628,7 +634,7 @@ cgraph_get_node_or_alias (tree decl)
    is assigned.  */
 
 struct cgraph_node *
-cgraph_get_node (tree decl)
+cgraph_get_node (const_tree decl)
 {
   struct cgraph_node key, *node = NULL, **slot;
 
@@ -637,7 +643,7 @@ cgraph_get_node (tree decl)
   if (!cgraph_hash)
     return NULL;
 
-  key.decl = decl;
+  key.decl = CONST_CAST2 (tree, const_tree, decl);
 
   slot = (struct cgraph_node **) htab_find_slot (cgraph_hash, &key,
                                                 NO_INSERT);
@@ -1849,8 +1855,6 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
     fprintf (f, " local");
   if (node->local.externally_visible)
     fprintf (f, " externally_visible");
-  if (node->local.used_from_object_file)
-    fprintf (f, " used_from_object_file");
   if (node->local.finalized)
     fprintf (f, " finalized");
   if (node->local.disregard_inline_limits)
@@ -2124,7 +2128,6 @@ cgraph_clone_node (struct cgraph_node *n, tree decl, gcov_type count, int freq,
   new_node->analyzed = n->analyzed;
   new_node->local = n->local;
   new_node->local.externally_visible = false;
-  new_node->local.used_from_object_file = false;
   new_node->local.local = true;
   new_node->local.vtable_method = false;
   new_node->global = n->global;
@@ -2318,7 +2321,6 @@ cgraph_create_virtual_clone (struct cgraph_node *old_node,
   else
     new_node->clone.combined_args_to_skip = args_to_skip;
   new_node->local.externally_visible = 0;
-  new_node->local.used_from_object_file = 0;
   new_node->local.local = 1;
   new_node->lowered = true;
   new_node->reachable = true;
@@ -2369,7 +2371,7 @@ cgraph_function_body_availability (struct cgraph_node *node)
      AVAIL_AVAILABLE here?  That would be good reason to preserve this
      bit.  */
 
-  else if (DECL_REPLACEABLE_P (node->decl) && !DECL_EXTERNAL (node->decl))
+  else if (decl_replaceable_p (node->decl) && !DECL_EXTERNAL (node->decl))
     avail = AVAIL_OVERWRITABLE;
   else avail = AVAIL_AVAILABLE;
 
@@ -2556,6 +2558,7 @@ cgraph_make_node_local (struct cgraph_node *node)
 
       node->local.externally_visible = false;
       node->local.local = true;
+      node->resolution = LDPR_PREVAILING_DEF_IRONLY;
       gcc_assert (cgraph_function_body_availability (node) == AVAIL_LOCAL);
     }
 }
@@ -2720,7 +2723,8 @@ cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node)
     return false;
   /* Only COMDAT functions can be removed if externally visible.  */
   if (node->local.externally_visible
-      && (!DECL_COMDAT (node->decl) || node->local.used_from_object_file))
+      && (!DECL_COMDAT (node->decl)
+         || cgraph_used_from_object_file_p (node)))
     return false;
   /* Constructors and destructors are executed by the runtime, however
      we can get rid of all pure constructors and destructors.  */
@@ -2753,7 +2757,7 @@ cgraph_can_remove_if_no_direct_calls_and_refs_p (struct cgraph_node *node)
 bool
 cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node)
 {
-  if (node->local.used_from_object_file)
+  if (cgraph_used_from_object_file_p (node))
     return false;
   if (!in_lto_p && !flag_whole_program)
     return cgraph_only_called_directly_p (node);
@@ -2761,4 +2765,35 @@ cgraph_will_be_removed_from_program_if_no_direct_calls (struct cgraph_node *node
     return cgraph_can_remove_if_no_direct_calls_p (node);
 }
 
+/* Return true when RESOLUTION indicate that linker will use
+   the symbol from non-LTo object files.  */
+
+bool
+resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution resolution)
+{
+  return (resolution == LDPR_PREVAILING_DEF
+          || resolution == LDPR_PREEMPTED_REG
+          || resolution == LDPR_RESOLVED_EXEC
+          || resolution == LDPR_RESOLVED_DYN);
+}
+
+/* Return true when NODE is known to be used from other (non-LTO) object file.
+   Known only when doing LTO via linker plugin.  */
+
+bool
+cgraph_used_from_object_file_p (struct cgraph_node *node)
+{
+  struct cgraph_node *alias;
+
+  if (!TREE_PUBLIC (node->decl))
+    return false;
+  if (resolution_used_from_other_file_p (node->resolution))
+    return true;
+  for (alias = node->same_body; alias; alias = alias->next)
+    if (TREE_PUBLIC (alias->decl)
+       && resolution_used_from_other_file_p (alias->resolution))
+      return true;
+  return false;
+}
+
 #include "gt-cgraph.h"
index ec90894317ea7dbeb1fa3e1349b4c67a66c46ac2..330c88396361bca49ba52dc3054f8518ac92f65a 100644 (file)
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_CGRAPH_H
 #define GCC_CGRAPH_H
 
+#include "plugin-api.h"
 #include "vec.h"
 #include "tree.h"
 #include "basic-block.h"
@@ -101,9 +102,6 @@ struct GTY(()) cgraph_local_info {
 
   /* Set when function is visible by other units.  */
   unsigned externally_visible : 1;
-
-  /* Set when resolver determines that function is visible by other units.  */
-  unsigned used_from_object_file : 1;
   
   /* Set once it has been finalized so we consider it to be output.  */
   unsigned finalized : 1;
@@ -259,6 +257,7 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.previous"))) cgraph_node {
   /* unique id for profiling. pid is not suitable because of different
      number of cfg nodes with -fprofile-generate and -fprofile-use */
   int pid;
+  enum ld_plugin_symbol_resolution resolution;
 
   /* Set when function must be output for some reason.  The primary
      use of this flag is to mark functions needed to be output for
@@ -476,6 +475,7 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.prev"))) varpool_node {
   PTR GTY ((skip)) aux;
   /* Ordering of all cgraph nodes.  */
   int order;
+  enum ld_plugin_symbol_resolution resolution;
 
   /* Set when function must be output - it is externally visible
      or its address is taken.  */
@@ -492,8 +492,6 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.prev"))) varpool_node {
   unsigned output : 1;
   /* Set when function is visible by other units.  */
   unsigned externally_visible : 1;
-  /* Set when resolver determines that variable is visible by other units.  */
-  unsigned used_from_object_file : 1;
   /* Set for aliases once they got through assemble_alias.  Also set for
      extra name aliases in varpool_extra_name_alias.  */
   unsigned alias : 1;
@@ -503,8 +501,6 @@ struct GTY((chain_next ("%h.next"), chain_prev ("%h.prev"))) varpool_node {
      During WPA output it is used to mark nodes that are present in
      multiple partitions.  */
   unsigned in_other_partition : 1;
-  /* True when variable is constant and its value is known.  */
-  unsigned int const_value_known : 1;
 };
 
 /* Every top level asm statement is put into a cgraph_asm_node.  */
@@ -561,11 +557,12 @@ struct cgraph_edge *cgraph_create_edge (struct cgraph_node *,
                                        gimple, gcov_type, int, int);
 struct cgraph_edge *cgraph_create_indirect_edge (struct cgraph_node *, gimple, int,
                                                 gcov_type, int, int);
-struct cgraph_node * cgraph_get_node (tree);
-struct cgraph_node * cgraph_get_node_or_alias (tree);
-struct cgraph_node *cgraph_node (tree);
-bool cgraph_same_body_alias (tree, tree);
-void cgraph_add_thunk (tree, tree, bool, HOST_WIDE_INT, HOST_WIDE_INT, tree, tree);
+struct cgraph_node * cgraph_get_node (const_tree);
+struct cgraph_node * cgraph_get_node_or_alias (const_tree);
+struct cgraph_node * cgraph_node (tree);
+struct cgraph_node * cgraph_same_body_alias (tree, tree);
+struct cgraph_node * cgraph_add_thunk (tree, tree, bool, HOST_WIDE_INT,
+                                      HOST_WIDE_INT, tree, tree);
 void cgraph_remove_same_body_alias (struct cgraph_node *);
 struct cgraph_node *cgraph_node_for_asm (tree);
 struct cgraph_edge *cgraph_edge (struct cgraph_node *, gimple);
@@ -614,6 +611,9 @@ bool cgraph_will_be_removed_from_program_if_no_direct_calls
   (struct cgraph_node *node);
 bool cgraph_can_remove_if_no_direct_calls_and_refs_p
   (struct cgraph_node *node);
+bool resolution_used_from_other_file_p (enum ld_plugin_symbol_resolution resolution);
+bool cgraph_used_from_object_file_p (struct cgraph_node *node);
+bool varpool_used_from_object_file_p (struct varpool_node *node);
 
 /* In cgraphunit.c  */
 extern FILE *cgraph_dump_file;
@@ -718,14 +718,14 @@ void cgraph_make_node_local (struct cgraph_node *);
 bool cgraph_node_can_be_local_p (struct cgraph_node *);
 
 
-struct varpool_node * varpool_get_node (tree decl);
+struct varpool_node * varpool_get_node (const_tree decl);
 void varpool_remove_node (struct varpool_node *node);
 bool varpool_assemble_pending_decls (void);
 bool varpool_assemble_decl (struct varpool_node *node);
 bool varpool_analyze_pending_decls (void);
 void varpool_remove_unreferenced_decls (void);
 void varpool_empty_needed_queue (void);
-bool varpool_extra_name_alias (tree, tree);
+struct varpool_node * varpool_extra_name_alias (tree, tree);
 const char * varpool_node_name (struct varpool_node *node);
 void varpool_reset_queue (void);
 bool const_value_known_p (tree);
index 0e2d2fb2326f0b62f5b4f3b09fe62f2a36dae158..4b6eb74fe8db227bbb97d25e27288ff5f0f2fa2a 100644 (file)
@@ -1,3 +1,8 @@
+2010-09-24  Jan Hubicka  <jh@suse.cz>
+
+       * decl.c (finish_function): Use decl_replaceable_p
+       * method.c (make_alias_for_thunk): Update call of cgraph_same_body_alias.
+
 2010-09-24  Jason Merrill  <jason@redhat.com>
 
        * decl.c (compute_array_index_type): Remember type dependence of
index 6a444822c167503d026565b8c70a74d8de5ea7b6..07eddb551df2c51208b92e8ff43d24a801738b4b 100644 (file)
@@ -12674,7 +12674,7 @@ finish_function (int flags)
   if (!processing_template_decl
       && !cp_function_chain->can_throw
       && !flag_non_call_exceptions
-      && !DECL_REPLACEABLE_P (fndecl))
+      && !decl_replaceable_p (fndecl))
     TREE_NOTHROW (fndecl) = 1;
 
   /* This must come after expand_function_end because cleanups might
index 0ec38264062d480e2a157f9c1e6e0398ba3d7b2e..1083e16dc55277703e8b84550027b97a5c1a88b0 100644 (file)
@@ -259,9 +259,9 @@ make_alias_for_thunk (tree function)
 
   if (!flag_syntax_only)
     {
-      bool ok = cgraph_same_body_alias (alias, function);
+      struct cgraph_node *aliasn = cgraph_same_body_alias (alias, function);
       DECL_ASSEMBLER_NAME (function);
-      gcc_assert (ok);
+      gcc_assert (aliasn != NULL);
     }
 
   return alias;
index 7bc1575decaf4d04b2fcd61e188ec4a742350c92..d63ee55e8aa9c14538c67e59374a6a30bc94e91b 100644 (file)
@@ -8830,7 +8830,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
                 && TREE_READONLY (array) && ! TREE_SIDE_EFFECTS (array)
                 && TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
                 && TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK
-                && targetm.binds_local_p (array))
+                && const_value_known_p (array))
          {
            if (TREE_CODE (index) == INTEGER_CST)
              {
index 79cd85e735cfcf6d4e1074dfbda539f759966f8f..4fe1031458cc8f9230a0e07a8547ec65f5180709 100644 (file)
@@ -4441,7 +4441,10 @@ rest_of_clean_state (void)
 
   delete_tree_ssa ();
 
-  if (targetm.binds_local_p (current_function_decl))
+  /* We can reduce stack alignment on call site only when we are sure that
+     the function body just produced will be actually used in the final
+     executable.  */
+  if (decl_binds_to_current_def_p (current_function_decl))
     {
       unsigned int pref = crtl->preferred_stack_boundary;
       if (crtl->stack_alignment_needed > crtl->preferred_stack_boundary)
index 5ff7c149e1581cf1b63b5b5348608038587afb12..9670a9c7941576f1731cec801e33a64eb04f9121 100644 (file)
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -570,7 +570,6 @@ ipa_discover_readonly_nonaddressable_vars (void)
            if (dump_file)
              fprintf (dump_file, " %s (read-only)", varpool_node_name (vnode));
            TREE_READONLY (vnode->decl) = 1;
-           vnode->const_value_known |= const_value_known_p (vnode->decl);
          }
       }
   if (dump_file)
@@ -622,7 +621,7 @@ cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program, bool
              return true;
        }
     }
-  if (node->local.used_from_object_file)
+  if (cgraph_used_from_object_file_p (node))
     return true;
   if (DECL_PRESERVE_P (node->decl))
     return true;
@@ -739,6 +738,7 @@ function_and_variable_visibility (bool whole_program)
           struct cgraph_node *alias;
          gcc_assert (whole_program || in_lto_p || !TREE_PUBLIC (node->decl));
          cgraph_make_decl_local (node->decl);
+         node->resolution = LDPR_PREVAILING_DEF_IRONLY;
          for (alias = node->same_body; alias; alias = alias->next)
            cgraph_make_decl_local (alias->decl);
          if (node->same_comdat_group)
@@ -777,9 +777,6 @@ function_and_variable_visibility (bool whole_program)
              || ! (ADDR_SPACE_GENERIC_P
                    (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl))))))
        DECL_COMMON (vnode->decl) = 0;
-     /* Even extern variables might have initializers known.
-       See, for example testsuite/g++.dg/opt/static3.C  */
-     vnode->const_value_known |= const_value_known_p (vnode->decl);
     }
   for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
     {
@@ -802,7 +799,7 @@ function_and_variable_visibility (bool whole_program)
                      In this case we do not sed used_from_object_file.  */
                   || !vnode->finalized))
              || DECL_PRESERVE_P (vnode->decl)
-              || vnode->used_from_object_file
+              || varpool_used_from_object_file_p (vnode)
              || pointer_set_contains (aliased_vnodes, vnode)
              || lookup_attribute ("externally_visible",
                                   DECL_ATTRIBUTES (vnode->decl))))
@@ -813,8 +810,8 @@ function_and_variable_visibility (bool whole_program)
        {
          gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->decl));
          cgraph_make_decl_local (vnode->decl);
+         vnode->resolution = LDPR_PREVAILING_DEF_IRONLY;
        }
-     vnode->const_value_known |= const_value_known_p (vnode->decl);
      gcc_assert (TREE_STATIC (vnode->decl));
     }
   pointer_set_destroy (aliased_nodes);
index f009fccfe8c5f44dffb45a250911def805b888b4..b82fa735deda8e8f98e184f272fb579af2b3109b 100644 (file)
@@ -519,6 +519,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
   bp_pack_value (&bp, node->finalized_by_frontend, 1);
   bp_pack_value (&bp, node->frequency, 2);
   lto_output_bitpack (&bp);
+  lto_output_uleb128_stream (ob->main_stream, node->resolution);
 
   if (node->same_body)
     {
@@ -550,6 +551,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
              lto_output_fn_decl_index (ob->decl_state, ob->main_stream,
                                        alias->thunk.alias);
            }
+         lto_output_uleb128_stream (ob->main_stream, alias->resolution);
          alias = alias->previous;
        }
       while (alias);
@@ -578,7 +580,6 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node
   bp_pack_value (&bp, node->force_output, 1);
   bp_pack_value (&bp, node->finalized, 1);
   bp_pack_value (&bp, node->alias, 1);
-  bp_pack_value (&bp, node->const_value_known, 1);
   gcc_assert (!node->alias || !node->extra_name);
   gcc_assert (node->finalized || !node->analyzed);
   gcc_assert (node->needed);
@@ -611,12 +612,16 @@ lto_output_varpool_node (struct lto_simple_output_block *ob, struct varpool_node
   else
     ref = LCC_NOT_FOUND;
   lto_output_sleb128_stream (ob->main_stream, ref);
+  lto_output_uleb128_stream (ob->main_stream, node->resolution);
 
   if (count)
     {
       lto_output_uleb128_stream (ob->main_stream, count);
       for (alias = node->extra_name; alias; alias = alias->next)
-       lto_output_var_decl_index (ob->decl_state, ob->main_stream, alias->decl);
+       {
+         lto_output_var_decl_index (ob->decl_state, ob->main_stream, alias->decl);
+         lto_output_uleb128_stream (ob->main_stream, alias->resolution);
+       }
     }
 }
 
@@ -926,7 +931,8 @@ input_overwrite_node (struct lto_file_decl_data *file_data,
                      unsigned int self_time,
                      unsigned int time_inlining_benefit,
                      unsigned int self_size,
-                     unsigned int size_inlining_benefit)
+                     unsigned int size_inlining_benefit,
+                     enum ld_plugin_symbol_resolution resolution)
 {
   node->aux = (void *) tag;
   node->local.inline_summary.estimated_self_stack_size = stack_size;
@@ -972,6 +978,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data,
   node->alias = bp_unpack_value (bp, 1);
   node->finalized_by_frontend = bp_unpack_value (bp, 1);
   node->frequency = (enum node_frequency)bp_unpack_value (bp, 2);
+  node->resolution = resolution;
 }
 
 /* Output the part of the cgraph in SET.  */
@@ -1019,6 +1026,7 @@ input_node (struct lto_file_decl_data *file_data,
   int size_inlining_benefit = 0;
   unsigned long same_body_count = 0;
   int clone_ref;
+  enum ld_plugin_symbol_resolution resolution;
 
   clone_ref = lto_input_sleb128 (ib);
 
@@ -1057,9 +1065,10 @@ input_node (struct lto_file_decl_data *file_data,
                    "node %d", node->uid);
 
   bp = lto_input_bitpack (ib);
+  resolution = (enum ld_plugin_symbol_resolution)lto_input_uleb128 (ib);
   input_overwrite_node (file_data, node, tag, &bp, stack_size, self_time,
                        time_inlining_benefit, self_size,
-                       size_inlining_benefit);
+                       size_inlining_benefit, resolution);
 
   /* Store a reference for now, and fix up later to be a pointer.  */
   node->global.inlined_to = (cgraph_node_ptr) (intptr_t) ref;
@@ -1072,6 +1081,7 @@ input_node (struct lto_file_decl_data *file_data,
     {
       tree alias_decl;
       int type;
+      struct cgraph_node *alias;
       decl_index = lto_input_uleb128 (ib);
       alias_decl = lto_file_decl_data_get_fn_decl (file_data, decl_index);
       type = lto_input_uleb128 (ib);
@@ -1080,7 +1090,7 @@ input_node (struct lto_file_decl_data *file_data,
          tree real_alias;
          decl_index = lto_input_uleb128 (ib);
          real_alias = lto_file_decl_data_get_fn_decl (file_data, decl_index);
-         cgraph_same_body_alias (alias_decl, real_alias);
+         alias = cgraph_same_body_alias (alias_decl, real_alias);
        }
       else
         {
@@ -1089,11 +1099,12 @@ input_node (struct lto_file_decl_data *file_data,
          tree real_alias;
          decl_index = lto_input_uleb128 (ib);
          real_alias = lto_file_decl_data_get_fn_decl (file_data, decl_index);
-         cgraph_add_thunk (alias_decl, fn_decl, type & 2, fixed_offset,
-                           virtual_value,
-                           (type & 4) ? size_int (virtual_value) : NULL_TREE,
-                           real_alias);
+         alias = cgraph_add_thunk (alias_decl, fn_decl, type & 2, fixed_offset,
+                                   virtual_value,
+                                   (type & 4) ? size_int (virtual_value) : NULL_TREE,
+                                   real_alias);
        }
+       alias->resolution = (enum ld_plugin_symbol_resolution)lto_input_uleb128 (ib);
     }
   return node;
 }
@@ -1123,7 +1134,6 @@ input_varpool_node (struct lto_file_decl_data *file_data,
   node->force_output = bp_unpack_value (&bp, 1);
   node->finalized = bp_unpack_value (&bp, 1);
   node->alias = bp_unpack_value (&bp, 1);
-  node->const_value_known = bp_unpack_value (&bp, 1);
   node->analyzed = node->finalized; 
   node->used_from_other_partition = bp_unpack_value (&bp, 1);
   node->in_other_partition = bp_unpack_value (&bp, 1);
@@ -1138,6 +1148,7 @@ input_varpool_node (struct lto_file_decl_data *file_data,
   ref = lto_input_sleb128 (ib);
   /* Store a reference for now, and fix up later to be a pointer.  */
   node->same_comdat_group = (struct varpool_node *) (intptr_t) ref;
+  node->resolution = (enum ld_plugin_symbol_resolution)lto_input_uleb128 (ib);
   if (aliases_p)
     {
       count = lto_input_uleb128 (ib);
@@ -1145,7 +1156,9 @@ input_varpool_node (struct lto_file_decl_data *file_data,
        {
          tree decl = lto_file_decl_data_get_var_decl (file_data,
                                                       lto_input_uleb128 (ib));
-         varpool_extra_name_alias (decl, var_decl);
+         struct varpool_node *alias;
+         alias = varpool_extra_name_alias (decl, var_decl);
+         alias->resolution = (enum ld_plugin_symbol_resolution)lto_input_uleb128 (ib);
        }
     }
   return node;
index bdfbd7d67a2ba447ef4480f2fbcf3bc8a57541de..1d90ab113f60992af02ad145fb14bd588046b763 100644 (file)
@@ -51,6 +51,8 @@ struct GTY(()) lto_symtab_entry_def
   /* LTO file-data and symbol resolution for this decl.  */
   struct lto_file_decl_data * GTY((skip (""))) file_data;
   enum ld_plugin_symbol_resolution resolution;
+  /* True when resolution was guessed and not read from the file.  */
+  bool guessed;
   /* Pointer to the next entry with the same key.  Before decl merging
      this links all symbols from the different TUs.  After decl merging
      this links merged but incompatible decls, thus all prevailing ones
@@ -513,12 +515,14 @@ lto_symtab_resolve_symbols (void **slot)
       if (!lto_symtab_resolve_can_prevail_p (e))
        {
          e->resolution = LDPR_RESOLVED_IR;
+          e->guessed = true;
          continue;
        }
 
       /* Set a default resolution - the final prevailing one will get
          adjusted later.  */
       e->resolution = LDPR_PREEMPTED_IR;
+      e->guessed = true;
       if (!lto_symtab_resolve_replaceable_p (e))
        {
          if (prevailing)
@@ -572,6 +576,7 @@ found:
     resolution file.  These variables still need manual
     externally_visible attribute.  */
     prevailing->resolution = LDPR_PREVAILING_DEF_IRONLY;
+    prevailing->guessed = true;
 }
 
 /* Merge all decls in the symbol table chain to the prevailing decl and
@@ -740,27 +745,21 @@ lto_symtab_merge_decls_1 (void **slot, void *data ATTRIBUTE_UNUSED)
       && TREE_CODE (prevailing->decl) != VAR_DECL)
     prevailing->next = NULL;
 
-  /* Set used_from_object_file flags.  */
-  if (prevailing->resolution == LDPR_PREVAILING_DEF
-      || prevailing->resolution == LDPR_PREEMPTED_REG
-      || prevailing->resolution == LDPR_RESOLVED_EXEC
-      || prevailing->resolution == LDPR_RESOLVED_DYN)
-    {
-      if (TREE_CODE (prevailing->decl) == FUNCTION_DECL)
-       {
-         if (prevailing->node->same_body_alias)
-           prevailing->node->same_body->local.used_from_object_file = true;
-         else
-           prevailing->node->local.used_from_object_file = true;
-       }
-      else
-       {
-         if (prevailing->vnode->alias)
-           prevailing->vnode->extra_name->used_from_object_file = true;
-         else
-           prevailing->vnode->used_from_object_file = true;
-       }
-    }
+  /* Store resolution decision into the callgraph.  
+     In LTRANS don't overwrite information we stored into callgraph at
+     WPA stage.
+
+     Do not bother to store guessed decisions.  Generic code knows how
+     to handle UNKNOWN relocation well.
+
+     The problem with storing guessed decision is whether to use
+     PREVAILING_DEF or PREVAILING_DEF_IRONLY.  First one would disable
+     some whole program optimizations, while ther second would imply
+     to many whole program assumptions.  */
+  if (prevailing->node && !flag_ltrans && !prevailing->guessed)
+    prevailing->node->resolution = prevailing->resolution;
+  else if (prevailing->vnode && !flag_ltrans && !prevailing->guessed)
+    prevailing->vnode->resolution = prevailing->resolution;
   return 1;
 }
 
index 6aab1af6426687d482ee38038a1a3c57c9a97e58..ec853a9b9e6657ef87707067e5ce04c75b71cbfa 100644 (file)
@@ -1,3 +1,7 @@
+2010-09-24  Jan Hubicka  <jh@suse.cz>
+
+       * lto.c (lto_promote_cross_file_statics): Use const_value_known_p.
+
 2010-09-20  Jan Hubicka  <jh@suse.cz>
 
        PR tree-optimize/45605
index 98a9387ce9d8da0292c6d95f9fc1c54d3ecedeac..f52c66e6a475d1bd0d5008e9f361364ca933af23 100644 (file)
@@ -1048,7 +1048,8 @@ lto_promote_cross_file_statics (void)
                           && !v->externally_visible && v->analyzed)
                    {
                      if (promote_var (v)
-                         && DECL_INITIAL (v->decl) && v->const_value_known
+                         && DECL_INITIAL (v->decl)
+                         && const_value_known_p (v->decl)
                          && !pointer_set_insert (inserted, vnode))
                        VEC_safe_push (varpool_node_ptr, heap,
                                       promoted_initializers, v);
index 1b843f869a40ecc34b6222e8758e7d85ecbfea6c..03950d6305904eb3948efc9d7839db0e80acdea4 100644 (file)
@@ -3002,31 +3002,6 @@ struct GTY(()) tree_parm_decl {
    multiple translation units should be merged.  */
 #define DECL_ONE_ONLY(NODE) (DECL_COMDAT_GROUP (NODE) != NULL_TREE)
 
-/* A replaceable function is one which may be replaced at link-time
-   with an entirely different definition, provided that the
-   replacement has the same type.  For example, functions declared
-   with __attribute__((weak)) on most systems are replaceable.
-
-   COMDAT functions are not replaceable, since all definitions of the
-   function must be equivalent.  It is important that COMDAT functions
-   not be treated as replaceable so that use of C++ template
-   instantiations is not penalized.
-
-   In other respects, the condition is usually equivalent to whether
-   the function binds to the current module (shared library or executable).
-   However, weak functions can always be overridden by earlier TUs
-   in the same module, even if they bind locally to that module.
-
-   For example, DECL_REPLACEABLE is used to determine whether or not a
-   function (including a template instantiation) which is not
-   explicitly declared "inline" can be inlined.  If the function is
-   DECL_REPLACEABLE then it is not safe to do the inlining, since the
-   implementation chosen at link-time may be different.  However, a
-   function that is not DECL_REPLACEABLE can be inlined, since all
-   versions of the function will be functionally identical.  */
-#define DECL_REPLACEABLE_P(NODE) \
-  (!DECL_COMDAT (NODE) && (DECL_WEAK (NODE) || !targetm.binds_local_p (NODE)))
-
 /* The name of the object as the assembler will see it (but before any
    translations made by ASM_OUTPUT_LABELREF).  Often this is the same
    as DECL_NAME.  It is an IDENTIFIER_NODE.  */
@@ -5299,6 +5274,8 @@ extern void process_pending_assemble_externals (void);
 extern void finish_aliases_1 (void);
 extern void finish_aliases_2 (void);
 extern void remove_unreachable_alias_pairs (void);
+extern bool decl_replaceable_p (tree);
+extern bool decl_binds_to_current_def_p (tree);
 
 /* In stmt.c */
 extern void expand_computed_goto (tree);
index 1c2a525c523f4960bab1c46ce54c22f15463ef78..b02462bdec4a391ce2d55df0ecae750f128e70cb 100644 (file)
@@ -6381,6 +6381,30 @@ default_use_anchors_for_symbol_p (const_rtx symbol)
   return true;
 }
 
+/* Return true when RESOLUTION indicate that symbol will be bound to the
+   definition provided by current .o file.  */
+
+static bool
+resolution_to_local_definition_p (enum ld_plugin_symbol_resolution resolution)
+{
+  return (resolution == LDPR_PREVAILING_DEF
+         || resolution == LDPR_PREVAILING_DEF_IRONLY);
+}
+
+/* Return true when RESOLUTION indicate that symbol will be bound locally
+   within current executable or DSO.  */
+
+static bool
+resolution_local_p (enum ld_plugin_symbol_resolution resolution)
+{
+  return (resolution == LDPR_PREVAILING_DEF
+         || resolution == LDPR_PREVAILING_DEF_IRONLY
+         || resolution == LDPR_PREEMPTED_REG
+         || resolution == LDPR_PREEMPTED_IR
+         || resolution == LDPR_RESOLVED_IR
+         || resolution == LDPR_RESOLVED_EXEC);
+}
+
 /* Assume ELF-ish defaults, since that's pretty much the most liberal
    wrt cross-module name binding.  */
 
@@ -6394,12 +6418,41 @@ bool
 default_binds_local_p_1 (const_tree exp, int shlib)
 {
   bool local_p;
+  bool resolved_locally = false;
+  bool resolved_to_local_def = false;
+
+  /* With resolution file in hands, take look into resolutions.
+     We can't just return true for resolved_localy symbols,
+     because dynamic linking might overwrite symbols
+     in shared libraries.  */
+  if (TREE_CODE (exp) == VAR_DECL && TREE_PUBLIC (exp)
+      && (TREE_STATIC (exp) || DECL_EXTERNAL (exp)))
+    {
+      struct varpool_node *vnode = varpool_get_node (exp);
+      if (vnode && resolution_local_p (vnode->resolution))
+       resolved_locally = true;
+      if (vnode
+         && resolution_to_local_definition_p (vnode->resolution))
+       resolved_to_local_def = true;
+    }
+  else if (TREE_CODE (exp) == FUNCTION_DECL && TREE_PUBLIC (exp))
+    {
+      struct cgraph_node *node = cgraph_get_node_or_alias (exp);
+      if (node
+         && resolution_local_p (node->resolution))
+       resolved_locally = true;
+      if (node
+         && resolution_to_local_definition_p (node->resolution))
+       resolved_to_local_def = true;
+    }
 
   /* A non-decl is an entry in the constant pool.  */
   if (!DECL_P (exp))
     local_p = true;
   /* Weakrefs may not bind locally, even though the weakref itself is
-     always static and therefore local.  */
+     always static and therefore local.
+     FIXME: We can resolve this more curefuly by looking at the weakref
+     alias.  */
   else if (lookup_attribute ("weakref", DECL_ATTRIBUTES (exp)))
     local_p = false;
   /* Static variables are always local.  */
@@ -6407,11 +6460,12 @@ default_binds_local_p_1 (const_tree exp, int shlib)
     local_p = true;
   /* A variable is local if the user has said explicitly that it will
      be.  */
-  else if (DECL_VISIBILITY_SPECIFIED (exp)
+  else if ((DECL_VISIBILITY_SPECIFIED (exp)
+           || resolved_to_local_def)
           && DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
     local_p = true;
   /* Variables defined outside this object might not be local.  */
-  else if (DECL_EXTERNAL (exp))
+  else if (DECL_EXTERNAL (exp) && !resolved_locally)
     local_p = false;
   /* If defined in this object and visibility is not default, must be
      local.  */
@@ -6419,16 +6473,17 @@ default_binds_local_p_1 (const_tree exp, int shlib)
     local_p = true;
   /* Default visibility weak data can be overridden by a strong symbol
      in another module and so are not local.  */
-  else if (DECL_WEAK (exp))
+  else if (DECL_WEAK (exp)
+          && !resolved_locally)
     local_p = false;
   /* If PIC, then assume that any global name can be overridden by
-     symbols resolved from other modules, unless we are compiling with
-     -fwhole-program, which assumes that names are local.  */
+     symbols resolved from other modules.  */
   else if (shlib)
-    local_p = flag_whole_program;
+    local_p = false;
   /* Uninitialized COMMON variable may be unified with symbols
      resolved from other modules.  */
   else if (DECL_COMMON (exp)
+          && !resolved_locally
           && (DECL_INITIAL (exp) == NULL
               || DECL_INITIAL (exp) == error_mark_node))
     local_p = false;
@@ -6440,6 +6495,67 @@ default_binds_local_p_1 (const_tree exp, int shlib)
   return local_p;
 }
 
+/* Return true when references to DECL must bind to current definition in
+   final executable.
+
+   The condition is usually equivalent to whether the function binds to the
+   current module (shared library or executable), that is to binds_local_p.
+   We use this fact to avoid need for another target hook and implement
+   the logic using binds_local_p and just special cases where
+   decl_binds_to_current_def_p is stronger than binds local_p.  In particular
+   the weak definitions (that can be overwritten at linktime by other
+   definition from different object file) and when resolution info is available
+   we simply use the knowledge passed to us by linker plugin.  */
+bool
+decl_binds_to_current_def_p (tree decl)
+{
+  gcc_assert (DECL_P (decl));
+  if (!TREE_PUBLIC (decl))
+    return true;
+  if (!targetm.binds_local_p (decl))
+    return false;
+  /* When resolution is available, just use it.  */
+  if (TREE_CODE (decl) == VAR_DECL && TREE_PUBLIC (decl)
+      && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+    {
+      struct varpool_node *vnode = varpool_get_node (decl);
+      if (vnode
+         && vnode->resolution != LDPR_UNKNOWN)
+       return resolution_to_local_definition_p (vnode->resolution);
+    }
+  else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_PUBLIC (decl))
+    {
+      struct cgraph_node *node = cgraph_get_node_or_alias (decl);
+      if (node
+         && node->resolution != LDPR_UNKNOWN)
+       return resolution_to_local_definition_p (node->resolution);
+    }
+  /* Otherwise we have to assume the worst for DECL_WEAK (hidden weaks
+     binds localy but still can be overwritten).
+     This rely on fact that binds_local_p behave as decl_replaceable_p
+     for all other declaration types.  */
+  return !DECL_WEAK (decl);
+}
+
+/* A replaceable function or variable is one which may be replaced
+   at link-time with an entirely different definition, provided that the
+   replacement has the same type.  For example, functions declared
+   with __attribute__((weak)) on most systems are replaceable.
+
+   COMDAT functions are not replaceable, since all definitions of the
+   function must be equivalent.  It is important that COMDAT functions
+   not be treated as replaceable so that use of C++ template
+   instantiations is not penalized.  */
+
+bool
+decl_replaceable_p (tree decl)
+{
+  gcc_assert (DECL_P (decl));
+  if (!TREE_PUBLIC (decl) || DECL_COMDAT (decl))
+    return false;
+  return !decl_binds_to_current_def_p (decl);
+}
+
 /* Default function to output code that will globalize a label.  A
    target must define GLOBAL_ASM_OP or provide its own function to
    globalize a label.  */
index 673905d5a76d761c1fa9654948c9bf84d1f48202..ff3631b3478361c2da7edd2bb092d0f70725f0cb 100644 (file)
@@ -107,7 +107,7 @@ eq_varpool_node (const void *p1, const void *p2)
 
 /* Return varpool node assigned to DECL without creating new one.  */
 struct varpool_node *
-varpool_get_node (tree decl)
+varpool_get_node (const_tree decl)
 {
   struct varpool_node key, **slot;
 
@@ -116,7 +116,7 @@ varpool_get_node (tree decl)
 
   if (!varpool_hash)
     return NULL;
-  key.decl = decl;
+  key.decl = CONST_CAST2 (tree, const_tree, decl);
   slot = (struct varpool_node **)
     htab_find_slot (varpool_hash, &key, NO_INSERT);
   if (!slot)
@@ -365,8 +365,6 @@ decide_is_variable_needed (struct varpool_node *node, tree decl)
 bool
 const_value_known_p (tree decl)
 {
-  struct varpool_node *vnode;
-
   if (TREE_CODE (decl) != VAR_DECL
       &&TREE_CODE (decl) != CONST_DECL)
     return false;
@@ -386,21 +384,12 @@ const_value_known_p (tree decl)
 
   gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl));
 
-  /* In WHOPR mode we can put variable into one partition
-     and make it external in the other partition.  In this
-     case we still know the value, but it can't be determined
-     from DECL flags.  For this reason we keep const_value_known
-     flag in varpool nodes.  */
-  if ((vnode = varpool_get_node (decl))
-      && vnode->const_value_known)
-    return true;
-
   /* Variables declared 'const' without an initializer
      have zero as the initializer if they may not be
      overridden at link or run time.  */
   if (!DECL_INITIAL (decl)
       && (DECL_EXTERNAL (decl)
-         || DECL_REPLACEABLE_P (decl)))
+         || decl_replaceable_p (decl)))
     return false;
 
   /* Variables declared `const' with an initializer are considered
@@ -444,7 +433,6 @@ varpool_finalize_decl (tree decl)
      there.  */
   else if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))
     varpool_mark_needed_node (node);
-  node->const_value_known |= const_value_known_p (node->decl);
   if (cgraph_global_info_ready)
     varpool_assemble_pending_decls ();
 }
@@ -462,7 +450,7 @@ cgraph_variable_initializer_availability (struct varpool_node *node)
   /* If the variable can be overwritten, return OVERWRITABLE.  Takes
      care of at least two notable extensions - the COMDAT variables
      used to share template instantiations in C++.  */
-  if (!(*targetm.binds_local_p) (node->decl) && !DECL_COMDAT (node->decl))
+  if (!decl_replaceable_p (node->decl))
     return AVAIL_OVERWRITABLE;
   return AVAIL_AVAILABLE;
 }
@@ -674,7 +662,7 @@ add_new_static_var (tree type)
 /* Attempt to mark ALIAS as an alias to DECL.  Return TRUE if successful.
    Extra name aliases are output whenever DECL is output.  */
 
-bool
+struct varpool_node *
 varpool_extra_name_alias (tree alias, tree decl)
 {
   struct varpool_node key, *alias_node, *decl_node, **slot;
@@ -695,7 +683,7 @@ varpool_extra_name_alias (tree alias, tree decl)
 
   /* If the varpool_node has been already created, fail.  */
   if (*slot)
-    return false;
+    return NULL;
 
   alias_node = ggc_alloc_cleared_varpool_node ();
   alias_node->decl = alias;
@@ -707,7 +695,26 @@ varpool_extra_name_alias (tree alias, tree decl)
     decl_node->extra_name->prev = alias_node;
   decl_node->extra_name = alias_node;
   *slot = alias_node;
-  return true;
+  return alias_node;
+}
+
+/* Return true when NODE is known to be used from other (non-LTO) object file.
+   Known only when doing LTO via linker plugin.  */
+
+bool
+varpool_used_from_object_file_p (struct varpool_node *node)
+{
+  struct varpool_node *alias;
+
+  if (!TREE_PUBLIC (node->decl))
+    return false;
+  if (resolution_used_from_other_file_p (node->resolution))
+    return true;
+  for (alias = node->extra_name; alias; alias = alias->next)
+    if (TREE_PUBLIC (alias->decl)
+       && resolution_used_from_other_file_p (alias->resolution))
+      return true;
+  return false;
 }
 
 #include "gt-varpool.h"