From b9de1157289455b0ca26daff519d4a0ddcd1fa13 Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Wed, 24 Feb 2016 13:48:45 -0800 Subject: Update 4.8.1 to 4.8.3. My previous drop was the wrong version. The platform mingw is currently using 4.8.3, not 4.8.1 (not sure how I got that wrong). From ftp://ftp.gnu.org/gnu/gcc/gcc-4.8.3/gcc-4.8.3.tar.bz2. Bug: http://b/26523949 Change-Id: Id85f1bdcbbaf78c7d0b5a69e74c798a08f341c35 --- gcc-4.8.3/gcc/varpool.c | 543 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 543 insertions(+) create mode 100644 gcc-4.8.3/gcc/varpool.c (limited to 'gcc-4.8.3/gcc/varpool.c') diff --git a/gcc-4.8.3/gcc/varpool.c b/gcc-4.8.3/gcc/varpool.c new file mode 100644 index 000000000..f5a905c75 --- /dev/null +++ b/gcc-4.8.3/gcc/varpool.c @@ -0,0 +1,543 @@ +/* Callgraph handling code. + Copyright (C) 2003-2013 Free Software Foundation, Inc. + Contributed by Jan Hubicka + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "cgraph.h" +#include "langhooks.h" +#include "diagnostic-core.h" +#include "hashtab.h" +#include "ggc.h" +#include "timevar.h" +#include "debug.h" +#include "target.h" +#include "output.h" +#include "gimple.h" +#include "tree-flow.h" +#include "flags.h" + +/* Return varpool node assigned to DECL. Create new one when needed. */ +struct varpool_node * +varpool_node_for_decl (tree decl) +{ + struct varpool_node *node = varpool_get_node (decl); + gcc_assert (TREE_CODE (decl) == VAR_DECL + && (TREE_STATIC (decl) || DECL_EXTERNAL (decl) || in_lto_p)); + if (node) + return node; + + node = ggc_alloc_cleared_varpool_node (); + node->symbol.type = SYMTAB_VARIABLE; + node->symbol.decl = decl; + symtab_register_node ((symtab_node)node); + return node; +} + +/* Remove node from the varpool. */ +void +varpool_remove_node (struct varpool_node *node) +{ + symtab_unregister_node ((symtab_node)node); + if (DECL_INITIAL (node->symbol.decl) + && !DECL_IN_CONSTANT_POOL (node->symbol.decl) + /* Keep vtables for BINFO folding. */ + && !DECL_VIRTUAL_P (node->symbol.decl) + /* FIXME: http://gcc.gnu.org/PR55395 */ + && debug_info_level == DINFO_LEVEL_NONE) + DECL_INITIAL (node->symbol.decl) = error_mark_node; + ggc_free (node); +} + +/* Dump given cgraph node. */ +void +dump_varpool_node (FILE *f, struct varpool_node *node) +{ + dump_symtab_base (f, (symtab_node)node); + fprintf (f, " Availability: %s\n", + cgraph_function_flags_ready + ? cgraph_availability_names[cgraph_variable_initializer_availability (node)] + : "not-ready"); + fprintf (f, " Varpool flags:"); + if (DECL_INITIAL (node->symbol.decl)) + fprintf (f, " initialized"); + if (node->analyzed) + fprintf (f, " analyzed"); + if (node->finalized) + fprintf (f, " finalized"); + if (node->output) + fprintf (f, " output"); + fprintf (f, "\n"); +} + +/* Dump the variable pool. */ +void +dump_varpool (FILE *f) +{ + struct varpool_node *node; + + fprintf (f, "variable pool:\n\n"); + FOR_EACH_VARIABLE (node) + dump_varpool_node (f, node); +} + +/* Dump the variable pool to stderr. */ + +DEBUG_FUNCTION void +debug_varpool (void) +{ + dump_varpool (stderr); +} + +/* Given an assembler name, lookup node. */ +struct varpool_node * +varpool_node_for_asm (tree asmname) +{ + if (symtab_node node = symtab_node_for_asm (asmname)) + if (varpool_node *vnode = dyn_cast (node)) + return vnode; + return NULL; +} + +/* Determine if variable DECL is needed. That is, visible to something + either outside this translation unit, something magic in the system + configury */ +bool +decide_is_variable_needed (struct varpool_node *node, tree decl) +{ + if (DECL_EXTERNAL (decl)) + return false; + + /* If the user told us it is used, then it must be so. */ + if (node->symbol.force_output) + return true; + + /* Externally visible variables must be output. The exception is + COMDAT variables that must be output only when they are needed. */ + if (TREE_PUBLIC (decl) + && !DECL_COMDAT (decl)) + return true; + + return false; +} + +/* Return if DECL is constant and its initial value is known (so we can do + constant folding using DECL_INITIAL (decl)). */ + +bool +const_value_known_p (tree decl) +{ + if (TREE_CODE (decl) != VAR_DECL + &&TREE_CODE (decl) != CONST_DECL) + return false; + + if (TREE_CODE (decl) == CONST_DECL + || DECL_IN_CONSTANT_POOL (decl)) + return true; + + gcc_assert (TREE_CODE (decl) == VAR_DECL); + + if (!TREE_READONLY (decl) || TREE_THIS_VOLATILE (decl)) + return false; + + /* Gimplifier takes away constructors of local vars */ + if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) + return DECL_INITIAL (decl) != NULL; + + gcc_assert (TREE_STATIC (decl) || DECL_EXTERNAL (decl)); + + /* 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))) + return false; + + /* Variables declared `const' with an initializer are considered + to not be overwritable with different initializer by default. + + ??? Previously we behaved so for scalar variables but not for array + accesses. */ + return true; +} + +/* Add the variable DECL to the varpool. + Unlike varpool_finalize_decl function is intended to be used + by middle end and allows insertion of new variable at arbitrary point + of compilation. */ +void +varpool_add_new_variable (tree decl) +{ + struct varpool_node *node; + varpool_finalize_decl (decl); + node = varpool_node_for_decl (decl); + if (varpool_externally_visible_p (node, false)) + node->symbol.externally_visible = true; +} + +/* Return variable availability. See cgraph.h for description of individual + return values. */ +enum availability +cgraph_variable_initializer_availability (struct varpool_node *node) +{ + gcc_assert (cgraph_function_flags_ready); + if (!node->finalized) + return AVAIL_NOT_AVAILABLE; + if (!TREE_PUBLIC (node->symbol.decl)) + return AVAIL_AVAILABLE; + /* 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 (!decl_replaceable_p (node->symbol.decl)) + return AVAIL_OVERWRITABLE; + return AVAIL_AVAILABLE; +} + +void +varpool_analyze_node (struct varpool_node *node) +{ + tree decl = node->symbol.decl; + + /* When reading back varpool at LTO time, we re-construct the queue in order + to have "needed" list right by inserting all needed nodes into varpool. + We however don't want to re-analyze already analyzed nodes. */ + if (!node->analyzed) + { + gcc_assert (!in_lto_p || cgraph_function_flags_ready); + /* Compute the alignment early so function body expanders are + already informed about increased alignment. */ + align_variable (decl, 0); + } + if (node->alias && node->alias_of) + { + struct varpool_node *tgt = varpool_node_for_decl (node->alias_of); + struct varpool_node *n; + + for (n = tgt; n && n->alias; + n = n->analyzed ? varpool_alias_aliased_node (n) : NULL) + if (n == node) + { + error ("variable %q+D part of alias cycle", node->symbol.decl); + node->alias = false; + continue; + } + if (!vec_safe_length (node->symbol.ref_list.references)) + ipa_record_reference ((symtab_node)node, (symtab_node)tgt, IPA_REF_ALIAS, NULL); + if (node->extra_name_alias) + { + DECL_WEAK (node->symbol.decl) = DECL_WEAK (node->alias_of); + DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (node->alias_of); + DECL_VISIBILITY (node->symbol.decl) = DECL_VISIBILITY (node->alias_of); + fixup_same_cpp_alias_visibility ((symtab_node) node, + (symtab_node) tgt, node->alias_of); + } + } + else if (DECL_INITIAL (decl)) + record_references_in_initializer (decl, node->analyzed); + node->analyzed = true; +} + +/* Assemble thunks and aliases associated to NODE. */ + +static void +assemble_aliases (struct varpool_node *node) +{ + int i; + struct ipa_ref *ref; + for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, i, ref); i++) + if (ref->use == IPA_REF_ALIAS) + { + struct varpool_node *alias = ipa_ref_referring_varpool_node (ref); + do_assemble_alias (alias->symbol.decl, + DECL_ASSEMBLER_NAME (alias->alias_of)); + assemble_aliases (alias); + } +} + +/* Output one variable, if necessary. Return whether we output it. */ + +bool +varpool_assemble_decl (struct varpool_node *node) +{ + tree decl = node->symbol.decl; + + /* Aliases are outout when their target is produced or by + output_weakrefs. */ + if (node->alias) + return false; + + /* Constant pool is output from RTL land when the reference + survive till this level. */ + if (DECL_IN_CONSTANT_POOL (decl) && TREE_ASM_WRITTEN (decl)) + return false; + + /* Decls with VALUE_EXPR should not be in the varpool at all. They + are not real variables, but just info for debugging and codegen. + Unfortunately at the moment emutls is not updating varpool correctly + after turning real vars into value_expr vars. */ + if (DECL_HAS_VALUE_EXPR_P (decl) + && !targetm.have_tls) + return false; + + /* Hard register vars do not need to be output. */ + if (DECL_HARD_REGISTER (decl)) + return false; + + gcc_checking_assert (!TREE_ASM_WRITTEN (decl) + && TREE_CODE (decl) == VAR_DECL + && !DECL_HAS_VALUE_EXPR_P (decl)); + + if (!node->symbol.in_other_partition + && !DECL_EXTERNAL (decl)) + { + assemble_variable (decl, 0, 1, 0); + gcc_assert (TREE_ASM_WRITTEN (decl)); + node->finalized = 1; + assemble_aliases (node); + return true; + } + + return false; +} + +/* Add NODE to queue starting at FIRST. + The queue is linked via AUX pointers and terminated by pointer to 1. */ + +static void +enqueue_node (struct varpool_node *node, struct varpool_node **first) +{ + if (node->symbol.aux) + return; + gcc_checking_assert (*first); + node->symbol.aux = *first; + *first = node; +} + +/* Optimization of function bodies might've rendered some variables as + unnecessary so we want to avoid these from being compiled. Re-do + reachability starting from variables that are either externally visible + or was referred from the asm output routines. */ + +static void +varpool_remove_unreferenced_decls (void) +{ + struct varpool_node *next, *node; + struct varpool_node *first = (struct varpool_node *)(void *)1; + int i; + struct ipa_ref *ref; + + if (seen_error ()) + return; + + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "Trivially needed variables:"); + FOR_EACH_DEFINED_VARIABLE (node) + { + if (node->analyzed + && (!varpool_can_remove_if_no_refs (node) + /* We just expanded all function bodies. See if any of + them needed the variable. */ + || DECL_RTL_SET_P (node->symbol.decl))) + { + enqueue_node (node, &first); + if (cgraph_dump_file) + fprintf (cgraph_dump_file, " %s", varpool_node_asm_name (node)); + } + } + while (first != (struct varpool_node *)(void *)1) + { + node = first; + first = (struct varpool_node *)first->symbol.aux; + + if (node->symbol.same_comdat_group) + { + symtab_node next; + for (next = node->symbol.same_comdat_group; + next != (symtab_node)node; + next = next->symbol.same_comdat_group) + { + varpool_node *vnext = dyn_cast (next); + if (vnext && vnext->analyzed) + enqueue_node (vnext, &first); + } + } + for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, i, ref); i++) + { + varpool_node *vnode = dyn_cast (ref->referred); + if (vnode + && (!DECL_EXTERNAL (ref->referred->symbol.decl) + || vnode->alias) + && vnode->analyzed) + enqueue_node (vnode, &first); + } + } + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "\nRemoving variables:"); + for (node = varpool_first_defined_variable (); node; node = next) + { + next = varpool_next_defined_variable (node); + if (!node->symbol.aux) + { + if (cgraph_dump_file) + fprintf (cgraph_dump_file, " %s", varpool_node_asm_name (node)); + varpool_remove_node (node); + } + } + if (cgraph_dump_file) + fprintf (cgraph_dump_file, "\n"); +} + +/* For variables in named sections make sure get_variable_section + is called before we switch to those sections. Then section + conflicts between read-only and read-only requiring relocations + sections can be resolved. */ +void +varpool_finalize_named_section_flags (struct varpool_node *node) +{ + if (!TREE_ASM_WRITTEN (node->symbol.decl) + && !node->alias + && !node->symbol.in_other_partition + && !DECL_EXTERNAL (node->symbol.decl) + && TREE_CODE (node->symbol.decl) == VAR_DECL + && !DECL_HAS_VALUE_EXPR_P (node->symbol.decl) + && DECL_SECTION_NAME (node->symbol.decl)) + get_variable_section (node->symbol.decl, false); +} + +/* Output all variables enqueued to be assembled. */ +bool +varpool_output_variables (void) +{ + bool changed = false; + struct varpool_node *node; + + if (seen_error ()) + return false; + + varpool_remove_unreferenced_decls (); + + timevar_push (TV_VAROUT); + + FOR_EACH_DEFINED_VARIABLE (node) + varpool_finalize_named_section_flags (node); + + FOR_EACH_DEFINED_VARIABLE (node) + if (varpool_assemble_decl (node)) + changed = true; + timevar_pop (TV_VAROUT); + return changed; +} + +/* Create a new global variable of type TYPE. */ +tree +add_new_static_var (tree type) +{ + tree new_decl; + struct 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 (new_decl) = 0; + lang_hooks.dup_lang_specific_decl (new_decl); + new_node = varpool_node_for_decl (new_decl); + varpool_finalize_decl (new_decl); + + return new_node->symbol.decl; +} + +/* Attempt to mark ALIAS as an alias to DECL. Return TRUE if successful. + Extra name aliases are output whenever DECL is output. */ + +struct varpool_node * +varpool_create_variable_alias (tree alias, tree decl) +{ + struct varpool_node *alias_node; + + gcc_assert (TREE_CODE (decl) == VAR_DECL); + gcc_assert (TREE_CODE (alias) == VAR_DECL); + alias_node = varpool_node_for_decl (alias); + alias_node->alias = 1; + alias_node->finalized = 1; + alias_node->alias_of = decl; + + /* Extra name alias mechanizm creates aliases really late + via DECL_ASSEMBLER_NAME mechanizm. + This is unfortunate because they are not going through the + standard channels. Ensure they get output. */ + if (cgraph_state >= CGRAPH_STATE_IPA) + { + varpool_analyze_node (alias_node); + if (TREE_PUBLIC (alias)) + alias_node->symbol.externally_visible = true; + } + return alias_node; +} + +/* Attempt to mark ALIAS as an alias to DECL. Return TRUE if successful. + Extra name aliases are output whenever DECL is output. */ + +struct varpool_node * +varpool_extra_name_alias (tree alias, tree decl) +{ + struct varpool_node *alias_node; + +#ifndef ASM_OUTPUT_DEF + /* If aliases aren't supported by the assembler, fail. */ + return NULL; +#endif + alias_node = varpool_create_variable_alias (alias, decl); + alias_node->extra_name_alias = true; + return alias_node; +} + +/* Call calback on NODE and aliases associated to NODE. + When INCLUDE_OVERWRITABLE is false, overwritable aliases and thunks are + skipped. */ + +bool +varpool_for_node_and_aliases (struct varpool_node *node, + bool (*callback) (struct varpool_node *, void *), + void *data, + bool include_overwritable) +{ + int i; + struct ipa_ref *ref; + + if (callback (node, data)) + return true; + for (i = 0; ipa_ref_list_referring_iterate (&node->symbol.ref_list, i, ref); i++) + if (ref->use == IPA_REF_ALIAS) + { + struct varpool_node *alias = ipa_ref_referring_varpool_node (ref); + if (include_overwritable + || cgraph_variable_initializer_availability (alias) > AVAIL_OVERWRITABLE) + if (varpool_for_node_and_aliases (alias, callback, data, + include_overwritable)) + return true; + } + return false; +} -- cgit v1.2.3