/* Callgraph handling code.
- Copyright (C) 2003-2014 Free Software Foundation, Inc.
+ Copyright (C) 2003-2020 Free Software Foundation, Inc.
Contributed by Jan Hubicka
This file is part of GCC.
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
+#include "target.h"
#include "tree.h"
-#include "varasm.h"
-#include "predict.h"
-#include "basic-block.h"
-#include "hash-map.h"
-#include "is-a.h"
-#include "plugin-api.h"
-#include "vec.h"
-#include "hashtab.h"
-#include "hash-set.h"
-#include "machmode.h"
-#include "hard-reg-set.h"
-#include "input.h"
-#include "function.h"
-#include "ipa-ref.h"
-#include "cgraph.h"
-#include "langhooks.h"
-#include "diagnostic-core.h"
+#include "gimple.h"
#include "timevar.h"
+#include "cgraph.h"
+#include "lto-streamer.h"
+#include "varasm.h"
#include "debug.h"
-#include "target.h"
#include "output.h"
-#include "gimple-expr.h"
-#include "flags.h"
-#include "tree-ssa-alias.h"
-#include "gimple.h"
-#include "lto-streamer.h"
+#include "omp-offload.h"
+#include "context.h"
+#include "stringpool.h"
+#include "attribs.h"
-const char * const tls_model_names[]={"none", "tls-emulated", "tls-real",
- "tls-global-dynamic", "tls-local-dynamic",
- "tls-initial-exec", "tls-local-exec"};
+const char * const tls_model_names[]={"none", "emulated",
+ "global-dynamic", "local-dynamic",
+ "initial-exec", "local-exec"};
/* List of hooks triggered on varpool_node events. */
struct varpool_node_hook_list {
varpool_node *
varpool_node::create_empty (void)
-{
- varpool_node *node = ggc_cleared_alloc<varpool_node> ();
- node->type = SYMTAB_VARIABLE;
- return node;
+{
+ return new (ggc_alloc<varpool_node> ()) varpool_node ();
}
/* Return varpool node assigned to DECL. Create new one when needed. */
varpool_node::get_create (tree decl)
{
varpool_node *node = varpool_node::get (decl);
- gcc_checking_assert (TREE_CODE (decl) == VAR_DECL);
+ gcc_checking_assert (VAR_P (decl));
if (node)
return node;
node = varpool_node::create_empty ();
node->decl = decl;
+
+ if ((flag_openacc || flag_openmp)
+ && lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl)))
+ {
+ node->offloadable = 1;
+ if (ENABLE_OFFLOADING && !DECL_EXTERNAL (decl))
+ {
+ g->have_offload = true;
+ if (!in_lto_p)
+ vec_safe_push (offload_vars, decl);
+ }
+ }
+
node->register_symbol ();
return node;
}
varpool_node::remove (void)
{
symtab->call_varpool_removal_hooks (this);
- unregister ();
+ if (lto_file_data)
+ {
+ lto_free_function_in_decl_state_for_node (this);
+ lto_file_data = NULL;
+ }
/* When streaming we can have multiple nodes associated with decl. */
if (symtab->state == LTO_STREAMING)
else if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node
&& !ctor_useable_for_folding_p ())
remove_initializer ();
+
+ unregister ();
ggc_free (this);
}
&& debug_info_level == DINFO_LEVEL_NONE
/* When doing declaration merging we have duplicate
entries for given decl. Do not attempt to remove
- the boides, or we will end up remiving
+ the bodies, or we will end up removing
wrong one. */
&& symtab->state != LTO_STREAMING)
DECL_INITIAL (decl) = error_mark_node;
fprintf (f, " output");
if (used_by_single_function)
fprintf (f, " used-by-single-function");
- if (need_bounds_init)
- fprintf (f, " need-bounds-init");
if (TREE_READONLY (decl))
fprintf (f, " read-only");
if (ctor_useable_for_folding_p ())
if (writeonly)
fprintf (f, " write-only");
if (tls_model)
- fprintf (f, " %s", tls_model_names [tls_model]);
+ fprintf (f, " tls-%s", tls_model_names [tls_model]);
fprintf (f, "\n");
}
size_t len;
if (DECL_INITIAL (decl) != error_mark_node
- || !in_lto_p)
+ || !in_lto_p
+ || !lto_file_data)
return DECL_INITIAL (decl);
timevar_push (TV_IPA_LTO_CTORS_IN);
/* We may have renamed the declaration, e.g., a static function. */
name = lto_get_decl_name_mapping (file_data, name);
+ struct lto_in_decl_state *decl_state
+ = lto_get_function_in_decl_state (file_data, decl);
data = lto_get_section_data (file_data, LTO_section_function_body,
- name, &len);
+ name, order - file_data->order_base,
+ &len, decl_state->compressed);
if (!data)
- fatal_error ("%s: section %s is missing",
+ fatal_error (input_location, "%s: section %s.%d is missing",
file_data->file_name,
- name);
+ name, order - file_data->order_base);
+ if (!quiet_flag)
+ fprintf (stderr, " in:%s", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
lto_input_variable_constructor (file_data, this, data);
+ gcc_assert (DECL_INITIAL (decl) != error_mark_node);
lto_stats.num_function_bodies++;
lto_free_section_data (file_data, LTO_section_function_body, name,
- data, len);
+ data, len, decl_state->compressed);
lto_free_function_in_decl_state_for_node (this);
timevar_pop (TV_IPA_LTO_CTORS_IN);
return DECL_INITIAL (decl);
if (TREE_THIS_VOLATILE (decl))
return false;
+ /* Avoid attempts to load constructors that was not streamed. */
+ if (in_lto_p && DECL_INITIAL (real_node->decl) == error_mark_node
+ && real_node->body_removed)
+ return false;
+
/* If we do not have a constructor, we can't use it. */
if (DECL_INITIAL (real_node->decl) == error_mark_node
&& !real_node->lto_file_data)
return false;
- /* Avoid attempts to load constructors that was not streamed. */
- if (flag_ltrans && DECL_INITIAL (real_node->decl) == error_mark_node
- && real_node->body_removed)
- return false;
-
/* Vtables are defined by their types and must match no matter of interposition
rules. */
if (DECL_VIRTUAL_P (decl))
return DECL_INITIAL (real_node->decl) != NULL;
}
- /* Alias of readonly variable is also readonly, since the variable is stored
- in readonly memory. We also accept readonly aliases of non-readonly
- locations assuming that user knows what he is asking for. */
+ /* An alias of a read-only variable is also read-only, since the variable
+ is stored in read-only memory. We also accept read-only aliases of
+ non-read-only locations assuming that the user knows what he is asking
+ for. */
if (!TREE_READONLY (decl) && !TREE_READONLY (real_node->decl))
return false;
overridden at link or run time.
It is actually requirement for C++ compiler to optimize const variables
- consistently. As a GNU extension, do not enfore this rule for user defined
+ consistently. As a GNU extension, do not enforce this rule for user defined
weak variables, so we support interposition on:
static const int dummy = 0;
extern const int foo __attribute__((__weak__, __alias__("dummy")));
varpool_node *node, *real_node;
tree real_decl;
- if (TREE_CODE (decl) != VAR_DECL
- && TREE_CODE (decl) != CONST_DECL)
- return error_mark_node;
-
- /* Static constant bounds are created to be
- used instead of constants and therefore
- do not let folding it. */
- if (POINTER_BOUNDS_P (decl))
+ if (!VAR_P (decl) && TREE_CODE (decl) != CONST_DECL)
return error_mark_node;
if (TREE_CODE (decl) == CONST_DECL
return error_mark_node;
/* Do not care about automatic variables. Those are never initialized
- anyway, because gimplifier exapnds the code. */
+ anyway, because gimplifier expands the code. */
if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
{
gcc_assert (!TREE_PUBLIC (decl));
return error_mark_node;
}
- gcc_assert (TREE_CODE (decl) == VAR_DECL);
+ gcc_assert (VAR_P (decl));
real_node = node = varpool_node::get (decl);
if (node)
gcc_assert (!DECL_INITIAL (decl)
|| (node->alias && node->get_alias_target () == real_node)
|| DECL_INITIAL (decl) == error_mark_node);
- if (node->weakref)
+ while (node->transparent_alias && node->analyzed)
{
node = node->get_alias_target ();
decl = node->decl;
/* Return variable availability. See cgraph.h for description of individual
return values. */
enum availability
-varpool_node::get_availability (void)
+varpool_node::get_availability (symtab_node *ref)
{
if (!definition)
return AVAIL_NOT_AVAILABLE;
if (DECL_IN_CONSTANT_POOL (decl)
|| DECL_VIRTUAL_P (decl))
return AVAIL_AVAILABLE;
- if (alias && weakref)
+ if (transparent_alias && definition)
{
enum availability avail;
- ultimate_alias_target (&avail)->get_availability ();
+ ultimate_alias_target (&avail, ref);
return avail;
}
+ /* If this is a reference from symbol itself and there are no aliases, we
+ may be sure that the symbol was not interposed by something else because
+ the symbol itself would be unreachable otherwise. */
+ if ((this == ref && !has_aliases_p ())
+ || (ref && get_comdat_group ()
+ && get_comdat_group () == ref->get_comdat_group ()))
+ return AVAIL_AVAILABLE;
/* If the variable can be overwritten, return OVERWRITABLE. Takes
care of at least one notable extension - the COMDAT variables
used to share template instantiations in C++. */
FOR_EACH_ALIAS (this, ref)
{
varpool_node *alias = dyn_cast <varpool_node *> (ref->referring);
- do_assemble_alias (alias->decl,
- DECL_ASSEMBLER_NAME (decl));
+ if (alias->symver)
+ do_assemble_symver (alias->decl,
+ DECL_ASSEMBLER_NAME (decl));
+ else if (!alias->transparent_alias)
+ do_assemble_alias (alias->decl,
+ DECL_ASSEMBLER_NAME (decl));
alias->assemble_aliases ();
}
}
bool
varpool_node::assemble_decl (void)
{
- /* Aliases are outout when their target is produced or by
+ /* Aliases are output when their target is produced or by
output_weakrefs. */
if (alias)
return false;
return false;
gcc_checking_assert (!TREE_ASM_WRITTEN (decl)
- && TREE_CODE (decl) == VAR_DECL
+ && VAR_P (decl)
&& !DECL_HAS_VALUE_EXPR_P (decl));
if (!in_other_partition
gcc_assert (TREE_ASM_WRITTEN (decl));
gcc_assert (definition);
assemble_aliases ();
+ /* After the parser has generated debugging information, augment
+ this information with any new location/etc information that may
+ have become available after the compilation proper. */
+ debug_hooks->late_global_decl (decl);
return true;
}
{
enqueue_node (node, &first);
if (dump_file)
- fprintf (dump_file, " %s", node->asm_name ());
+ fprintf (dump_file, " %s", node->dump_asm_name ());
}
}
while (first != (varpool_node *)(void *)1)
&& vnode->analyzed)
enqueue_node (vnode, &first);
else
- referenced.add (node);
+ {
+ referenced.add (vnode);
+ while (vnode && vnode->alias && vnode->definition)
+ {
+ vnode = vnode->get_alias_target ();
+ referenced.add (vnode);
+ }
+ }
}
}
if (dump_file)
if (!node->aux && !node->no_reorder)
{
if (dump_file)
- fprintf (dump_file, " %s", node->asm_name ());
+ fprintf (dump_file, " %s", node->dump_asm_name ());
if (referenced.contains(node))
node->remove_initializer ();
else
&& !alias
&& !in_other_partition
&& !DECL_EXTERNAL (decl)
- && TREE_CODE (decl) == VAR_DECL
+ && VAR_P (decl)
&& !DECL_HAS_VALUE_EXPR_P (decl)
&& get_section ())
get_variable_section (decl, false);
node->finalize_named_section_flags ();
}
- FOR_EACH_DEFINED_VARIABLE (node)
+ /* There is a similar loop in output_in_order. Please keep them in sync. */
+ FOR_EACH_VARIABLE (node)
{
/* Handled in output_in_order. */
if (node->no_reorder)
continue;
- if (node->assemble_decl ())
- changed = true;
+ if (DECL_HARD_REGISTER (node->decl)
+ || DECL_HAS_VALUE_EXPR_P (node->decl))
+ continue;
+ if (node->definition)
+ changed |= node->assemble_decl ();
+ else
+ assemble_undefined_decl (node->decl);
}
timevar_pop (TV_VAROUT);
return changed;
}
-/* Create a new global variable of type TYPE. */
-tree
-add_new_static_var (tree type)
-{
- tree new_decl;
- varpool_node *new_node;
-
- new_decl = create_tmp_var_raw (type, NULL);
- DECL_NAME (new_decl) = create_tmp_var_name (NULL);
- TREE_READONLY (new_decl) = 0;
- TREE_STATIC (new_decl) = 1;
- TREE_USED (new_decl) = 1;
- DECL_CONTEXT (new_decl) = NULL_TREE;
- DECL_ABSTRACT_P (new_decl) = false;
- lang_hooks.dup_lang_specific_decl (new_decl);
- new_node = varpool_node::get_create (new_decl);
- varpool_node::finalize_decl (new_decl);
-
- return new_node->decl;
-}
-
/* Attempt to mark ALIAS as an alias to DECL. Return TRUE if successful.
Extra name aliases are output whenever DECL is output. */
{
varpool_node *alias_node;
- gcc_assert (TREE_CODE (decl) == VAR_DECL);
- gcc_assert (TREE_CODE (alias) == VAR_DECL);
+ gcc_assert (VAR_P (decl));
+ gcc_assert (VAR_P (alias));
alias_node = varpool_node::get_create (alias);
alias_node->alias = true;
alias_node->definition = true;
alias_node->alias_target = decl;
if (lookup_attribute ("weakref", DECL_ATTRIBUTES (alias)) != NULL)
- alias_node->weakref = true;
+ alias_node->weakref = alias_node->transparent_alias = true;
return alias_node;
}
{
varpool_node *alias_node;
-#ifndef ASM_OUTPUT_DEF
/* If aliases aren't supported by the assembler, fail. */
- return NULL;
-#endif
+ if (!TARGET_SUPPORTS_ALIASES)
+ return NULL;
+
alias_node = varpool_node::create_alias (alias, decl);
alias_node->cpp_implicit_alias = true;
- /* Extra name alias mechanizm creates aliases really late
- via DECL_ASSEMBLER_NAME mechanizm.
+ /* Extra name alias mechanism creates aliases really late
+ via DECL_ASSEMBLER_NAME mechanism.
This is unfortunate because they are not going through the
standard channels. Ensure they get output. */
if (symtab->cpp_implicit_aliases_done)
return alias_node;
}
-/* Call calback on varpool symbol and aliases associated to varpool symbol.
- When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are
- skipped. */
+/* Worker for call_for_symbol_and_aliases. */
bool
-varpool_node::call_for_node_and_aliases (bool (*callback) (varpool_node *,
- void *),
- void *data,
- bool include_overwritable)
+varpool_node::call_for_symbol_and_aliases_1 (bool (*callback) (varpool_node *,
+ void *),
+ void *data,
+ bool include_overwritable)
{
ipa_ref *ref;
- if (callback (this, data))
- return true;
-
FOR_EACH_ALIAS (this, ref)
{
varpool_node *alias = dyn_cast <varpool_node *> (ref->referring);
if (include_overwritable
|| alias->get_availability () > AVAIL_INTERPOSABLE)
- if (alias->call_for_node_and_aliases (callback, data,
- include_overwritable))
+ if (alias->call_for_symbol_and_aliases (callback, data,
+ include_overwritable))
return true;
}
return false;