123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846 |
- /* IPA visibility pass
- Copyright (C) 2003-2015 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 "hash-set.h"
- #include "machmode.h"
- #include "vec.h"
- #include "double-int.h"
- #include "input.h"
- #include "alias.h"
- #include "symtab.h"
- #include "wide-int.h"
- #include "inchash.h"
- #include "tree.h"
- #include "hash-map.h"
- #include "is-a.h"
- #include "plugin-api.h"
- #include "hard-reg-set.h"
- #include "input.h"
- #include "function.h"
- #include "ipa-ref.h"
- #include "cgraph.h"
- #include "tree-pass.h"
- #include "calls.h"
- #include "gimple-expr.h"
- #include "varasm.h"
- /* Return true when NODE can not be local. Worker for cgraph_local_node_p. */
- static bool
- non_local_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
- {
- return !(node->only_called_directly_or_aliased_p ()
- /* i386 would need update to output thunk with locak calling
- ocnvetions. */
- && !node->thunk.thunk_p
- && 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_node::local_p (void)
- {
- cgraph_node *n = ultimate_alias_target ();
- if (n->thunk.thunk_p)
- return n->callees->callee->local_p ();
- return !n->call_for_symbol_thunks_and_aliases (non_local_p,
- NULL, true);
-
- }
- /* 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;
- if (node->address_can_be_compared_p ())
- {
- struct ipa_ref *ref;
- for (unsigned int i = 0; node->iterate_referring (i, ref); i++)
- if (ref->address_matters_p ())
- 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 (node->used_from_object_file_p ())
- 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;
- if (node->instrumentation_clone
- && MAIN_NAME_P (DECL_NAME (node->orig_decl)))
- return true;
- return false;
- }
- /* Return true when variable should be considered externally visible. */
- bool
- varpool_node::externally_visible_p (void)
- {
- if (DECL_EXTERNAL (decl))
- return true;
- if (!TREE_PUBLIC (decl))
- return false;
- /* If linker counts on us, we must preserve the function. */
- if (used_from_object_file_p ())
- return true;
- /* Bringing TLS variables local may cause dynamic linker failures
- on limits of static TLS vars. */
- if (DECL_THREAD_LOCAL_P (decl)
- && (DECL_TLS_MODEL (decl) != TLS_MODEL_EMULATED
- && DECL_TLS_MODEL (decl) != TLS_MODEL_INITIAL_EXEC))
- return true;
- if (DECL_HARD_REGISTER (decl))
- return true;
- if (DECL_PRESERVE_P (decl))
- return true;
- if (lookup_attribute ("externally_visible",
- DECL_ATTRIBUTES (decl)))
- return true;
- if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
- && lookup_attribute ("dllexport",
- DECL_ATTRIBUTES (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 (used_from_object_file_p ())
- return true;
- if (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 (decl)
- && comdat_can_be_unshared_p (this))
- return false;
- /* When doing link time optimizations, hidden symbols become local. */
- if (in_lto_p
- && (DECL_VISIBILITY (decl) == VISIBILITY_HIDDEN
- || DECL_VISIBILITY (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. */
- && 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 (decl) || DECL_WEAK (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 (node->get_availability () > AVAIL_INTERPOSABLE
- && !decl_binds_to_current_def_p (node->decl)
- && !node->can_be_discarded_p ());
- }
- /* Return true if we can replace refernece to NODE by local alias
- within a virtual table. Generally we can replace function pointers
- and virtual table pointers. */
- bool
- can_replace_by_local_alias_in_vtable (symtab_node *node)
- {
- if (is_a <varpool_node *> (node)
- && !DECL_VIRTUAL_P (node->decl))
- return false;
- return can_replace_by_local_alias (node);
- }
- /* walk_tree callback that rewrites initializer references. */
- static tree
- update_vtable_references (tree *tp, int *walk_subtrees,
- void *data ATTRIBUTE_UNUSED)
- {
- if (TREE_CODE (*tp) == VAR_DECL
- || TREE_CODE (*tp) == FUNCTION_DECL)
- {
- if (can_replace_by_local_alias_in_vtable (symtab_node::get (*tp)))
- *tp = symtab_node::get (*tp)->noninterposable_alias ()->decl;
- *walk_subtrees = 0;
- }
- else if (IS_TYPE_OR_DECL_P (*tp))
- *walk_subtrees = 0;
- return NULL;
- }
- /* 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_UNDEF
- || 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)
- {
- if (!next->externally_visible)
- continue;
- bool same_def
- = define == (next->resolution == LDPR_PREVAILING_DEF_IRONLY
- || next->resolution == LDPR_PREVAILING_DEF
- || next->resolution == LDPR_UNDEF
- || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP);
- gcc_assert (in_lto_p || same_def);
- if (!same_def)
- return;
- }
- 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;
- node->dissolve_same_comdat_group_list ();
- }
- /* 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
- node->dissolve_same_comdat_group_list ();
- }
- 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);
- if (!next->alias)
- next->set_section (NULL);
- next->make_decl_local ();
- 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. */
- node->dissolve_same_comdat_group_list ();
- }
- if (TREE_PUBLIC (node->decl))
- node->set_comdat_group (NULL);
- if (DECL_COMDAT (node->decl) && !node->alias)
- node->set_section (NULL);
- node->make_decl_local ();
- }
- if (node->thunk.thunk_p
- && !node->thunk.add_pointer_bounds_args
- && TREE_PUBLIC (node->decl))
- {
- struct cgraph_node *decl_node = node;
- decl_node = decl_node->callees->callee->function_symbol ();
- /* 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 (node->in_same_comdat_group_p (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)
- {
- if (!node->local.local)
- node->local.local |= node->local_p ();
- /* 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 noninterposable 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))
- {
- cgraph_node *alias = dyn_cast<cgraph_node *>
- (node->noninterposable_alias ());
- if (alias && alias != node)
- {
- while (node->callers)
- {
- struct cgraph_edge *e = node->callers;
- e->redirect_callee (alias);
- if (gimple_has_body_p (e->caller->decl))
- {
- push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl));
- e->redirect_call_stmt_to_callee ();
- 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 (vnode->externally_visible_p ())
- vnode->externally_visible = true;
- else
- {
- vnode->externally_visible = false;
- vnode->forced_by_abi = false;
- }
- if (lookup_attribute ("no_reorder",
- DECL_ATTRIBUTES (vnode->decl)))
- vnode->no_reorder = 1;
- 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);
- if (!next->alias)
- next->set_section (NULL);
- next->make_decl_local ();
- next->unique_name = ((next->resolution == LDPR_PREVAILING_DEF_IRONLY
- || next->unique_name
- || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
- && TREE_PUBLIC (next->decl));
- }
- vnode->dissolve_same_comdat_group_list ();
- }
- if (TREE_PUBLIC (vnode->decl))
- vnode->set_comdat_group (NULL);
- if (DECL_COMDAT (vnode->decl) && !vnode->alias)
- vnode->set_section (NULL);
- vnode->make_decl_local ();
- vnode->resolution = LDPR_PREVAILING_DEF_IRONLY;
- }
- update_visibility_by_resolution_info (vnode);
- /* Update virtual tables to point to local aliases where possible. */
- if (DECL_VIRTUAL_P (vnode->decl)
- && !DECL_EXTERNAL (vnode->decl))
- {
- int i;
- struct ipa_ref *ref;
- bool found = false;
- /* See if there is something to update. */
- for (i = 0; vnode->iterate_referring (i, ref); i++)
- if (ref->use == IPA_REF_ADDR
- && can_replace_by_local_alias_in_vtable (ref->referred))
- {
- found = true;
- break;
- }
- if (found)
- {
- hash_set<tree> visited_nodes;
- vnode->get_constructor ();
- walk_tree (&DECL_INITIAL (vnode->decl),
- update_vtable_references, NULL, &visited_nodes);
- vnode->remove_all_references ();
- record_references_in_initializer (vnode->decl, false);
- }
- }
- }
- 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");
- }
- symtab->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 */
- 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 */
- 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);
- }
|