diff options
-rw-r--r-- | gcc/ChangeLog | 15 | ||||
-rw-r--r-- | gcc/Makefile.in | 1 | ||||
-rw-r--r-- | gcc/cgraph.h | 4 | ||||
-rw-r--r-- | gcc/ipa-visibility.c | 758 | ||||
-rw-r--r-- | gcc/ipa.c | 682 |
5 files changed, 778 insertions, 682 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9477db83c32..05f5e3efb1e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,20 @@ 2014-05-23 Jan Hubicka <hubicka@ucw.cz> + * ipa.c (cgraph_non_local_node_p_1, cgraph_local_node_p, address_taken_from_non_vtable_p, + comdat_can_be_unshared_p_1, comdat_can_be_unshared_p, cgraph_externally_visible_p, + varpool_externally_visible_p, can_replace_by_local_alias, + update_visibility_by_resolution_info, function_and_variable_visibility, + pass_data_ipa_function_and_variable_visibility, + make_pass_ipa_function_and_variable_visibility, + whole_program_function_and_variable_visibility, + pass_data_ipa_whole_program_visibility, + make_pass_ipa_whole_program_visibility): Move to ipa-visibility.c + * cgraph.h (cgraph_local_node_p): Declare. + * ipa-visibility.c: New file. + * Makefile.in (OBJS): Add ipa-visiblity.o + +2014-05-23 Jan Hubicka <hubicka@ucw.cz> + * gimple-fold.c (can_refer_decl_in_current_unit_p): Be sure that var decl is available. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index e74bb67c4da..335018606e5 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1270,6 +1270,7 @@ OBJS = \ ipa-split.o \ ipa-inline.o \ ipa-comdats.o \ + ipa-visibility.o \ ipa-inline-analysis.o \ ipa-inline-transform.o \ ipa-profile.o \ diff --git a/gcc/cgraph.h b/gcc/cgraph.h index cfb2d4850fd..91bcc000369 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -963,6 +963,10 @@ void free_varpool_node_set (varpool_node_set); void ipa_discover_readonly_nonaddressable_vars (void); bool varpool_externally_visible_p (varpool_node *); +/* In ipa-visibility.c */ +bool cgraph_local_node_p (struct cgraph_node *); + + /* In predict.c */ bool cgraph_maybe_hot_edge_p (struct cgraph_edge *e); bool cgraph_optimize_for_size_p (struct cgraph_node *); diff --git a/gcc/ipa-visibility.c b/gcc/ipa-visibility.c new file mode 100644 index 00000000000..b091071d448 --- /dev/null +++ b/gcc/ipa-visibility.c @@ -0,0 +1,758 @@ +/* IPA visibility pass + Copyright (C) 2003-2014 Free Software Foundation, Inc. + +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 +<http://www.gnu.org/licenses/>. */ + +/* This file implements two related passes: + + - pass_data_ipa_function_and_variable_visibility run just after + symbol table, references and callgraph are built + + - pass_data_ipa_function_and_variable_visibility run as first + proper IPA pass (that is after early optimization, or, (with LTO) + as a first pass done at link-time. + + Purpose of both passes is to set correctly visibility properties + of all symbols. This includes: + + - Symbol privatization: + + Some symbols that are declared public by frontend may be + turned local (either by -fwhole-program flag, by linker plugin feedback + or by other reasons) + + - Discovery of local functions: + + A local function is one whose calls can occur only in the current + compilation unit and all its calls are explicit, so we can change + its calling convention. We simply mark all static functions whose + address is not taken as local. + + externally_visible flag is set for symbols that can not be privatized. + For privatized symbols we clear TREE_PUBLIC flag and dismantle comdat + group. + + - Dismantling of comdat groups: + + Comdat group represent a section that may be replaced by linker by + a different copy of the same section from other unit. + If we have resolution information (from linker plugin) and we know that + a given comdat gorup is prevailing, we can dismantle it and turn symbols + into normal symbols. If the resolution information says that the + section was previaled by copy from non-LTO code, we can also dismantle + it and turn all symbols into external. + + - Local aliases: + + Some symbols can be interposed by dynamic linker. Refering to these + symbols is expensive, since it needs to be overwritable by the dynamic + linker. In some cases we know that the interposition does not change + semantic and we can always refer to a local copy (as in the case of + inline function). In this case we produce a local alias and redirect + calls to it. + + TODO: This should be done for references, too. + + - Removal of static ocnstructors and destructors that have no side effects. + + - Regularization of several oddities introduced by frontends that may + be impractical later in the optimization queue. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "cgraph.h" +#include "tree-pass.h" +#include "pointer-set.h" +#include "calls.h" +#include "gimple-expr.h" + +/* Return true when NODE can not be local. Worker for cgraph_local_node_p. */ + +static bool +cgraph_non_local_node_p_1 (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) +{ + /* FIXME: Aliases can be local, but i386 gets thunks wrong then. */ + return !(cgraph_only_called_directly_or_aliased_p (node) + && !ipa_ref_has_aliases_p (&node->ref_list) + && node->definition + && !DECL_EXTERNAL (node->decl) + && !node->externally_visible + && !node->used_from_other_partition + && !node->in_other_partition); +} + +/* Return true when function can be marked local. */ + +bool +cgraph_local_node_p (struct cgraph_node *node) +{ + struct cgraph_node *n = cgraph_function_or_thunk_node (node, NULL); + + /* FIXME: thunks can be considered local, but we need prevent i386 + from attempting to change calling convention of them. */ + if (n->thunk.thunk_p) + return false; + return !cgraph_for_node_and_aliases (n, + cgraph_non_local_node_p_1, NULL, true); + +} + +/* Return true when there is a reference to node and it is not vtable. */ +static bool +address_taken_from_non_vtable_p (symtab_node *node) +{ + int i; + struct ipa_ref *ref; + for (i = 0; ipa_ref_list_referring_iterate (&node->ref_list, + i, ref); i++) + if (ref->use == IPA_REF_ADDR) + { + varpool_node *node; + if (is_a <cgraph_node *> (ref->referring)) + return true; + node = ipa_ref_referring_varpool_node (ref); + if (!DECL_VIRTUAL_P (node->decl)) + return true; + } + return false; +} + +/* A helper for comdat_can_be_unshared_p. */ + +static bool +comdat_can_be_unshared_p_1 (symtab_node *node) +{ + if (!node->externally_visible) + return true; + /* When address is taken, we don't know if equality comparison won't + break eventually. Exception are virutal functions, C++ + constructors/destructors and vtables, where this is not possible by + language standard. */ + if (!DECL_VIRTUAL_P (node->decl) + && (TREE_CODE (node->decl) != FUNCTION_DECL + || (!DECL_CXX_CONSTRUCTOR_P (node->decl) + && !DECL_CXX_DESTRUCTOR_P (node->decl))) + && address_taken_from_non_vtable_p (node)) + return false; + + /* If the symbol is used in some weird way, better to not touch it. */ + if (node->force_output) + return false; + + /* Explicit instantiations needs to be output when possibly + used externally. */ + if (node->forced_by_abi + && TREE_PUBLIC (node->decl) + && (node->resolution != LDPR_PREVAILING_DEF_IRONLY + && !flag_whole_program)) + return false; + + /* Non-readonly and volatile variables can not be duplicated. */ + if (is_a <varpool_node *> (node) + && (!TREE_READONLY (node->decl) + || TREE_THIS_VOLATILE (node->decl))) + return false; + return true; +} + +/* COMDAT functions must be shared only if they have address taken, + otherwise we can produce our own private implementation with + -fwhole-program. + Return true when turning COMDAT functoin static can not lead to wrong + code when the resulting object links with a library defining same COMDAT. + + Virtual functions do have their addresses taken from the vtables, + but in C++ there is no way to compare their addresses for equality. */ + +static bool +comdat_can_be_unshared_p (symtab_node *node) +{ + if (!comdat_can_be_unshared_p_1 (node)) + return false; + if (node->same_comdat_group) + { + symtab_node *next; + + /* If more than one function is in the same COMDAT group, it must + be shared even if just one function in the comdat group has + address taken. */ + for (next = node->same_comdat_group; + next != node; next = next->same_comdat_group) + if (!comdat_can_be_unshared_p_1 (next)) + return false; + } + return true; +} + +/* Return true when function NODE should be considered externally visible. */ + +static bool +cgraph_externally_visible_p (struct cgraph_node *node, + bool whole_program) +{ + if (!node->definition) + return false; + if (!TREE_PUBLIC (node->decl) + || DECL_EXTERNAL (node->decl)) + return false; + + /* 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; + + /* If linker counts on us, we must preserve the function. */ + if (symtab_used_from_object_file_p (node)) + return true; + if (DECL_PRESERVE_P (node->decl)) + 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; + if (node->resolution == LDPR_PREVAILING_DEF_IRONLY) + return false; + /* 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 + implementing same COMDAT) */ + if ((in_lto_p || whole_program) + && DECL_COMDAT (node->decl) + && comdat_can_be_unshared_p (node)) + return false; + + /* When doing link time optimizations, hidden symbols become local. */ + if (in_lto_p + && (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN + || DECL_VISIBILITY (node->decl) == VISIBILITY_INTERNAL) + /* Be sure that node is defined in IR file, not in other object + file. In that case we don't set used_from_other_object_file. */ + && node->definition) + ; + else if (!whole_program) + return true; + + if (MAIN_NAME_P (DECL_NAME (node->decl))) + return true; + + return false; +} + +/* Return true when variable VNODE should be considered externally visible. */ + +bool +varpool_externally_visible_p (varpool_node *vnode) +{ + if (DECL_EXTERNAL (vnode->decl)) + return true; + + if (!TREE_PUBLIC (vnode->decl)) + return false; + + /* If linker counts on us, we must preserve the function. */ + if (symtab_used_from_object_file_p (vnode)) + return true; + + if (DECL_HARD_REGISTER (vnode->decl)) + 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. + + Even if the linker clams the symbol is unused, never bring internal + symbols that are declared by user as used or externally visible. + This is needed for i.e. references from asm statements. */ + if (symtab_used_from_object_file_p (vnode)) + return true; + if (vnode->resolution == LDPR_PREVAILING_DEF_IRONLY) + return false; + + /* As a special case, the COMDAT virtual tables can be unshared. + In LTO mode turn vtables into static variables. The variable is readonly, + so this does not enable more optimization, but referring static var + is faster for dynamic linking. Also this match logic hidding vtables + from LTO symbol tables. */ + if ((in_lto_p || flag_whole_program) + && DECL_COMDAT (vnode->decl) + && comdat_can_be_unshared_p (vnode)) + return false; + + /* When doing link time optimizations, hidden symbols become local. */ + if (in_lto_p + && (DECL_VISIBILITY (vnode->decl) == VISIBILITY_HIDDEN + || DECL_VISIBILITY (vnode->decl) == VISIBILITY_INTERNAL) + /* Be sure that node is defined in IR file, not in other object + file. In that case we don't set used_from_other_object_file. */ + && vnode->definition) + ; + else if (!flag_whole_program) + return true; + + /* Do not attempt to privatize COMDATS by default. + This would break linking with C++ libraries sharing + inline definitions. + + FIXME: We can do so for readonly vars with no address taken and + possibly also for vtables since no direct pointer comparsion is done. + It might be interesting to do so to reduce linking overhead. */ + if (DECL_COMDAT (vnode->decl) || DECL_WEAK (vnode->decl)) + return true; + return false; +} + +/* Return true if reference to NODE can be replaced by a local alias. + Local aliases save dynamic linking overhead and enable more optimizations. + */ + +bool +can_replace_by_local_alias (symtab_node *node) +{ + return (symtab_node_availability (node) > AVAIL_OVERWRITABLE + && !symtab_can_be_discarded (node)); +} + +/* In LTO we can remove COMDAT groups and weak symbols. + Either turn them into normal symbols or external symbol depending on + resolution info. */ + +static void +update_visibility_by_resolution_info (symtab_node * node) +{ + bool define; + + if (!node->externally_visible + || (!DECL_WEAK (node->decl) && !DECL_ONE_ONLY (node->decl)) + || node->resolution == LDPR_UNKNOWN) + return; + + define = (node->resolution == LDPR_PREVAILING_DEF_IRONLY + || node->resolution == LDPR_PREVAILING_DEF + || node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP); + + /* The linker decisions ought to agree in the whole group. */ + if (node->same_comdat_group) + for (symtab_node *next = node->same_comdat_group; + next != node; next = next->same_comdat_group) + gcc_assert (!node->externally_visible + || define == (next->resolution == LDPR_PREVAILING_DEF_IRONLY + || next->resolution == LDPR_PREVAILING_DEF + || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)); + + if (node->same_comdat_group) + for (symtab_node *next = node->same_comdat_group; + next != node; next = next->same_comdat_group) + { + next->set_comdat_group (NULL); + DECL_WEAK (next->decl) = false; + if (next->externally_visible + && !define) + DECL_EXTERNAL (next->decl) = true; + } + node->set_comdat_group (NULL); + DECL_WEAK (node->decl) = false; + if (!define) + DECL_EXTERNAL (node->decl) = true; + symtab_dissolve_same_comdat_group_list (node); +} + +/* Decide on visibility of all symbols. */ + +static unsigned int +function_and_variable_visibility (bool whole_program) +{ + struct cgraph_node *node; + varpool_node *vnode; + + /* All aliases should be procssed at this point. */ + gcc_checking_assert (!alias_pairs || !alias_pairs->length ()); + + FOR_EACH_FUNCTION (node) + { + 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)) + { + DECL_STATIC_CONSTRUCTOR (node->decl) = 0; + 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 (DECL_EXTERNAL (node->decl) || !node->definition) + { + node->force_output = 0; + node->forced_by_abi = 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 necessary to keep the flag to make rest of C++ FE + happy. Clear the flag here to avoid confusion in middle-end. */ + if (DECL_COMDAT (node->decl) && !TREE_PUBLIC (node->decl)) + DECL_COMDAT (node->decl) = 0; + + /* For external decls stop tracking same_comdat_group. It doesn't matter + what comdat group they are in when they won't be emitted in this TU. */ + if (node->same_comdat_group && DECL_EXTERNAL (node->decl)) + { +#ifdef ENABLE_CHECKING + symtab_node *n; + + for (n = node->same_comdat_group; + n != node; + n = n->same_comdat_group) + /* If at least one of same comdat group functions is external, + all of them have to be, otherwise it is a front-end bug. */ + gcc_assert (DECL_EXTERNAL (n->decl)); +#endif + symtab_dissolve_same_comdat_group_list (node); + } + gcc_assert ((!DECL_WEAK (node->decl) + && !DECL_COMDAT (node->decl)) + || TREE_PUBLIC (node->decl) + || node->weakref + || DECL_EXTERNAL (node->decl)); + if (cgraph_externally_visible_p (node, whole_program)) + { + gcc_assert (!node->global.inlined_to); + node->externally_visible = true; + } + else + { + node->externally_visible = false; + node->forced_by_abi = false; + } + if (!node->externally_visible + && node->definition && !node->weakref + && !DECL_EXTERNAL (node->decl)) + { + gcc_assert (whole_program || in_lto_p + || !TREE_PUBLIC (node->decl)); + node->unique_name = ((node->resolution == LDPR_PREVAILING_DEF_IRONLY + || node->unique_name + || node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) + && TREE_PUBLIC (node->decl)); + node->resolution = LDPR_PREVAILING_DEF_IRONLY; + if (node->same_comdat_group && TREE_PUBLIC (node->decl)) + { + symtab_node *next = node; + + /* Set all members of comdat group local. */ + if (node->same_comdat_group) + for (next = node->same_comdat_group; + next != node; + next = next->same_comdat_group) + { + next->set_comdat_group (NULL); + symtab_make_decl_local (next->decl); + next->unique_name = ((next->resolution == LDPR_PREVAILING_DEF_IRONLY + || next->unique_name + || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) + && TREE_PUBLIC (next->decl)); + } + /* cgraph_externally_visible_p has already checked all other nodes + in the group and they will all be made local. We need to + dissolve the group at once so that the predicate does not + segfault though. */ + symtab_dissolve_same_comdat_group_list (node); + } + if (TREE_PUBLIC (node->decl)) + node->set_comdat_group (NULL); + symtab_make_decl_local (node->decl); + } + + if (node->thunk.thunk_p + && TREE_PUBLIC (node->decl)) + { + struct cgraph_node *decl_node = node; + + decl_node = cgraph_function_node (decl_node->callees->callee, NULL); + + /* Thunks have the same visibility as function they are attached to. + Make sure the C++ front end set this up properly. */ + if (DECL_ONE_ONLY (decl_node->decl)) + { + gcc_checking_assert (DECL_COMDAT (node->decl) + == DECL_COMDAT (decl_node->decl)); + gcc_checking_assert (symtab_in_same_comdat_p (node, decl_node)); + gcc_checking_assert (node->same_comdat_group); + } + node->forced_by_abi = decl_node->forced_by_abi; + if (DECL_EXTERNAL (decl_node->decl)) + DECL_EXTERNAL (node->decl) = 1; + } + + update_visibility_by_resolution_info (node); + } + FOR_EACH_DEFINED_FUNCTION (node) + { + node->local.local |= cgraph_local_node_p (node); + + /* If we know that function can not be overwritten by a different semantics + and moreover its section can not be discarded, replace all direct calls + by calls to an nonoverwritable alias. This make dynamic linking + cheaper and enable more optimization. + + TODO: We can also update virtual tables. */ + if (node->callers && can_replace_by_local_alias (node)) + { + struct cgraph_node *alias = cgraph (symtab_nonoverwritable_alias (node)); + + if (alias && alias != node) + { + while (node->callers) + { + struct cgraph_edge *e = node->callers; + + cgraph_redirect_edge_callee (e, alias); + if (gimple_has_body_p (e->caller->decl)) + { + push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl)); + cgraph_redirect_edge_call_stmt_to_callee (e); + pop_cfun (); + } + } + } + } + } + FOR_EACH_VARIABLE (vnode) + { + /* weak flag makes no sense on local variables. */ + gcc_assert (!DECL_WEAK (vnode->decl) + || vnode->weakref + || TREE_PUBLIC (vnode->decl) + || DECL_EXTERNAL (vnode->decl)); + /* In several cases declarations can not be common: + + - when declaration has initializer + - when it is in weak + - when it has specific section + - when it resides in non-generic address space. + - if declaration is local, it will get into .local common section + so common flag is not needed. Frontends still produce these in + certain cases, such as for: + + static int a __attribute__ ((common)) + + Canonicalize things here and clear the redundant flag. */ + if (DECL_COMMON (vnode->decl) + && (!(TREE_PUBLIC (vnode->decl) + || DECL_EXTERNAL (vnode->decl)) + || (DECL_INITIAL (vnode->decl) + && DECL_INITIAL (vnode->decl) != error_mark_node) + || DECL_WEAK (vnode->decl) + || DECL_SECTION_NAME (vnode->decl) != NULL + || ! (ADDR_SPACE_GENERIC_P + (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl)))))) + DECL_COMMON (vnode->decl) = 0; + } + FOR_EACH_DEFINED_VARIABLE (vnode) + { + if (!vnode->definition) + continue; + if (varpool_externally_visible_p (vnode)) + vnode->externally_visible = true; + else + { + vnode->externally_visible = false; + vnode->forced_by_abi = false; + } + if (!vnode->externally_visible + && !vnode->weakref) + { + gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->decl)); + vnode->unique_name = ((vnode->resolution == LDPR_PREVAILING_DEF_IRONLY + || vnode->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) + && TREE_PUBLIC (vnode->decl)); + if (vnode->same_comdat_group && TREE_PUBLIC (vnode->decl)) + { + symtab_node *next = vnode; + + /* Set all members of comdat group local. */ + if (vnode->same_comdat_group) + for (next = vnode->same_comdat_group; + next != vnode; + next = next->same_comdat_group) + { + next->set_comdat_group (NULL); + symtab_make_decl_local (next->decl); + next->unique_name = ((next->resolution == LDPR_PREVAILING_DEF_IRONLY + || next->unique_name + || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) + && TREE_PUBLIC (next->decl)); + } + symtab_dissolve_same_comdat_group_list (vnode); + } + if (TREE_PUBLIC (vnode->decl)) + vnode->set_comdat_group (NULL); + symtab_make_decl_local (vnode->decl); + vnode->resolution = LDPR_PREVAILING_DEF_IRONLY; + } + update_visibility_by_resolution_info (vnode); + } + + if (dump_file) + { + fprintf (dump_file, "\nMarking local functions:"); + FOR_EACH_DEFINED_FUNCTION (node) + if (node->local.local) + fprintf (dump_file, " %s", node->name ()); + fprintf (dump_file, "\n\n"); + fprintf (dump_file, "\nMarking externally visible functions:"); + FOR_EACH_DEFINED_FUNCTION (node) + if (node->externally_visible) + fprintf (dump_file, " %s", node->name ()); + fprintf (dump_file, "\n\n"); + fprintf (dump_file, "\nMarking externally visible variables:"); + FOR_EACH_DEFINED_VARIABLE (vnode) + if (vnode->externally_visible) + fprintf (dump_file, " %s", vnode->name ()); + fprintf (dump_file, "\n\n"); + } + cgraph_function_flags_ready = true; + return 0; +} + +/* Local function pass handling visibilities. This happens before LTO streaming + so in particular -fwhole-program should be ignored at this level. */ + +namespace { + +const pass_data pass_data_ipa_function_and_variable_visibility = +{ + SIMPLE_IPA_PASS, /* type */ + "visibility", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + true, /* has_execute */ + TV_CGRAPHOPT, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + ( TODO_remove_functions | TODO_dump_symtab ), /* todo_flags_finish */ +}; + +/* Bring functions local at LTO time with -fwhole-program. */ + +static unsigned int +whole_program_function_and_variable_visibility (void) +{ + function_and_variable_visibility (flag_whole_program); + if (optimize) + ipa_discover_readonly_nonaddressable_vars (); + return 0; +} + +} // anon namespace + +namespace { + +const pass_data pass_data_ipa_whole_program_visibility = +{ + IPA_PASS, /* type */ + "whole-program", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + true, /* has_execute */ + TV_CGRAPHOPT, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + ( TODO_remove_functions | TODO_dump_symtab ), /* todo_flags_finish */ +}; + +class pass_ipa_whole_program_visibility : public ipa_opt_pass_d +{ +public: + pass_ipa_whole_program_visibility (gcc::context *ctxt) + : ipa_opt_pass_d (pass_data_ipa_whole_program_visibility, ctxt, + NULL, /* generate_summary */ + NULL, /* write_summary */ + NULL, /* read_summary */ + NULL, /* write_optimization_summary */ + NULL, /* read_optimization_summary */ + NULL, /* stmt_fixup */ + 0, /* function_transform_todo_flags_start */ + NULL, /* function_transform */ + NULL) /* variable_transform */ + {} + + /* opt_pass methods: */ + + virtual bool gate (function *) + { + /* Do not re-run on ltrans stage. */ + return !flag_ltrans; + } + virtual unsigned int execute (function *) + { + return whole_program_function_and_variable_visibility (); + } + +}; // class pass_ipa_whole_program_visibility + +} // anon namespace + +ipa_opt_pass_d * +make_pass_ipa_whole_program_visibility (gcc::context *ctxt) +{ + return new pass_ipa_whole_program_visibility (ctxt); +} + +class pass_ipa_function_and_variable_visibility : public simple_ipa_opt_pass +{ +public: + pass_ipa_function_and_variable_visibility (gcc::context *ctxt) + : simple_ipa_opt_pass (pass_data_ipa_function_and_variable_visibility, + ctxt) + {} + + /* opt_pass methods: */ + virtual unsigned int execute (function *) + { + return function_and_variable_visibility (flag_whole_program && !flag_lto); + } + +}; // class pass_ipa_function_and_variable_visibility + +simple_ipa_opt_pass * +make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt) +{ + return new pass_ipa_function_and_variable_visibility (ctxt); +} diff --git a/gcc/ipa.c b/gcc/ipa.c index b0cc6d5887a..5850d281829 100644 --- a/gcc/ipa.c +++ b/gcc/ipa.c @@ -42,36 +42,6 @@ along with GCC; see the file COPYING3. If not see #include "gimple.h" #include "dbgcnt.h" -/* Return true when NODE can not be local. Worker for cgraph_local_node_p. */ - -static bool -cgraph_non_local_node_p_1 (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) -{ - /* FIXME: Aliases can be local, but i386 gets thunks wrong then. */ - return !(cgraph_only_called_directly_or_aliased_p (node) - && !ipa_ref_has_aliases_p (&node->ref_list) - && node->definition - && !DECL_EXTERNAL (node->decl) - && !node->externally_visible - && !node->used_from_other_partition - && !node->in_other_partition); -} - -/* Return true when function can be marked local. */ - -static bool -cgraph_local_node_p (struct cgraph_node *node) -{ - struct cgraph_node *n = cgraph_function_or_thunk_node (node, NULL); - - /* FIXME: thunks can be considered local, but we need prevent i386 - from attempting to change calling convention of them. */ - if (n->thunk.thunk_p) - return false; - return !cgraph_for_node_and_aliases (n, - cgraph_non_local_node_p_1, NULL, true); - -} /* Return true when NODE has ADDR reference. */ @@ -761,593 +731,6 @@ ipa_discover_readonly_nonaddressable_vars (void) fprintf (dump_file, "\n"); } -/* Return true when there is a reference to node and it is not vtable. */ -static bool -address_taken_from_non_vtable_p (symtab_node *node) -{ - int i; - struct ipa_ref *ref; - for (i = 0; ipa_ref_list_referring_iterate (&node->ref_list, - i, ref); i++) - if (ref->use == IPA_REF_ADDR) - { - varpool_node *node; - if (is_a <cgraph_node *> (ref->referring)) - return true; - node = ipa_ref_referring_varpool_node (ref); - if (!DECL_VIRTUAL_P (node->decl)) - return true; - } - return false; -} - -/* A helper for comdat_can_be_unshared_p. */ - -static bool -comdat_can_be_unshared_p_1 (symtab_node *node) -{ - if (!node->externally_visible) - return true; - /* When address is taken, we don't know if equality comparison won't - break eventually. Exception are virutal functions, C++ - constructors/destructors and vtables, where this is not possible by - language standard. */ - if (!DECL_VIRTUAL_P (node->decl) - && (TREE_CODE (node->decl) != FUNCTION_DECL - || (!DECL_CXX_CONSTRUCTOR_P (node->decl) - && !DECL_CXX_DESTRUCTOR_P (node->decl))) - && address_taken_from_non_vtable_p (node)) - return false; - - /* If the symbol is used in some weird way, better to not touch it. */ - if (node->force_output) - return false; - - /* Explicit instantiations needs to be output when possibly - used externally. */ - if (node->forced_by_abi - && TREE_PUBLIC (node->decl) - && (node->resolution != LDPR_PREVAILING_DEF_IRONLY - && !flag_whole_program)) - return false; - - /* Non-readonly and volatile variables can not be duplicated. */ - if (is_a <varpool_node *> (node) - && (!TREE_READONLY (node->decl) - || TREE_THIS_VOLATILE (node->decl))) - return false; - return true; -} - -/* COMDAT functions must be shared only if they have address taken, - otherwise we can produce our own private implementation with - -fwhole-program. - Return true when turning COMDAT functoin static can not lead to wrong - code when the resulting object links with a library defining same COMDAT. - - Virtual functions do have their addresses taken from the vtables, - but in C++ there is no way to compare their addresses for equality. */ - -static bool -comdat_can_be_unshared_p (symtab_node *node) -{ - if (!comdat_can_be_unshared_p_1 (node)) - return false; - if (node->same_comdat_group) - { - symtab_node *next; - - /* If more than one function is in the same COMDAT group, it must - be shared even if just one function in the comdat group has - address taken. */ - for (next = node->same_comdat_group; - next != node; next = next->same_comdat_group) - if (!comdat_can_be_unshared_p_1 (next)) - return false; - } - return true; -} - -/* Return true when function NODE should be considered externally visible. */ - -static bool -cgraph_externally_visible_p (struct cgraph_node *node, - bool whole_program) -{ - if (!node->definition) - return false; - if (!TREE_PUBLIC (node->decl) - || DECL_EXTERNAL (node->decl)) - return false; - - /* 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; - - /* If linker counts on us, we must preserve the function. */ - if (symtab_used_from_object_file_p (node)) - return true; - if (DECL_PRESERVE_P (node->decl)) - 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; - if (node->resolution == LDPR_PREVAILING_DEF_IRONLY) - return false; - /* 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 - implementing same COMDAT) */ - if ((in_lto_p || whole_program) - && DECL_COMDAT (node->decl) - && comdat_can_be_unshared_p (node)) - return false; - - /* When doing link time optimizations, hidden symbols become local. */ - if (in_lto_p - && (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN - || DECL_VISIBILITY (node->decl) == VISIBILITY_INTERNAL) - /* Be sure that node is defined in IR file, not in other object - file. In that case we don't set used_from_other_object_file. */ - && node->definition) - ; - else if (!whole_program) - return true; - - if (MAIN_NAME_P (DECL_NAME (node->decl))) - return true; - - return false; -} - -/* Return true when variable VNODE should be considered externally visible. */ - -bool -varpool_externally_visible_p (varpool_node *vnode) -{ - if (DECL_EXTERNAL (vnode->decl)) - return true; - - if (!TREE_PUBLIC (vnode->decl)) - return false; - - /* If linker counts on us, we must preserve the function. */ - if (symtab_used_from_object_file_p (vnode)) - return true; - - if (DECL_HARD_REGISTER (vnode->decl)) - 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. - - Even if the linker clams the symbol is unused, never bring internal - symbols that are declared by user as used or externally visible. - This is needed for i.e. references from asm statements. */ - if (symtab_used_from_object_file_p (vnode)) - return true; - if (vnode->resolution == LDPR_PREVAILING_DEF_IRONLY) - return false; - - /* As a special case, the COMDAT virtual tables can be unshared. - In LTO mode turn vtables into static variables. The variable is readonly, - so this does not enable more optimization, but referring static var - is faster for dynamic linking. Also this match logic hidding vtables - from LTO symbol tables. */ - if ((in_lto_p || flag_whole_program) - && DECL_COMDAT (vnode->decl) - && comdat_can_be_unshared_p (vnode)) - return false; - - /* When doing link time optimizations, hidden symbols become local. */ - if (in_lto_p - && (DECL_VISIBILITY (vnode->decl) == VISIBILITY_HIDDEN - || DECL_VISIBILITY (vnode->decl) == VISIBILITY_INTERNAL) - /* Be sure that node is defined in IR file, not in other object - file. In that case we don't set used_from_other_object_file. */ - && vnode->definition) - ; - else if (!flag_whole_program) - return true; - - /* Do not attempt to privatize COMDATS by default. - This would break linking with C++ libraries sharing - inline definitions. - - FIXME: We can do so for readonly vars with no address taken and - possibly also for vtables since no direct pointer comparsion is done. - It might be interesting to do so to reduce linking overhead. */ - if (DECL_COMDAT (vnode->decl) || DECL_WEAK (vnode->decl)) - return true; - return false; -} - -/* Return true if reference to NODE can be replaced by a local alias. - Local aliases save dynamic linking overhead and enable more optimizations. - */ - -bool -can_replace_by_local_alias (symtab_node *node) -{ - return (symtab_node_availability (node) > AVAIL_OVERWRITABLE - && !symtab_can_be_discarded (node)); -} - -/* In LTO we can remove COMDAT groups and weak symbols. - Either turn them into normal symbols or external symbol depending on - resolution info. */ - -static void -update_visibility_by_resolution_info (symtab_node * node) -{ - bool define; - - if (!node->externally_visible - || (!DECL_WEAK (node->decl) && !DECL_ONE_ONLY (node->decl)) - || node->resolution == LDPR_UNKNOWN) - return; - - define = (node->resolution == LDPR_PREVAILING_DEF_IRONLY - || node->resolution == LDPR_PREVAILING_DEF - || node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP); - - /* The linker decisions ought to agree in the whole group. */ - if (node->same_comdat_group) - for (symtab_node *next = node->same_comdat_group; - next != node; next = next->same_comdat_group) - gcc_assert (!node->externally_visible - || define == (next->resolution == LDPR_PREVAILING_DEF_IRONLY - || next->resolution == LDPR_PREVAILING_DEF - || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)); - - if (node->same_comdat_group) - for (symtab_node *next = node->same_comdat_group; - next != node; next = next->same_comdat_group) - { - next->set_comdat_group (NULL); - DECL_WEAK (next->decl) = false; - if (next->externally_visible - && !define) - DECL_EXTERNAL (next->decl) = true; - } - node->set_comdat_group (NULL); - DECL_WEAK (node->decl) = false; - if (!define) - DECL_EXTERNAL (node->decl) = true; - symtab_dissolve_same_comdat_group_list (node); -} - -/* Mark visibility of all functions. - - A local function is one whose calls can occur only in the current - compilation unit and all its calls are explicit, so we can change - its calling convention. We simply mark all static functions whose - address is not taken as local. - - We also change the TREE_PUBLIC flag of all declarations that are public - in language point of view but we want to overwrite this default - via visibilities for the backend point of view. */ - -static unsigned int -function_and_variable_visibility (bool whole_program) -{ - struct cgraph_node *node; - varpool_node *vnode; - - /* All aliases should be procssed at this point. */ - gcc_checking_assert (!alias_pairs || !alias_pairs->length ()); - - FOR_EACH_FUNCTION (node) - { - 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)) - { - DECL_STATIC_CONSTRUCTOR (node->decl) = 0; - 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 (DECL_EXTERNAL (node->decl) || !node->definition) - { - node->force_output = 0; - node->forced_by_abi = 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 necessary to keep the flag to make rest of C++ FE - happy. Clear the flag here to avoid confusion in middle-end. */ - if (DECL_COMDAT (node->decl) && !TREE_PUBLIC (node->decl)) - DECL_COMDAT (node->decl) = 0; - - /* For external decls stop tracking same_comdat_group. It doesn't matter - what comdat group they are in when they won't be emitted in this TU. */ - if (node->same_comdat_group && DECL_EXTERNAL (node->decl)) - { -#ifdef ENABLE_CHECKING - symtab_node *n; - - for (n = node->same_comdat_group; - n != node; - n = n->same_comdat_group) - /* If at least one of same comdat group functions is external, - all of them have to be, otherwise it is a front-end bug. */ - gcc_assert (DECL_EXTERNAL (n->decl)); -#endif - symtab_dissolve_same_comdat_group_list (node); - } - gcc_assert ((!DECL_WEAK (node->decl) - && !DECL_COMDAT (node->decl)) - || TREE_PUBLIC (node->decl) - || node->weakref - || DECL_EXTERNAL (node->decl)); - if (cgraph_externally_visible_p (node, whole_program)) - { - gcc_assert (!node->global.inlined_to); - node->externally_visible = true; - } - else - { - node->externally_visible = false; - node->forced_by_abi = false; - } - if (!node->externally_visible - && node->definition && !node->weakref - && !DECL_EXTERNAL (node->decl)) - { - gcc_assert (whole_program || in_lto_p - || !TREE_PUBLIC (node->decl)); - node->unique_name = ((node->resolution == LDPR_PREVAILING_DEF_IRONLY - || node->unique_name - || node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) - && TREE_PUBLIC (node->decl)); - node->resolution = LDPR_PREVAILING_DEF_IRONLY; - if (node->same_comdat_group && TREE_PUBLIC (node->decl)) - { - symtab_node *next = node; - - /* Set all members of comdat group local. */ - if (node->same_comdat_group) - for (next = node->same_comdat_group; - next != node; - next = next->same_comdat_group) - { - next->set_comdat_group (NULL); - symtab_make_decl_local (next->decl); - next->unique_name = ((next->resolution == LDPR_PREVAILING_DEF_IRONLY - || next->unique_name - || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) - && TREE_PUBLIC (next->decl)); - } - /* cgraph_externally_visible_p has already checked all other nodes - in the group and they will all be made local. We need to - dissolve the group at once so that the predicate does not - segfault though. */ - symtab_dissolve_same_comdat_group_list (node); - } - if (TREE_PUBLIC (node->decl)) - node->set_comdat_group (NULL); - symtab_make_decl_local (node->decl); - } - - if (node->thunk.thunk_p - && TREE_PUBLIC (node->decl)) - { - struct cgraph_node *decl_node = node; - - decl_node = cgraph_function_node (decl_node->callees->callee, NULL); - - /* Thunks have the same visibility as function they are attached to. - Make sure the C++ front end set this up properly. */ - if (DECL_ONE_ONLY (decl_node->decl)) - { - gcc_checking_assert (DECL_COMDAT (node->decl) - == DECL_COMDAT (decl_node->decl)); - gcc_checking_assert (symtab_in_same_comdat_p (node, decl_node)); - gcc_checking_assert (node->same_comdat_group); - } - node->forced_by_abi = decl_node->forced_by_abi; - if (DECL_EXTERNAL (decl_node->decl)) - DECL_EXTERNAL (node->decl) = 1; - } - - update_visibility_by_resolution_info (node); - } - FOR_EACH_DEFINED_FUNCTION (node) - { - node->local.local |= cgraph_local_node_p (node); - - /* If we know that function can not be overwritten by a different semantics - and moreover its section can not be discarded, replace all direct calls - by calls to an nonoverwritable alias. This make dynamic linking - cheaper and enable more optimization. - - TODO: We can also update virtual tables. */ - if (node->callers && can_replace_by_local_alias (node)) - { - struct cgraph_node *alias = cgraph (symtab_nonoverwritable_alias (node)); - - if (alias && alias != node) - { - while (node->callers) - { - struct cgraph_edge *e = node->callers; - - cgraph_redirect_edge_callee (e, alias); - if (gimple_has_body_p (e->caller->decl)) - { - push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl)); - cgraph_redirect_edge_call_stmt_to_callee (e); - pop_cfun (); - } - } - } - } - } - FOR_EACH_VARIABLE (vnode) - { - /* weak flag makes no sense on local variables. */ - gcc_assert (!DECL_WEAK (vnode->decl) - || vnode->weakref - || TREE_PUBLIC (vnode->decl) - || DECL_EXTERNAL (vnode->decl)); - /* In several cases declarations can not be common: - - - when declaration has initializer - - when it is in weak - - when it has specific section - - when it resides in non-generic address space. - - if declaration is local, it will get into .local common section - so common flag is not needed. Frontends still produce these in - certain cases, such as for: - - static int a __attribute__ ((common)) - - Canonicalize things here and clear the redundant flag. */ - if (DECL_COMMON (vnode->decl) - && (!(TREE_PUBLIC (vnode->decl) - || DECL_EXTERNAL (vnode->decl)) - || (DECL_INITIAL (vnode->decl) - && DECL_INITIAL (vnode->decl) != error_mark_node) - || DECL_WEAK (vnode->decl) - || DECL_SECTION_NAME (vnode->decl) != NULL - || ! (ADDR_SPACE_GENERIC_P - (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl)))))) - DECL_COMMON (vnode->decl) = 0; - } - FOR_EACH_DEFINED_VARIABLE (vnode) - { - if (!vnode->definition) - continue; - if (varpool_externally_visible_p (vnode)) - vnode->externally_visible = true; - else - { - vnode->externally_visible = false; - vnode->forced_by_abi = false; - } - if (!vnode->externally_visible - && !vnode->weakref) - { - gcc_assert (in_lto_p || whole_program || !TREE_PUBLIC (vnode->decl)); - vnode->unique_name = ((vnode->resolution == LDPR_PREVAILING_DEF_IRONLY - || vnode->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) - && TREE_PUBLIC (vnode->decl)); - if (vnode->same_comdat_group && TREE_PUBLIC (vnode->decl)) - { - symtab_node *next = vnode; - - /* Set all members of comdat group local. */ - if (vnode->same_comdat_group) - for (next = vnode->same_comdat_group; - next != vnode; - next = next->same_comdat_group) - { - next->set_comdat_group (NULL); - symtab_make_decl_local (next->decl); - next->unique_name = ((next->resolution == LDPR_PREVAILING_DEF_IRONLY - || next->unique_name - || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) - && TREE_PUBLIC (next->decl)); - } - symtab_dissolve_same_comdat_group_list (vnode); - } - if (TREE_PUBLIC (vnode->decl)) - vnode->set_comdat_group (NULL); - symtab_make_decl_local (vnode->decl); - vnode->resolution = LDPR_PREVAILING_DEF_IRONLY; - } - update_visibility_by_resolution_info (vnode); - } - - if (dump_file) - { - fprintf (dump_file, "\nMarking local functions:"); - FOR_EACH_DEFINED_FUNCTION (node) - if (node->local.local) - fprintf (dump_file, " %s", node->name ()); - fprintf (dump_file, "\n\n"); - fprintf (dump_file, "\nMarking externally visible functions:"); - FOR_EACH_DEFINED_FUNCTION (node) - if (node->externally_visible) - fprintf (dump_file, " %s", node->name ()); - fprintf (dump_file, "\n\n"); - fprintf (dump_file, "\nMarking externally visible variables:"); - FOR_EACH_DEFINED_VARIABLE (vnode) - if (vnode->externally_visible) - fprintf (dump_file, " %s", vnode->name ()); - fprintf (dump_file, "\n\n"); - } - cgraph_function_flags_ready = true; - return 0; -} - -/* Local function pass handling visibilities. This happens before LTO streaming - so in particular -fwhole-program should be ignored at this level. */ - -namespace { - -const pass_data pass_data_ipa_function_and_variable_visibility = -{ - SIMPLE_IPA_PASS, /* type */ - "visibility", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - true, /* has_execute */ - TV_CGRAPHOPT, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - ( TODO_remove_functions | TODO_dump_symtab ), /* todo_flags_finish */ -}; - -class pass_ipa_function_and_variable_visibility : public simple_ipa_opt_pass -{ -public: - pass_ipa_function_and_variable_visibility (gcc::context *ctxt) - : simple_ipa_opt_pass (pass_data_ipa_function_and_variable_visibility, - ctxt) - {} - - /* opt_pass methods: */ - virtual unsigned int execute (function *) - { - return function_and_variable_visibility (flag_whole_program && !flag_lto); - } - -}; // class pass_ipa_function_and_variable_visibility - -} // anon namespace - -simple_ipa_opt_pass * -make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt) -{ - return new pass_ipa_function_and_variable_visibility (ctxt); -} - /* Free inline summary. */ namespace { @@ -1390,71 +773,6 @@ make_pass_ipa_free_inline_summary (gcc::context *ctxt) return new pass_ipa_free_inline_summary (ctxt); } -/* Bring functionss local at LTO time with -fwhole-program. */ - -static unsigned int -whole_program_function_and_variable_visibility (void) -{ - function_and_variable_visibility (flag_whole_program); - if (optimize) - ipa_discover_readonly_nonaddressable_vars (); - return 0; -} - -namespace { - -const pass_data pass_data_ipa_whole_program_visibility = -{ - IPA_PASS, /* type */ - "whole-program", /* name */ - OPTGROUP_NONE, /* optinfo_flags */ - true, /* has_execute */ - TV_CGRAPHOPT, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - ( TODO_remove_functions | TODO_dump_symtab ), /* todo_flags_finish */ -}; - -class pass_ipa_whole_program_visibility : public ipa_opt_pass_d -{ -public: - pass_ipa_whole_program_visibility (gcc::context *ctxt) - : ipa_opt_pass_d (pass_data_ipa_whole_program_visibility, ctxt, - NULL, /* generate_summary */ - NULL, /* write_summary */ - NULL, /* read_summary */ - NULL, /* write_optimization_summary */ - NULL, /* read_optimization_summary */ - NULL, /* stmt_fixup */ - 0, /* function_transform_todo_flags_start */ - NULL, /* function_transform */ - NULL) /* variable_transform */ - {} - - /* opt_pass methods: */ - - virtual bool gate (function *) - { - /* Do not re-run on ltrans stage. */ - return !flag_ltrans; - } - virtual unsigned int execute (function *) - { - return whole_program_function_and_variable_visibility (); - } - -}; // class pass_ipa_whole_program_visibility - -} // anon namespace - -ipa_opt_pass_d * -make_pass_ipa_whole_program_visibility (gcc::context *ctxt) -{ - return new pass_ipa_whole_program_visibility (ctxt); -} - /* 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 |