138fd1498Szrj /* Basic IPA optimizations and utilities.
238fd1498Szrj Copyright (C) 2003-2018 Free Software Foundation, Inc.
338fd1498Szrj
438fd1498Szrj This file is part of GCC.
538fd1498Szrj
638fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
738fd1498Szrj the terms of the GNU General Public License as published by the Free
838fd1498Szrj Software Foundation; either version 3, or (at your option) any later
938fd1498Szrj version.
1038fd1498Szrj
1138fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
1238fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
1338fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1438fd1498Szrj for more details.
1538fd1498Szrj
1638fd1498Szrj You should have received a copy of the GNU General Public License
1738fd1498Szrj along with GCC; see the file COPYING3. If not see
1838fd1498Szrj <http://www.gnu.org/licenses/>. */
1938fd1498Szrj
2038fd1498Szrj #include "config.h"
2138fd1498Szrj #include "system.h"
2238fd1498Szrj #include "coretypes.h"
2338fd1498Szrj #include "backend.h"
2438fd1498Szrj #include "target.h"
2538fd1498Szrj #include "tree.h"
2638fd1498Szrj #include "gimple.h"
2738fd1498Szrj #include "alloc-pool.h"
2838fd1498Szrj #include "tree-pass.h"
2938fd1498Szrj #include "stringpool.h"
3038fd1498Szrj #include "cgraph.h"
3138fd1498Szrj #include "gimplify.h"
3238fd1498Szrj #include "tree-iterator.h"
3338fd1498Szrj #include "ipa-utils.h"
3438fd1498Szrj #include "symbol-summary.h"
3538fd1498Szrj #include "tree-vrp.h"
3638fd1498Szrj #include "ipa-prop.h"
3738fd1498Szrj #include "ipa-fnsummary.h"
3838fd1498Szrj #include "dbgcnt.h"
3938fd1498Szrj #include "debug.h"
4038fd1498Szrj #include "stringpool.h"
4138fd1498Szrj #include "attribs.h"
4238fd1498Szrj
4338fd1498Szrj /* Return true when NODE has ADDR reference. */
4438fd1498Szrj
4538fd1498Szrj static bool
has_addr_references_p(struct cgraph_node * node,void *)4638fd1498Szrj has_addr_references_p (struct cgraph_node *node,
4738fd1498Szrj void *)
4838fd1498Szrj {
4938fd1498Szrj int i;
5038fd1498Szrj struct ipa_ref *ref = NULL;
5138fd1498Szrj
5238fd1498Szrj for (i = 0; node->iterate_referring (i, ref); i++)
5338fd1498Szrj if (ref->use == IPA_REF_ADDR)
5438fd1498Szrj return true;
5538fd1498Szrj return false;
5638fd1498Szrj }
5738fd1498Szrj
5838fd1498Szrj /* Return true when NODE can be target of an indirect call. */
5938fd1498Szrj
6038fd1498Szrj static bool
is_indirect_call_target_p(struct cgraph_node * node,void *)6138fd1498Szrj is_indirect_call_target_p (struct cgraph_node *node, void *)
6238fd1498Szrj {
6338fd1498Szrj return node->indirect_call_target;
6438fd1498Szrj }
6538fd1498Szrj
6638fd1498Szrj /* Look for all functions inlined to NODE and update their inlined_to pointers
6738fd1498Szrj to INLINED_TO. */
6838fd1498Szrj
6938fd1498Szrj static void
update_inlined_to_pointer(struct cgraph_node * node,struct cgraph_node * inlined_to)7038fd1498Szrj update_inlined_to_pointer (struct cgraph_node *node, struct cgraph_node *inlined_to)
7138fd1498Szrj {
7238fd1498Szrj struct cgraph_edge *e;
7338fd1498Szrj for (e = node->callees; e; e = e->next_callee)
7438fd1498Szrj if (e->callee->global.inlined_to)
7538fd1498Szrj {
7638fd1498Szrj e->callee->global.inlined_to = inlined_to;
7738fd1498Szrj update_inlined_to_pointer (e->callee, inlined_to);
7838fd1498Szrj }
7938fd1498Szrj }
8038fd1498Szrj
8138fd1498Szrj /* Add symtab NODE to queue starting at FIRST.
8238fd1498Szrj
8338fd1498Szrj The queue is linked via AUX pointers and terminated by pointer to 1.
8438fd1498Szrj We enqueue nodes at two occasions: when we find them reachable or when we find
8538fd1498Szrj their bodies needed for further clonning. In the second case we mark them
8638fd1498Szrj by pointer to 2 after processing so they are re-queue when they become
8738fd1498Szrj reachable. */
8838fd1498Szrj
8938fd1498Szrj static void
enqueue_node(symtab_node * node,symtab_node ** first,hash_set<symtab_node * > * reachable)9038fd1498Szrj enqueue_node (symtab_node *node, symtab_node **first,
9138fd1498Szrj hash_set<symtab_node *> *reachable)
9238fd1498Szrj {
9338fd1498Szrj /* Node is still in queue; do nothing. */
9438fd1498Szrj if (node->aux && node->aux != (void *) 2)
9538fd1498Szrj return;
9638fd1498Szrj /* Node was already processed as unreachable, re-enqueue
9738fd1498Szrj only if it became reachable now. */
9838fd1498Szrj if (node->aux == (void *)2 && !reachable->contains (node))
9938fd1498Szrj return;
10038fd1498Szrj node->aux = *first;
10138fd1498Szrj *first = node;
10238fd1498Szrj }
10338fd1498Szrj
10438fd1498Szrj /* Process references. */
10538fd1498Szrj
10638fd1498Szrj static void
process_references(symtab_node * snode,symtab_node ** first,bool before_inlining_p,hash_set<symtab_node * > * reachable)10738fd1498Szrj process_references (symtab_node *snode,
10838fd1498Szrj symtab_node **first,
10938fd1498Szrj bool before_inlining_p,
11038fd1498Szrj hash_set<symtab_node *> *reachable)
11138fd1498Szrj {
11238fd1498Szrj int i;
11338fd1498Szrj struct ipa_ref *ref = NULL;
11438fd1498Szrj for (i = 0; snode->iterate_reference (i, ref); i++)
11538fd1498Szrj {
11638fd1498Szrj symtab_node *node = ref->referred;
11738fd1498Szrj symtab_node *body = node->ultimate_alias_target ();
11838fd1498Szrj
11938fd1498Szrj if (node->definition && !node->in_other_partition
12038fd1498Szrj && ((!DECL_EXTERNAL (node->decl) || node->alias)
12138fd1498Szrj || (((before_inlining_p
12238fd1498Szrj && (TREE_CODE (node->decl) != FUNCTION_DECL
12338fd1498Szrj || (TREE_CODE (node->decl) == FUNCTION_DECL
12438fd1498Szrj && opt_for_fn (body->decl, optimize))
12538fd1498Szrj || (symtab->state < IPA_SSA
12638fd1498Szrj && lookup_attribute
12738fd1498Szrj ("always_inline",
12838fd1498Szrj DECL_ATTRIBUTES (body->decl))))))
12938fd1498Szrj /* We use variable constructors during late compilation for
13038fd1498Szrj constant folding. Keep references alive so partitioning
13138fd1498Szrj knows about potential references. */
13238fd1498Szrj || (VAR_P (node->decl)
13338fd1498Szrj && flag_wpa
13438fd1498Szrj && ctor_for_folding (node->decl)
13538fd1498Szrj != error_mark_node))))
13638fd1498Szrj {
13738fd1498Szrj /* Be sure that we will not optimize out alias target
13838fd1498Szrj body. */
13938fd1498Szrj if (DECL_EXTERNAL (node->decl)
14038fd1498Szrj && node->alias
14138fd1498Szrj && before_inlining_p)
14238fd1498Szrj reachable->add (body);
14338fd1498Szrj reachable->add (node);
14438fd1498Szrj }
14538fd1498Szrj enqueue_node (node, first, reachable);
14638fd1498Szrj }
14738fd1498Szrj }
14838fd1498Szrj
14938fd1498Szrj /* EDGE is an polymorphic call. If BEFORE_INLINING_P is set, mark
15038fd1498Szrj all its potential targets as reachable to permit later inlining if
15138fd1498Szrj devirtualization happens. After inlining still keep their declarations
15238fd1498Szrj around, so we can devirtualize to a direct call.
15338fd1498Szrj
15438fd1498Szrj Also try to make trivial devirutalization when no or only one target is
15538fd1498Szrj possible. */
15638fd1498Szrj
15738fd1498Szrj static void
walk_polymorphic_call_targets(hash_set<void * > * reachable_call_targets,struct cgraph_edge * edge,symtab_node ** first,hash_set<symtab_node * > * reachable,bool before_inlining_p)15838fd1498Szrj walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
15938fd1498Szrj struct cgraph_edge *edge,
16038fd1498Szrj symtab_node **first,
16138fd1498Szrj hash_set<symtab_node *> *reachable,
16238fd1498Szrj bool before_inlining_p)
16338fd1498Szrj {
16438fd1498Szrj unsigned int i;
16538fd1498Szrj void *cache_token;
16638fd1498Szrj bool final;
16738fd1498Szrj vec <cgraph_node *>targets
16838fd1498Szrj = possible_polymorphic_call_targets
16938fd1498Szrj (edge, &final, &cache_token);
17038fd1498Szrj
17138fd1498Szrj if (!reachable_call_targets->add (cache_token))
17238fd1498Szrj {
17338fd1498Szrj for (i = 0; i < targets.length (); i++)
17438fd1498Szrj {
17538fd1498Szrj struct cgraph_node *n = targets[i];
17638fd1498Szrj
17738fd1498Szrj /* Do not bother to mark virtual methods in anonymous namespace;
17838fd1498Szrj either we will find use of virtual table defining it, or it is
17938fd1498Szrj unused. */
18038fd1498Szrj if (TREE_CODE (TREE_TYPE (n->decl)) == METHOD_TYPE
18138fd1498Szrj && type_in_anonymous_namespace_p
18238fd1498Szrj (TYPE_METHOD_BASETYPE (TREE_TYPE (n->decl))))
18338fd1498Szrj continue;
18438fd1498Szrj
18538fd1498Szrj n->indirect_call_target = true;
18638fd1498Szrj symtab_node *body = n->function_symbol ();
18738fd1498Szrj
18838fd1498Szrj /* Prior inlining, keep alive bodies of possible targets for
18938fd1498Szrj devirtualization. */
19038fd1498Szrj if (n->definition
19138fd1498Szrj && (before_inlining_p
19238fd1498Szrj && opt_for_fn (body->decl, optimize)
19338fd1498Szrj && opt_for_fn (body->decl, flag_devirtualize)))
19438fd1498Szrj {
19538fd1498Szrj /* Be sure that we will not optimize out alias target
19638fd1498Szrj body. */
19738fd1498Szrj if (DECL_EXTERNAL (n->decl)
19838fd1498Szrj && n->alias
19938fd1498Szrj && before_inlining_p)
20038fd1498Szrj reachable->add (body);
20138fd1498Szrj reachable->add (n);
20238fd1498Szrj }
20338fd1498Szrj /* Even after inlining we want to keep the possible targets in the
20438fd1498Szrj boundary, so late passes can still produce direct call even if
20538fd1498Szrj the chance for inlining is lost. */
20638fd1498Szrj enqueue_node (n, first, reachable);
20738fd1498Szrj }
20838fd1498Szrj }
20938fd1498Szrj
21038fd1498Szrj /* Very trivial devirtualization; when the type is
21138fd1498Szrj final or anonymous (so we know all its derivation)
21238fd1498Szrj and there is only one possible virtual call target,
21338fd1498Szrj make the edge direct. */
21438fd1498Szrj if (final)
21538fd1498Szrj {
21638fd1498Szrj if (targets.length () <= 1 && dbg_cnt (devirt))
21738fd1498Szrj {
21838fd1498Szrj cgraph_node *target, *node = edge->caller;
21938fd1498Szrj if (targets.length () == 1)
22038fd1498Szrj target = targets[0];
22138fd1498Szrj else
22238fd1498Szrj target = cgraph_node::get_create
22338fd1498Szrj (builtin_decl_implicit (BUILT_IN_UNREACHABLE));
22438fd1498Szrj
22538fd1498Szrj if (dump_enabled_p ())
22638fd1498Szrj {
22738fd1498Szrj location_t locus;
22838fd1498Szrj if (edge->call_stmt)
22938fd1498Szrj locus = gimple_location (edge->call_stmt);
23038fd1498Szrj else
23138fd1498Szrj locus = UNKNOWN_LOCATION;
23238fd1498Szrj dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, locus,
23338fd1498Szrj "devirtualizing call in %s to %s\n",
23438fd1498Szrj edge->caller->dump_name (),
23538fd1498Szrj target->dump_name ());
23638fd1498Szrj }
23738fd1498Szrj edge = edge->make_direct (target);
23838fd1498Szrj if (ipa_fn_summaries)
23938fd1498Szrj ipa_update_overall_fn_summary (node);
24038fd1498Szrj else if (edge->call_stmt)
24138fd1498Szrj {
24238fd1498Szrj edge->redirect_call_stmt_to_callee ();
24338fd1498Szrj
24438fd1498Szrj /* Call to __builtin_unreachable shouldn't be instrumented. */
24538fd1498Szrj if (!targets.length ())
24638fd1498Szrj gimple_call_set_with_bounds (edge->call_stmt, false);
24738fd1498Szrj }
24838fd1498Szrj }
24938fd1498Szrj }
25038fd1498Szrj }
25138fd1498Szrj
25238fd1498Szrj /* Perform reachability analysis and reclaim all unreachable nodes.
25338fd1498Szrj
25438fd1498Szrj The algorithm is basically mark&sweep but with some extra refinements:
25538fd1498Szrj
25638fd1498Szrj - reachable extern inline functions needs special handling; the bodies needs
25738fd1498Szrj to stay in memory until inlining in hope that they will be inlined.
25838fd1498Szrj After inlining we release their bodies and turn them into unanalyzed
25938fd1498Szrj nodes even when they are reachable.
26038fd1498Szrj
26138fd1498Szrj - virtual functions are kept in callgraph even if they seem unreachable in
26238fd1498Szrj hope calls to them will be devirtualized.
26338fd1498Szrj
26438fd1498Szrj Again we remove them after inlining. In late optimization some
26538fd1498Szrj devirtualization may happen, but it is not important since we won't inline
26638fd1498Szrj the call. In theory early opts and IPA should work out all important cases.
26738fd1498Szrj
26838fd1498Szrj - virtual clones needs bodies of their origins for later materialization;
26938fd1498Szrj this means that we want to keep the body even if the origin is unreachable
27038fd1498Szrj otherwise. To avoid origin from sitting in the callgraph and being
27138fd1498Szrj walked by IPA passes, we turn them into unanalyzed nodes with body
27238fd1498Szrj defined.
27338fd1498Szrj
27438fd1498Szrj We maintain set of function declaration where body needs to stay in
27538fd1498Szrj body_needed_for_clonning
27638fd1498Szrj
27738fd1498Szrj Inline clones represent special case: their declaration match the
27838fd1498Szrj declaration of origin and cgraph_remove_node already knows how to
27938fd1498Szrj reshape callgraph and preserve body when offline copy of function or
28038fd1498Szrj inline clone is being removed.
28138fd1498Szrj
28238fd1498Szrj - C++ virtual tables keyed to other unit are represented as DECL_EXTERNAL
28338fd1498Szrj variables with DECL_INITIAL set. We finalize these and keep reachable
28438fd1498Szrj ones around for constant folding purposes. After inlining we however
28538fd1498Szrj stop walking their references to let everything static referneced by them
28638fd1498Szrj to be removed when it is otherwise unreachable.
28738fd1498Szrj
28838fd1498Szrj We maintain queue of both reachable symbols (i.e. defined symbols that needs
28938fd1498Szrj to stay) and symbols that are in boundary (i.e. external symbols referenced
29038fd1498Szrj by reachable symbols or origins of clones). The queue is represented
29138fd1498Szrj as linked list by AUX pointer terminated by 1.
29238fd1498Szrj
29338fd1498Szrj At the end we keep all reachable symbols. For symbols in boundary we always
29438fd1498Szrj turn definition into a declaration, but we may keep function body around
29538fd1498Szrj based on body_needed_for_clonning
29638fd1498Szrj
29738fd1498Szrj All symbols that enter the queue have AUX pointer non-zero and are in the
29838fd1498Szrj boundary. Pointer set REACHABLE is used to track reachable symbols.
29938fd1498Szrj
30038fd1498Szrj Every symbol can be visited twice - once as part of boundary and once
30138fd1498Szrj as real reachable symbol. enqueue_node needs to decide whether the
30238fd1498Szrj node needs to be re-queued for second processing. For this purpose
30338fd1498Szrj we set AUX pointer of processed symbols in the boundary to constant 2. */
30438fd1498Szrj
30538fd1498Szrj bool
remove_unreachable_nodes(FILE * file)30638fd1498Szrj symbol_table::remove_unreachable_nodes (FILE *file)
30738fd1498Szrj {
30838fd1498Szrj symtab_node *first = (symtab_node *) (void *) 1;
30938fd1498Szrj struct cgraph_node *node, *next;
31038fd1498Szrj varpool_node *vnode, *vnext;
31138fd1498Szrj bool changed = false;
31238fd1498Szrj hash_set<symtab_node *> reachable;
31338fd1498Szrj hash_set<tree> body_needed_for_clonning;
31438fd1498Szrj hash_set<void *> reachable_call_targets;
31538fd1498Szrj bool before_inlining_p = symtab->state < (!optimize && !in_lto_p ? IPA_SSA
31638fd1498Szrj : IPA_SSA_AFTER_INLINING);
31738fd1498Szrj
31838fd1498Szrj timevar_push (TV_IPA_UNREACHABLE);
31938fd1498Szrj build_type_inheritance_graph ();
32038fd1498Szrj if (file)
32138fd1498Szrj fprintf (file, "\nReclaiming functions:");
32238fd1498Szrj if (flag_checking)
32338fd1498Szrj {
32438fd1498Szrj FOR_EACH_FUNCTION (node)
32538fd1498Szrj gcc_assert (!node->aux);
32638fd1498Szrj FOR_EACH_VARIABLE (vnode)
32738fd1498Szrj gcc_assert (!vnode->aux);
32838fd1498Szrj }
32938fd1498Szrj /* Mark functions whose bodies are obviously needed.
33038fd1498Szrj This is mostly when they can be referenced externally. Inline clones
33138fd1498Szrj are special since their declarations are shared with master clone and thus
33238fd1498Szrj cgraph_can_remove_if_no_direct_calls_and_refs_p should not be called on them. */
33338fd1498Szrj FOR_EACH_FUNCTION (node)
33438fd1498Szrj {
33538fd1498Szrj node->used_as_abstract_origin = false;
33638fd1498Szrj node->indirect_call_target = false;
33738fd1498Szrj if (node->definition
33838fd1498Szrj && !node->global.inlined_to
33938fd1498Szrj && !node->in_other_partition
34038fd1498Szrj && !node->can_remove_if_no_direct_calls_and_refs_p ())
34138fd1498Szrj {
34238fd1498Szrj gcc_assert (!node->global.inlined_to);
34338fd1498Szrj reachable.add (node);
34438fd1498Szrj enqueue_node (node, &first, &reachable);
34538fd1498Szrj }
34638fd1498Szrj else
34738fd1498Szrj gcc_assert (!node->aux);
34838fd1498Szrj }
34938fd1498Szrj
35038fd1498Szrj /* Mark variables that are obviously needed. */
35138fd1498Szrj FOR_EACH_DEFINED_VARIABLE (vnode)
35238fd1498Szrj if (!vnode->can_remove_if_no_refs_p()
35338fd1498Szrj && !vnode->in_other_partition)
35438fd1498Szrj {
35538fd1498Szrj reachable.add (vnode);
35638fd1498Szrj enqueue_node (vnode, &first, &reachable);
35738fd1498Szrj }
35838fd1498Szrj
35938fd1498Szrj /* Perform reachability analysis. */
36038fd1498Szrj while (first != (symtab_node *) (void *) 1)
36138fd1498Szrj {
36238fd1498Szrj bool in_boundary_p = !reachable.contains (first);
36338fd1498Szrj symtab_node *node = first;
36438fd1498Szrj
36538fd1498Szrj first = (symtab_node *)first->aux;
36638fd1498Szrj
36738fd1498Szrj /* If we are processing symbol in boundary, mark its AUX pointer for
36838fd1498Szrj possible later re-processing in enqueue_node. */
36938fd1498Szrj if (in_boundary_p)
37038fd1498Szrj {
37138fd1498Szrj node->aux = (void *)2;
37238fd1498Szrj if (node->alias && node->analyzed)
37338fd1498Szrj enqueue_node (node->get_alias_target (), &first, &reachable);
37438fd1498Szrj }
37538fd1498Szrj else
37638fd1498Szrj {
37738fd1498Szrj if (TREE_CODE (node->decl) == FUNCTION_DECL
37838fd1498Szrj && DECL_ABSTRACT_ORIGIN (node->decl))
37938fd1498Szrj {
38038fd1498Szrj struct cgraph_node *origin_node
38138fd1498Szrj = cgraph_node::get (DECL_ABSTRACT_ORIGIN (node->decl));
38238fd1498Szrj if (origin_node && !origin_node->used_as_abstract_origin)
38338fd1498Szrj {
38438fd1498Szrj origin_node->used_as_abstract_origin = true;
38538fd1498Szrj gcc_assert (!origin_node->prev_sibling_clone);
38638fd1498Szrj gcc_assert (!origin_node->next_sibling_clone);
38738fd1498Szrj for (cgraph_node *n = origin_node->clones; n;
38838fd1498Szrj n = n->next_sibling_clone)
38938fd1498Szrj if (n->decl == DECL_ABSTRACT_ORIGIN (node->decl))
39038fd1498Szrj n->used_as_abstract_origin = true;
39138fd1498Szrj }
39238fd1498Szrj }
39338fd1498Szrj /* If any symbol in a comdat group is reachable, force
39438fd1498Szrj all externally visible symbols in the same comdat
39538fd1498Szrj group to be reachable as well. Comdat-local symbols
39638fd1498Szrj can be discarded if all uses were inlined. */
39738fd1498Szrj if (node->same_comdat_group)
39838fd1498Szrj {
39938fd1498Szrj symtab_node *next;
40038fd1498Szrj for (next = node->same_comdat_group;
40138fd1498Szrj next != node;
40238fd1498Szrj next = next->same_comdat_group)
40338fd1498Szrj if (!next->comdat_local_p ()
40438fd1498Szrj && !reachable.add (next))
40538fd1498Szrj enqueue_node (next, &first, &reachable);
40638fd1498Szrj }
40738fd1498Szrj /* Mark references as reachable. */
40838fd1498Szrj process_references (node, &first, before_inlining_p, &reachable);
40938fd1498Szrj }
41038fd1498Szrj
41138fd1498Szrj if (cgraph_node *cnode = dyn_cast <cgraph_node *> (node))
41238fd1498Szrj {
41338fd1498Szrj /* Mark the callees reachable unless they are direct calls to extern
41438fd1498Szrj inline functions we decided to not inline. */
41538fd1498Szrj if (!in_boundary_p)
41638fd1498Szrj {
41738fd1498Szrj struct cgraph_edge *e;
41838fd1498Szrj /* Keep alive possible targets for devirtualization. */
41938fd1498Szrj if (opt_for_fn (cnode->decl, optimize)
42038fd1498Szrj && opt_for_fn (cnode->decl, flag_devirtualize))
42138fd1498Szrj {
42238fd1498Szrj struct cgraph_edge *next;
42338fd1498Szrj for (e = cnode->indirect_calls; e; e = next)
42438fd1498Szrj {
42538fd1498Szrj next = e->next_callee;
42638fd1498Szrj if (e->indirect_info->polymorphic)
42738fd1498Szrj walk_polymorphic_call_targets (&reachable_call_targets,
42838fd1498Szrj e, &first, &reachable,
42938fd1498Szrj before_inlining_p);
43038fd1498Szrj }
43138fd1498Szrj }
43238fd1498Szrj for (e = cnode->callees; e; e = e->next_callee)
43338fd1498Szrj {
43438fd1498Szrj symtab_node *body = e->callee->function_symbol ();
43538fd1498Szrj if (e->callee->definition
43638fd1498Szrj && !e->callee->in_other_partition
43738fd1498Szrj && (!e->inline_failed
43838fd1498Szrj || !DECL_EXTERNAL (e->callee->decl)
43938fd1498Szrj || e->callee->alias
44038fd1498Szrj || (before_inlining_p
44138fd1498Szrj && (opt_for_fn (body->decl, optimize)
44238fd1498Szrj || (symtab->state < IPA_SSA
44338fd1498Szrj && lookup_attribute
44438fd1498Szrj ("always_inline",
44538fd1498Szrj DECL_ATTRIBUTES (body->decl)))))))
44638fd1498Szrj {
44738fd1498Szrj /* Be sure that we will not optimize out alias target
44838fd1498Szrj body. */
44938fd1498Szrj if (DECL_EXTERNAL (e->callee->decl)
45038fd1498Szrj && e->callee->alias
45138fd1498Szrj && before_inlining_p)
45238fd1498Szrj reachable.add (body);
45338fd1498Szrj reachable.add (e->callee);
45438fd1498Szrj }
45538fd1498Szrj enqueue_node (e->callee, &first, &reachable);
45638fd1498Szrj }
45738fd1498Szrj
45838fd1498Szrj /* When inline clone exists, mark body to be preserved so when removing
45938fd1498Szrj offline copy of the function we don't kill it. */
46038fd1498Szrj if (cnode->global.inlined_to)
46138fd1498Szrj body_needed_for_clonning.add (cnode->decl);
46238fd1498Szrj
46338fd1498Szrj /* For instrumentation clones we always need original
46438fd1498Szrj function node for proper LTO privatization. */
46538fd1498Szrj if (cnode->instrumentation_clone
46638fd1498Szrj && cnode->definition)
46738fd1498Szrj {
46838fd1498Szrj gcc_assert (cnode->instrumented_version || in_lto_p);
46938fd1498Szrj if (cnode->instrumented_version)
47038fd1498Szrj {
47138fd1498Szrj enqueue_node (cnode->instrumented_version, &first,
47238fd1498Szrj &reachable);
47338fd1498Szrj reachable.add (cnode->instrumented_version);
47438fd1498Szrj }
47538fd1498Szrj }
47638fd1498Szrj
47738fd1498Szrj /* For non-inline clones, force their origins to the boundary and ensure
47838fd1498Szrj that body is not removed. */
47938fd1498Szrj while (cnode->clone_of)
48038fd1498Szrj {
48138fd1498Szrj bool noninline = cnode->clone_of->decl != cnode->decl;
48238fd1498Szrj cnode = cnode->clone_of;
48338fd1498Szrj if (noninline)
48438fd1498Szrj {
48538fd1498Szrj body_needed_for_clonning.add (cnode->decl);
48638fd1498Szrj enqueue_node (cnode, &first, &reachable);
48738fd1498Szrj }
48838fd1498Szrj }
48938fd1498Szrj
49038fd1498Szrj }
49138fd1498Szrj else if (cnode->thunk.thunk_p)
49238fd1498Szrj enqueue_node (cnode->callees->callee, &first, &reachable);
49338fd1498Szrj
49438fd1498Szrj /* If any reachable function has simd clones, mark them as
49538fd1498Szrj reachable as well. */
49638fd1498Szrj if (cnode->simd_clones)
49738fd1498Szrj {
49838fd1498Szrj cgraph_node *next;
49938fd1498Szrj for (next = cnode->simd_clones;
50038fd1498Szrj next;
50138fd1498Szrj next = next->simdclone->next_clone)
50238fd1498Szrj if (in_boundary_p
50338fd1498Szrj || !reachable.add (next))
50438fd1498Szrj enqueue_node (next, &first, &reachable);
50538fd1498Szrj }
50638fd1498Szrj }
50738fd1498Szrj /* When we see constructor of external variable, keep referred nodes in the
50838fd1498Szrj boundary. This will also hold initializers of the external vars NODE
50938fd1498Szrj refers to. */
51038fd1498Szrj varpool_node *vnode = dyn_cast <varpool_node *> (node);
51138fd1498Szrj if (vnode
51238fd1498Szrj && DECL_EXTERNAL (node->decl)
51338fd1498Szrj && !vnode->alias
51438fd1498Szrj && in_boundary_p)
51538fd1498Szrj {
51638fd1498Szrj struct ipa_ref *ref = NULL;
51738fd1498Szrj for (int i = 0; node->iterate_reference (i, ref); i++)
51838fd1498Szrj enqueue_node (ref->referred, &first, &reachable);
51938fd1498Szrj }
52038fd1498Szrj }
52138fd1498Szrj
52238fd1498Szrj /* Remove unreachable functions. */
52338fd1498Szrj for (node = first_function (); node; node = next)
52438fd1498Szrj {
52538fd1498Szrj next = next_function (node);
52638fd1498Szrj
52738fd1498Szrj /* If node is not needed at all, remove it. */
52838fd1498Szrj if (!node->aux)
52938fd1498Szrj {
53038fd1498Szrj if (file)
53138fd1498Szrj fprintf (file, " %s", node->dump_name ());
53238fd1498Szrj node->remove ();
53338fd1498Szrj changed = true;
53438fd1498Szrj }
53538fd1498Szrj /* If node is unreachable, remove its body. */
53638fd1498Szrj else if (!reachable.contains (node))
53738fd1498Szrj {
53838fd1498Szrj /* We keep definitions of thunks and aliases in the boundary so
53938fd1498Szrj we can walk to the ultimate alias targets and function symbols
54038fd1498Szrj reliably. */
54138fd1498Szrj if (node->alias || node->thunk.thunk_p)
54238fd1498Szrj ;
54338fd1498Szrj else if (!body_needed_for_clonning.contains (node->decl)
54438fd1498Szrj && !node->alias && !node->thunk.thunk_p)
54538fd1498Szrj node->release_body ();
54638fd1498Szrj else if (!node->clone_of)
54738fd1498Szrj gcc_assert (in_lto_p || DECL_RESULT (node->decl));
54838fd1498Szrj if (node->definition && !node->alias && !node->thunk.thunk_p)
54938fd1498Szrj {
55038fd1498Szrj if (file)
55138fd1498Szrj fprintf (file, " %s", node->dump_name ());
55238fd1498Szrj node->body_removed = true;
55338fd1498Szrj node->analyzed = false;
55438fd1498Szrj node->definition = false;
55538fd1498Szrj node->cpp_implicit_alias = false;
55638fd1498Szrj node->alias = false;
55738fd1498Szrj node->transparent_alias = false;
55838fd1498Szrj node->thunk.thunk_p = false;
55938fd1498Szrj node->weakref = false;
56038fd1498Szrj /* After early inlining we drop always_inline attributes on
56138fd1498Szrj bodies of functions that are still referenced (have their
56238fd1498Szrj address taken). */
56338fd1498Szrj DECL_ATTRIBUTES (node->decl)
56438fd1498Szrj = remove_attribute ("always_inline",
56538fd1498Szrj DECL_ATTRIBUTES (node->decl));
56638fd1498Szrj if (!node->in_other_partition)
56738fd1498Szrj node->local.local = false;
56838fd1498Szrj node->remove_callees ();
56938fd1498Szrj node->remove_all_references ();
57038fd1498Szrj changed = true;
57138fd1498Szrj if (node->thunk.thunk_p
57238fd1498Szrj && node->thunk.add_pointer_bounds_args)
57338fd1498Szrj {
57438fd1498Szrj node->thunk.thunk_p = false;
57538fd1498Szrj node->thunk.add_pointer_bounds_args = false;
57638fd1498Szrj }
57738fd1498Szrj }
57838fd1498Szrj }
57938fd1498Szrj else
58038fd1498Szrj gcc_assert (node->clone_of || !node->has_gimple_body_p ()
58138fd1498Szrj || in_lto_p || DECL_RESULT (node->decl));
58238fd1498Szrj }
58338fd1498Szrj
58438fd1498Szrj /* Inline clones might be kept around so their materializing allows further
58538fd1498Szrj cloning. If the function the clone is inlined into is removed, we need
58638fd1498Szrj to turn it into normal cone. */
58738fd1498Szrj FOR_EACH_FUNCTION (node)
58838fd1498Szrj {
58938fd1498Szrj if (node->global.inlined_to
59038fd1498Szrj && !node->callers)
59138fd1498Szrj {
59238fd1498Szrj gcc_assert (node->clones);
59338fd1498Szrj node->global.inlined_to = NULL;
59438fd1498Szrj update_inlined_to_pointer (node, node);
59538fd1498Szrj }
59638fd1498Szrj node->aux = NULL;
59738fd1498Szrj }
59838fd1498Szrj
59938fd1498Szrj /* Remove unreachable variables. */
60038fd1498Szrj if (file)
60138fd1498Szrj fprintf (file, "\nReclaiming variables:");
60238fd1498Szrj for (vnode = first_variable (); vnode; vnode = vnext)
60338fd1498Szrj {
60438fd1498Szrj vnext = next_variable (vnode);
60538fd1498Szrj if (!vnode->aux
60638fd1498Szrj /* For can_refer_decl_in_current_unit_p we want to track for
60738fd1498Szrj all external variables if they are defined in other partition
60838fd1498Szrj or not. */
60938fd1498Szrj && (!flag_ltrans || !DECL_EXTERNAL (vnode->decl)))
61038fd1498Szrj {
61138fd1498Szrj struct ipa_ref *ref = NULL;
61238fd1498Szrj
61338fd1498Szrj /* First remove the aliases, so varpool::remove can possibly lookup
61438fd1498Szrj the constructor and save it for future use. */
61538fd1498Szrj while (vnode->iterate_direct_aliases (0, ref))
61638fd1498Szrj {
61738fd1498Szrj if (file)
61838fd1498Szrj fprintf (file, " %s", ref->referred->dump_name ());
61938fd1498Szrj ref->referring->remove ();
62038fd1498Szrj }
62138fd1498Szrj if (file)
62238fd1498Szrj fprintf (file, " %s", vnode->dump_name ());
62338fd1498Szrj vnext = next_variable (vnode);
62438fd1498Szrj /* Signal removal to the debug machinery. */
62538fd1498Szrj if (! flag_wpa)
62638fd1498Szrj {
62738fd1498Szrj vnode->definition = false;
62838fd1498Szrj (*debug_hooks->late_global_decl) (vnode->decl);
62938fd1498Szrj }
63038fd1498Szrj vnode->remove ();
63138fd1498Szrj changed = true;
63238fd1498Szrj }
63338fd1498Szrj else if (!reachable.contains (vnode) && !vnode->alias)
63438fd1498Szrj {
63538fd1498Szrj tree init;
63638fd1498Szrj if (vnode->definition)
63738fd1498Szrj {
63838fd1498Szrj if (file)
63938fd1498Szrj fprintf (file, " %s", vnode->name ());
64038fd1498Szrj changed = true;
64138fd1498Szrj }
64238fd1498Szrj /* Keep body if it may be useful for constant folding. */
64338fd1498Szrj if ((init = ctor_for_folding (vnode->decl)) == error_mark_node
64438fd1498Szrj && !POINTER_BOUNDS_P (vnode->decl))
64538fd1498Szrj vnode->remove_initializer ();
64638fd1498Szrj else
64738fd1498Szrj DECL_INITIAL (vnode->decl) = init;
64838fd1498Szrj vnode->body_removed = true;
64938fd1498Szrj vnode->definition = false;
65038fd1498Szrj vnode->analyzed = false;
65138fd1498Szrj vnode->aux = NULL;
65238fd1498Szrj
65338fd1498Szrj vnode->remove_from_same_comdat_group ();
65438fd1498Szrj
65538fd1498Szrj vnode->remove_all_references ();
65638fd1498Szrj }
65738fd1498Szrj else
65838fd1498Szrj vnode->aux = NULL;
65938fd1498Szrj }
66038fd1498Szrj
66138fd1498Szrj /* Now update address_taken flags and try to promote functions to be local. */
66238fd1498Szrj if (file)
66338fd1498Szrj fprintf (file, "\nClearing address taken flags:");
66438fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
66538fd1498Szrj if (node->address_taken
66638fd1498Szrj && !node->used_from_other_partition)
66738fd1498Szrj {
66838fd1498Szrj if (!node->call_for_symbol_and_aliases
66938fd1498Szrj (has_addr_references_p, NULL, true)
67038fd1498Szrj && (!node->instrumentation_clone
67138fd1498Szrj || !node->instrumented_version
67238fd1498Szrj || !node->instrumented_version->address_taken))
67338fd1498Szrj {
67438fd1498Szrj if (file)
67538fd1498Szrj fprintf (file, " %s", node->name ());
67638fd1498Szrj node->address_taken = false;
67738fd1498Szrj changed = true;
67838fd1498Szrj if (node->local_p ()
67938fd1498Szrj /* Virtual functions may be kept in cgraph just because
68038fd1498Szrj of possible later devirtualization. Do not mark them as
68138fd1498Szrj local too early so we won't optimize them out before
68238fd1498Szrj we are done with polymorphic call analysis. */
68338fd1498Szrj && (!before_inlining_p
68438fd1498Szrj || !node->call_for_symbol_and_aliases
68538fd1498Szrj (is_indirect_call_target_p, NULL, true)))
68638fd1498Szrj {
68738fd1498Szrj node->local.local = true;
68838fd1498Szrj if (file)
68938fd1498Szrj fprintf (file, " (local)");
69038fd1498Szrj }
69138fd1498Szrj }
69238fd1498Szrj }
69338fd1498Szrj if (file)
69438fd1498Szrj fprintf (file, "\n");
69538fd1498Szrj
69638fd1498Szrj symtab_node::checking_verify_symtab_nodes ();
69738fd1498Szrj
69838fd1498Szrj /* If we removed something, perhaps profile could be improved. */
69938fd1498Szrj if (changed && (optimize || in_lto_p) && ipa_call_summaries)
70038fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
70138fd1498Szrj ipa_propagate_frequency (node);
70238fd1498Szrj
70338fd1498Szrj timevar_pop (TV_IPA_UNREACHABLE);
70438fd1498Szrj return changed;
70538fd1498Szrj }
70638fd1498Szrj
70738fd1498Szrj /* Process references to VNODE and set flags WRITTEN, ADDRESS_TAKEN, READ
70838fd1498Szrj as needed, also clear EXPLICIT_REFS if the references to given variable
70938fd1498Szrj do not need to be explicit. */
71038fd1498Szrj
71138fd1498Szrj void
process_references(varpool_node * vnode,bool * written,bool * address_taken,bool * read,bool * explicit_refs)71238fd1498Szrj process_references (varpool_node *vnode,
71338fd1498Szrj bool *written, bool *address_taken,
71438fd1498Szrj bool *read, bool *explicit_refs)
71538fd1498Szrj {
71638fd1498Szrj int i;
71738fd1498Szrj struct ipa_ref *ref;
71838fd1498Szrj
71938fd1498Szrj if (!vnode->all_refs_explicit_p ()
72038fd1498Szrj || TREE_THIS_VOLATILE (vnode->decl))
72138fd1498Szrj *explicit_refs = false;
72238fd1498Szrj
72338fd1498Szrj for (i = 0; vnode->iterate_referring (i, ref)
72438fd1498Szrj && *explicit_refs && (!*written || !*address_taken || !*read); i++)
72538fd1498Szrj switch (ref->use)
72638fd1498Szrj {
72738fd1498Szrj case IPA_REF_ADDR:
72838fd1498Szrj *address_taken = true;
72938fd1498Szrj break;
73038fd1498Szrj case IPA_REF_LOAD:
73138fd1498Szrj *read = true;
73238fd1498Szrj break;
73338fd1498Szrj case IPA_REF_STORE:
73438fd1498Szrj *written = true;
73538fd1498Szrj break;
73638fd1498Szrj case IPA_REF_ALIAS:
73738fd1498Szrj process_references (dyn_cast<varpool_node *> (ref->referring), written,
73838fd1498Szrj address_taken, read, explicit_refs);
73938fd1498Szrj break;
74038fd1498Szrj case IPA_REF_CHKP:
74138fd1498Szrj gcc_unreachable ();
74238fd1498Szrj }
74338fd1498Szrj }
74438fd1498Szrj
74538fd1498Szrj /* Set TREE_READONLY bit. */
74638fd1498Szrj
74738fd1498Szrj bool
set_readonly_bit(varpool_node * vnode,void * data ATTRIBUTE_UNUSED)74838fd1498Szrj set_readonly_bit (varpool_node *vnode, void *data ATTRIBUTE_UNUSED)
74938fd1498Szrj {
75038fd1498Szrj TREE_READONLY (vnode->decl) = true;
75138fd1498Szrj return false;
75238fd1498Szrj }
75338fd1498Szrj
75438fd1498Szrj /* Set writeonly bit and clear the initalizer, since it will not be needed. */
75538fd1498Szrj
75638fd1498Szrj bool
set_writeonly_bit(varpool_node * vnode,void * data)75738fd1498Szrj set_writeonly_bit (varpool_node *vnode, void *data)
75838fd1498Szrj {
75938fd1498Szrj vnode->writeonly = true;
76038fd1498Szrj if (optimize || in_lto_p)
76138fd1498Szrj {
76238fd1498Szrj DECL_INITIAL (vnode->decl) = NULL;
76338fd1498Szrj if (!vnode->alias)
76438fd1498Szrj {
76538fd1498Szrj if (vnode->num_references ())
76638fd1498Szrj *(bool *)data = true;
76738fd1498Szrj vnode->remove_all_references ();
76838fd1498Szrj }
76938fd1498Szrj }
77038fd1498Szrj return false;
77138fd1498Szrj }
77238fd1498Szrj
77338fd1498Szrj /* Clear addressale bit of VNODE. */
77438fd1498Szrj
77538fd1498Szrj bool
clear_addressable_bit(varpool_node * vnode,void * data ATTRIBUTE_UNUSED)77638fd1498Szrj clear_addressable_bit (varpool_node *vnode, void *data ATTRIBUTE_UNUSED)
77738fd1498Szrj {
77838fd1498Szrj vnode->address_taken = false;
77938fd1498Szrj TREE_ADDRESSABLE (vnode->decl) = 0;
78038fd1498Szrj return false;
78138fd1498Szrj }
78238fd1498Szrj
78338fd1498Szrj /* Discover variables that have no longer address taken or that are read only
78438fd1498Szrj and update their flags.
78538fd1498Szrj
78638fd1498Szrj Return true when unreachable symbol removan should be done.
78738fd1498Szrj
78838fd1498Szrj FIXME: This can not be done in between gimplify and omp_expand since
78938fd1498Szrj readonly flag plays role on what is shared and what is not. Currently we do
79038fd1498Szrj this transformation as part of whole program visibility and re-do at
79138fd1498Szrj ipa-reference pass (to take into account clonning), but it would
79238fd1498Szrj make sense to do it before early optimizations. */
79338fd1498Szrj
79438fd1498Szrj bool
ipa_discover_readonly_nonaddressable_vars(void)79538fd1498Szrj ipa_discover_readonly_nonaddressable_vars (void)
79638fd1498Szrj {
79738fd1498Szrj bool remove_p = false;
79838fd1498Szrj varpool_node *vnode;
79938fd1498Szrj if (dump_file)
80038fd1498Szrj fprintf (dump_file, "Clearing variable flags:");
80138fd1498Szrj FOR_EACH_VARIABLE (vnode)
80238fd1498Szrj if (!vnode->alias
80338fd1498Szrj && (TREE_ADDRESSABLE (vnode->decl)
80438fd1498Szrj || !vnode->writeonly
80538fd1498Szrj || !TREE_READONLY (vnode->decl)))
80638fd1498Szrj {
80738fd1498Szrj bool written = false;
80838fd1498Szrj bool address_taken = false;
80938fd1498Szrj bool read = false;
81038fd1498Szrj bool explicit_refs = true;
81138fd1498Szrj
81238fd1498Szrj process_references (vnode, &written, &address_taken, &read,
81338fd1498Szrj &explicit_refs);
81438fd1498Szrj if (!explicit_refs)
81538fd1498Szrj continue;
81638fd1498Szrj if (!address_taken)
81738fd1498Szrj {
81838fd1498Szrj if (TREE_ADDRESSABLE (vnode->decl) && dump_file)
81938fd1498Szrj fprintf (dump_file, " %s (non-addressable)", vnode->name ());
82038fd1498Szrj vnode->call_for_symbol_and_aliases (clear_addressable_bit, NULL,
82138fd1498Szrj true);
82238fd1498Szrj }
82338fd1498Szrj if (!address_taken && !written
82438fd1498Szrj /* Making variable in explicit section readonly can cause section
82538fd1498Szrj type conflict.
82638fd1498Szrj See e.g. gcc.c-torture/compile/pr23237.c */
82738fd1498Szrj && vnode->get_section () == NULL)
82838fd1498Szrj {
82938fd1498Szrj if (!TREE_READONLY (vnode->decl) && dump_file)
83038fd1498Szrj fprintf (dump_file, " %s (read-only)", vnode->name ());
83138fd1498Szrj vnode->call_for_symbol_and_aliases (set_readonly_bit, NULL, true);
83238fd1498Szrj }
83338fd1498Szrj if (!vnode->writeonly && !read && !address_taken && written)
83438fd1498Szrj {
83538fd1498Szrj if (dump_file)
83638fd1498Szrj fprintf (dump_file, " %s (write-only)", vnode->name ());
83738fd1498Szrj vnode->call_for_symbol_and_aliases (set_writeonly_bit, &remove_p,
83838fd1498Szrj true);
83938fd1498Szrj }
84038fd1498Szrj }
84138fd1498Szrj if (dump_file)
84238fd1498Szrj fprintf (dump_file, "\n");
84338fd1498Szrj return remove_p;
84438fd1498Szrj }
84538fd1498Szrj
84638fd1498Szrj /* Generate and emit a static constructor or destructor. WHICH must
84738fd1498Szrj be one of 'I' (for a constructor), 'D' (for a destructor), 'P'
84838fd1498Szrj (for chp static vars constructor) or 'B' (for chkp static bounds
84938fd1498Szrj constructor). BODY is a STATEMENT_LIST containing GENERIC
85038fd1498Szrj statements. PRIORITY is the initialization priority for this
85138fd1498Szrj constructor or destructor.
85238fd1498Szrj
85338fd1498Szrj FINAL specify whether the externally visible name for collect2 should
85438fd1498Szrj be produced. */
85538fd1498Szrj
85638fd1498Szrj static void
cgraph_build_static_cdtor_1(char which,tree body,int priority,bool final,tree optimization,tree target)857*58e805e6Szrj cgraph_build_static_cdtor_1 (char which, tree body, int priority, bool final,
858*58e805e6Szrj tree optimization,
859*58e805e6Szrj tree target)
86038fd1498Szrj {
86138fd1498Szrj static int counter = 0;
86238fd1498Szrj char which_buf[16];
86338fd1498Szrj tree decl, name, resdecl;
86438fd1498Szrj
86538fd1498Szrj /* The priority is encoded in the constructor or destructor name.
86638fd1498Szrj collect2 will sort the names and arrange that they are called at
86738fd1498Szrj program startup. */
86838fd1498Szrj if (final)
86938fd1498Szrj sprintf (which_buf, "%c_%.5d_%d", which, priority, counter++);
87038fd1498Szrj else
87138fd1498Szrj /* Proudce sane name but one not recognizable by collect2, just for the
87238fd1498Szrj case we fail to inline the function. */
87338fd1498Szrj sprintf (which_buf, "sub_%c_%.5d_%d", which, priority, counter++);
87438fd1498Szrj name = get_file_function_name (which_buf);
87538fd1498Szrj
87638fd1498Szrj decl = build_decl (input_location, FUNCTION_DECL, name,
87738fd1498Szrj build_function_type_list (void_type_node, NULL_TREE));
87838fd1498Szrj current_function_decl = decl;
87938fd1498Szrj
88038fd1498Szrj resdecl = build_decl (input_location,
88138fd1498Szrj RESULT_DECL, NULL_TREE, void_type_node);
88238fd1498Szrj DECL_ARTIFICIAL (resdecl) = 1;
88338fd1498Szrj DECL_RESULT (decl) = resdecl;
88438fd1498Szrj DECL_CONTEXT (resdecl) = decl;
88538fd1498Szrj
88638fd1498Szrj allocate_struct_function (decl, false);
88738fd1498Szrj
88838fd1498Szrj TREE_STATIC (decl) = 1;
88938fd1498Szrj TREE_USED (decl) = 1;
890*58e805e6Szrj DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl) = optimization;
891*58e805e6Szrj DECL_FUNCTION_SPECIFIC_TARGET (decl) = target;
89238fd1498Szrj DECL_ARTIFICIAL (decl) = 1;
89338fd1498Szrj DECL_IGNORED_P (decl) = 1;
89438fd1498Szrj DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
89538fd1498Szrj DECL_SAVED_TREE (decl) = body;
89638fd1498Szrj if (!targetm.have_ctors_dtors && final)
89738fd1498Szrj {
89838fd1498Szrj TREE_PUBLIC (decl) = 1;
89938fd1498Szrj DECL_PRESERVE_P (decl) = 1;
90038fd1498Szrj }
90138fd1498Szrj DECL_UNINLINABLE (decl) = 1;
90238fd1498Szrj
90338fd1498Szrj DECL_INITIAL (decl) = make_node (BLOCK);
90438fd1498Szrj BLOCK_SUPERCONTEXT (DECL_INITIAL (decl)) = decl;
90538fd1498Szrj TREE_USED (DECL_INITIAL (decl)) = 1;
90638fd1498Szrj
90738fd1498Szrj DECL_SOURCE_LOCATION (decl) = input_location;
90838fd1498Szrj cfun->function_end_locus = input_location;
90938fd1498Szrj
91038fd1498Szrj switch (which)
91138fd1498Szrj {
91238fd1498Szrj case 'I':
91338fd1498Szrj DECL_STATIC_CONSTRUCTOR (decl) = 1;
91438fd1498Szrj decl_init_priority_insert (decl, priority);
91538fd1498Szrj break;
91638fd1498Szrj case 'P':
91738fd1498Szrj DECL_STATIC_CONSTRUCTOR (decl) = 1;
91838fd1498Szrj DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("chkp ctor"),
91938fd1498Szrj NULL,
92038fd1498Szrj NULL_TREE);
92138fd1498Szrj decl_init_priority_insert (decl, priority);
92238fd1498Szrj break;
92338fd1498Szrj case 'B':
92438fd1498Szrj DECL_STATIC_CONSTRUCTOR (decl) = 1;
92538fd1498Szrj DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("bnd_legacy"),
92638fd1498Szrj NULL,
92738fd1498Szrj NULL_TREE);
92838fd1498Szrj decl_init_priority_insert (decl, priority);
92938fd1498Szrj break;
93038fd1498Szrj case 'D':
93138fd1498Szrj DECL_STATIC_DESTRUCTOR (decl) = 1;
93238fd1498Szrj decl_fini_priority_insert (decl, priority);
93338fd1498Szrj break;
93438fd1498Szrj default:
93538fd1498Szrj gcc_unreachable ();
93638fd1498Szrj }
93738fd1498Szrj
93838fd1498Szrj gimplify_function_tree (decl);
93938fd1498Szrj
94038fd1498Szrj cgraph_node::add_new_function (decl, false);
94138fd1498Szrj
94238fd1498Szrj set_cfun (NULL);
94338fd1498Szrj current_function_decl = NULL;
94438fd1498Szrj }
94538fd1498Szrj
94638fd1498Szrj /* Generate and emit a static constructor or destructor. WHICH must
94738fd1498Szrj be one of 'I' (for a constructor), 'D' (for a destructor), 'P'
94838fd1498Szrj (for chkp static vars constructor) or 'B' (for chkp static bounds
94938fd1498Szrj constructor). BODY is a STATEMENT_LIST containing GENERIC
95038fd1498Szrj statements. PRIORITY is the initialization priority for this
95138fd1498Szrj constructor or destructor. */
95238fd1498Szrj
95338fd1498Szrj void
cgraph_build_static_cdtor(char which,tree body,int priority)95438fd1498Szrj cgraph_build_static_cdtor (char which, tree body, int priority)
95538fd1498Szrj {
956*58e805e6Szrj cgraph_build_static_cdtor_1 (which, body, priority, false, NULL, NULL);
95738fd1498Szrj }
95838fd1498Szrj
95938fd1498Szrj /* When target does not have ctors and dtors, we call all constructor
96038fd1498Szrj and destructor by special initialization/destruction function
96138fd1498Szrj recognized by collect2.
96238fd1498Szrj
96338fd1498Szrj When we are going to build this function, collect all constructors and
96438fd1498Szrj destructors and turn them into normal functions. */
96538fd1498Szrj
96638fd1498Szrj static void
record_cdtor_fn(struct cgraph_node * node,vec<tree> * ctors,vec<tree> * dtors)96738fd1498Szrj record_cdtor_fn (struct cgraph_node *node, vec<tree> *ctors, vec<tree> *dtors)
96838fd1498Szrj {
96938fd1498Szrj if (DECL_STATIC_CONSTRUCTOR (node->decl))
97038fd1498Szrj ctors->safe_push (node->decl);
97138fd1498Szrj if (DECL_STATIC_DESTRUCTOR (node->decl))
97238fd1498Szrj dtors->safe_push (node->decl);
97338fd1498Szrj node = cgraph_node::get (node->decl);
97438fd1498Szrj DECL_DISREGARD_INLINE_LIMITS (node->decl) = 1;
97538fd1498Szrj }
97638fd1498Szrj
97738fd1498Szrj /* Define global constructors/destructor functions for the CDTORS, of
97838fd1498Szrj which they are LEN. The CDTORS are sorted by initialization
97938fd1498Szrj priority. If CTOR_P is true, these are constructors; otherwise,
98038fd1498Szrj they are destructors. */
98138fd1498Szrj
98238fd1498Szrj static void
build_cdtor(bool ctor_p,const vec<tree> & cdtors)98338fd1498Szrj build_cdtor (bool ctor_p, const vec<tree> &cdtors)
98438fd1498Szrj {
98538fd1498Szrj size_t i,j;
98638fd1498Szrj size_t len = cdtors.length ();
98738fd1498Szrj
98838fd1498Szrj i = 0;
98938fd1498Szrj while (i < len)
99038fd1498Szrj {
99138fd1498Szrj tree body;
99238fd1498Szrj tree fn;
99338fd1498Szrj priority_type priority;
99438fd1498Szrj
99538fd1498Szrj priority = 0;
99638fd1498Szrj body = NULL_TREE;
99738fd1498Szrj j = i;
99838fd1498Szrj do
99938fd1498Szrj {
100038fd1498Szrj priority_type p;
100138fd1498Szrj fn = cdtors[j];
100238fd1498Szrj p = ctor_p ? DECL_INIT_PRIORITY (fn) : DECL_FINI_PRIORITY (fn);
100338fd1498Szrj if (j == i)
100438fd1498Szrj priority = p;
100538fd1498Szrj else if (p != priority)
100638fd1498Szrj break;
100738fd1498Szrj j++;
100838fd1498Szrj }
100938fd1498Szrj while (j < len);
101038fd1498Szrj
101138fd1498Szrj /* When there is only one cdtor and target supports them, do nothing. */
101238fd1498Szrj if (j == i + 1
101338fd1498Szrj && targetm.have_ctors_dtors)
101438fd1498Szrj {
101538fd1498Szrj i++;
101638fd1498Szrj continue;
101738fd1498Szrj }
101838fd1498Szrj /* Find the next batch of constructors/destructors with the same
101938fd1498Szrj initialization priority. */
102038fd1498Szrj for (;i < j; i++)
102138fd1498Szrj {
102238fd1498Szrj tree call;
102338fd1498Szrj fn = cdtors[i];
102438fd1498Szrj call = build_call_expr (fn, 0);
102538fd1498Szrj if (ctor_p)
102638fd1498Szrj DECL_STATIC_CONSTRUCTOR (fn) = 0;
102738fd1498Szrj else
102838fd1498Szrj DECL_STATIC_DESTRUCTOR (fn) = 0;
102938fd1498Szrj /* We do not want to optimize away pure/const calls here.
103038fd1498Szrj When optimizing, these should be already removed, when not
103138fd1498Szrj optimizing, we want user to be able to breakpoint in them. */
103238fd1498Szrj TREE_SIDE_EFFECTS (call) = 1;
103338fd1498Szrj append_to_statement_list (call, &body);
103438fd1498Szrj }
103538fd1498Szrj gcc_assert (body != NULL_TREE);
103638fd1498Szrj /* Generate a function to call all the function of like
103738fd1498Szrj priority. */
1038*58e805e6Szrj cgraph_build_static_cdtor_1 (ctor_p ? 'I' : 'D', body, priority, true,
1039*58e805e6Szrj DECL_FUNCTION_SPECIFIC_OPTIMIZATION (cdtors[0]),
1040*58e805e6Szrj DECL_FUNCTION_SPECIFIC_TARGET (cdtors[0]));
104138fd1498Szrj }
104238fd1498Szrj }
104338fd1498Szrj
104438fd1498Szrj /* Comparison function for qsort. P1 and P2 are actually of type
104538fd1498Szrj "tree *" and point to static constructors. DECL_INIT_PRIORITY is
104638fd1498Szrj used to determine the sort order. */
104738fd1498Szrj
104838fd1498Szrj static int
compare_ctor(const void * p1,const void * p2)104938fd1498Szrj compare_ctor (const void *p1, const void *p2)
105038fd1498Szrj {
105138fd1498Szrj tree f1;
105238fd1498Szrj tree f2;
105338fd1498Szrj int priority1;
105438fd1498Szrj int priority2;
105538fd1498Szrj
105638fd1498Szrj f1 = *(const tree *)p1;
105738fd1498Szrj f2 = *(const tree *)p2;
105838fd1498Szrj priority1 = DECL_INIT_PRIORITY (f1);
105938fd1498Szrj priority2 = DECL_INIT_PRIORITY (f2);
106038fd1498Szrj
106138fd1498Szrj if (priority1 < priority2)
106238fd1498Szrj return -1;
106338fd1498Szrj else if (priority1 > priority2)
106438fd1498Szrj return 1;
106538fd1498Szrj else
106638fd1498Szrj /* Ensure a stable sort. Constructors are executed in backwarding
106738fd1498Szrj order to make LTO initialize braries first. */
106838fd1498Szrj return DECL_UID (f2) - DECL_UID (f1);
106938fd1498Szrj }
107038fd1498Szrj
107138fd1498Szrj /* Comparison function for qsort. P1 and P2 are actually of type
107238fd1498Szrj "tree *" and point to static destructors. DECL_FINI_PRIORITY is
107338fd1498Szrj used to determine the sort order. */
107438fd1498Szrj
107538fd1498Szrj static int
compare_dtor(const void * p1,const void * p2)107638fd1498Szrj compare_dtor (const void *p1, const void *p2)
107738fd1498Szrj {
107838fd1498Szrj tree f1;
107938fd1498Szrj tree f2;
108038fd1498Szrj int priority1;
108138fd1498Szrj int priority2;
108238fd1498Szrj
108338fd1498Szrj f1 = *(const tree *)p1;
108438fd1498Szrj f2 = *(const tree *)p2;
108538fd1498Szrj priority1 = DECL_FINI_PRIORITY (f1);
108638fd1498Szrj priority2 = DECL_FINI_PRIORITY (f2);
108738fd1498Szrj
108838fd1498Szrj if (priority1 < priority2)
108938fd1498Szrj return -1;
109038fd1498Szrj else if (priority1 > priority2)
109138fd1498Szrj return 1;
109238fd1498Szrj else
109338fd1498Szrj /* Ensure a stable sort. */
109438fd1498Szrj return DECL_UID (f1) - DECL_UID (f2);
109538fd1498Szrj }
109638fd1498Szrj
109738fd1498Szrj /* Generate functions to call static constructors and destructors
109838fd1498Szrj for targets that do not support .ctors/.dtors sections. These
109938fd1498Szrj functions have magic names which are detected by collect2. */
110038fd1498Szrj
110138fd1498Szrj static void
build_cdtor_fns(vec<tree> * ctors,vec<tree> * dtors)110238fd1498Szrj build_cdtor_fns (vec<tree> *ctors, vec<tree> *dtors)
110338fd1498Szrj {
110438fd1498Szrj if (!ctors->is_empty ())
110538fd1498Szrj {
110638fd1498Szrj gcc_assert (!targetm.have_ctors_dtors || in_lto_p);
110738fd1498Szrj ctors->qsort (compare_ctor);
110838fd1498Szrj build_cdtor (/*ctor_p=*/true, *ctors);
110938fd1498Szrj }
111038fd1498Szrj
111138fd1498Szrj if (!dtors->is_empty ())
111238fd1498Szrj {
111338fd1498Szrj gcc_assert (!targetm.have_ctors_dtors || in_lto_p);
111438fd1498Szrj dtors->qsort (compare_dtor);
111538fd1498Szrj build_cdtor (/*ctor_p=*/false, *dtors);
111638fd1498Szrj }
111738fd1498Szrj }
111838fd1498Szrj
111938fd1498Szrj /* Look for constructors and destructors and produce function calling them.
112038fd1498Szrj This is needed for targets not supporting ctors or dtors, but we perform the
112138fd1498Szrj transformation also at linktime to merge possibly numerous
112238fd1498Szrj constructors/destructors into single function to improve code locality and
112338fd1498Szrj reduce size. */
112438fd1498Szrj
112538fd1498Szrj static unsigned int
ipa_cdtor_merge(void)112638fd1498Szrj ipa_cdtor_merge (void)
112738fd1498Szrj {
112838fd1498Szrj /* A vector of FUNCTION_DECLs declared as static constructors. */
112938fd1498Szrj auto_vec<tree, 20> ctors;
113038fd1498Szrj /* A vector of FUNCTION_DECLs declared as static destructors. */
113138fd1498Szrj auto_vec<tree, 20> dtors;
113238fd1498Szrj struct cgraph_node *node;
113338fd1498Szrj FOR_EACH_DEFINED_FUNCTION (node)
113438fd1498Szrj if (DECL_STATIC_CONSTRUCTOR (node->decl)
113538fd1498Szrj || DECL_STATIC_DESTRUCTOR (node->decl))
113638fd1498Szrj record_cdtor_fn (node, &ctors, &dtors);
113738fd1498Szrj build_cdtor_fns (&ctors, &dtors);
113838fd1498Szrj return 0;
113938fd1498Szrj }
114038fd1498Szrj
114138fd1498Szrj namespace {
114238fd1498Szrj
114338fd1498Szrj const pass_data pass_data_ipa_cdtor_merge =
114438fd1498Szrj {
114538fd1498Szrj IPA_PASS, /* type */
114638fd1498Szrj "cdtor", /* name */
114738fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
114838fd1498Szrj TV_CGRAPHOPT, /* tv_id */
114938fd1498Szrj 0, /* properties_required */
115038fd1498Szrj 0, /* properties_provided */
115138fd1498Szrj 0, /* properties_destroyed */
115238fd1498Szrj 0, /* todo_flags_start */
115338fd1498Szrj 0, /* todo_flags_finish */
115438fd1498Szrj };
115538fd1498Szrj
115638fd1498Szrj class pass_ipa_cdtor_merge : public ipa_opt_pass_d
115738fd1498Szrj {
115838fd1498Szrj public:
pass_ipa_cdtor_merge(gcc::context * ctxt)115938fd1498Szrj pass_ipa_cdtor_merge (gcc::context *ctxt)
116038fd1498Szrj : ipa_opt_pass_d (pass_data_ipa_cdtor_merge, ctxt,
116138fd1498Szrj NULL, /* generate_summary */
116238fd1498Szrj NULL, /* write_summary */
116338fd1498Szrj NULL, /* read_summary */
116438fd1498Szrj NULL, /* write_optimization_summary */
116538fd1498Szrj NULL, /* read_optimization_summary */
116638fd1498Szrj NULL, /* stmt_fixup */
116738fd1498Szrj 0, /* function_transform_todo_flags_start */
116838fd1498Szrj NULL, /* function_transform */
116938fd1498Szrj NULL) /* variable_transform */
117038fd1498Szrj {}
117138fd1498Szrj
117238fd1498Szrj /* opt_pass methods: */
117338fd1498Szrj virtual bool gate (function *);
execute(function *)117438fd1498Szrj virtual unsigned int execute (function *) { return ipa_cdtor_merge (); }
117538fd1498Szrj
117638fd1498Szrj }; // class pass_ipa_cdtor_merge
117738fd1498Szrj
117838fd1498Szrj bool
gate(function *)117938fd1498Szrj pass_ipa_cdtor_merge::gate (function *)
118038fd1498Szrj {
118138fd1498Szrj /* Perform the pass when we have no ctors/dtors support
118238fd1498Szrj or at LTO time to merge multiple constructors into single
118338fd1498Szrj function. */
118438fd1498Szrj return !targetm.have_ctors_dtors || in_lto_p;
118538fd1498Szrj }
118638fd1498Szrj
118738fd1498Szrj } // anon namespace
118838fd1498Szrj
118938fd1498Szrj ipa_opt_pass_d *
make_pass_ipa_cdtor_merge(gcc::context * ctxt)119038fd1498Szrj make_pass_ipa_cdtor_merge (gcc::context *ctxt)
119138fd1498Szrj {
119238fd1498Szrj return new pass_ipa_cdtor_merge (ctxt);
119338fd1498Szrj }
119438fd1498Szrj
119538fd1498Szrj /* Invalid pointer representing BOTTOM for single user dataflow. */
119638fd1498Szrj #define BOTTOM ((cgraph_node *)(size_t) 2)
119738fd1498Szrj
119838fd1498Szrj /* Meet operation for single user dataflow.
119938fd1498Szrj Here we want to associate variables with sigle function that may access it.
120038fd1498Szrj
120138fd1498Szrj FUNCTION is current single user of a variable, VAR is variable that uses it.
120238fd1498Szrj Latttice is stored in SINGLE_USER_MAP.
120338fd1498Szrj
120438fd1498Szrj We represent:
120538fd1498Szrj - TOP by no entry in SIGNLE_USER_MAP
120638fd1498Szrj - BOTTOM by BOTTOM in AUX pointer (to save lookups)
120738fd1498Szrj - known single user by cgraph pointer in SINGLE_USER_MAP. */
120838fd1498Szrj
120938fd1498Szrj cgraph_node *
meet(cgraph_node * function,varpool_node * var,hash_map<varpool_node *,cgraph_node * > & single_user_map)121038fd1498Szrj meet (cgraph_node *function, varpool_node *var,
121138fd1498Szrj hash_map<varpool_node *, cgraph_node *> &single_user_map)
121238fd1498Szrj {
121338fd1498Szrj struct cgraph_node *user, **f;
121438fd1498Szrj
121538fd1498Szrj if (var->aux == BOTTOM)
121638fd1498Szrj return BOTTOM;
121738fd1498Szrj
121838fd1498Szrj f = single_user_map.get (var);
121938fd1498Szrj if (!f)
122038fd1498Szrj return function;
122138fd1498Szrj user = *f;
122238fd1498Szrj if (!function)
122338fd1498Szrj return user;
122438fd1498Szrj else if (function != user)
122538fd1498Szrj return BOTTOM;
122638fd1498Szrj else
122738fd1498Szrj return function;
122838fd1498Szrj }
122938fd1498Szrj
123038fd1498Szrj /* Propagation step of single-use dataflow.
123138fd1498Szrj
123238fd1498Szrj Check all uses of VNODE and see if they are used by single function FUNCTION.
123338fd1498Szrj SINGLE_USER_MAP represents the dataflow lattice. */
123438fd1498Szrj
123538fd1498Szrj cgraph_node *
propagate_single_user(varpool_node * vnode,cgraph_node * function,hash_map<varpool_node *,cgraph_node * > & single_user_map)123638fd1498Szrj propagate_single_user (varpool_node *vnode, cgraph_node *function,
123738fd1498Szrj hash_map<varpool_node *, cgraph_node *> &single_user_map)
123838fd1498Szrj {
123938fd1498Szrj int i;
124038fd1498Szrj struct ipa_ref *ref;
124138fd1498Szrj
124238fd1498Szrj gcc_assert (!vnode->externally_visible);
124338fd1498Szrj
124438fd1498Szrj /* If node is an alias, first meet with its target. */
124538fd1498Szrj if (vnode->alias)
124638fd1498Szrj function = meet (function, vnode->get_alias_target (), single_user_map);
124738fd1498Szrj
124838fd1498Szrj /* Check all users and see if they correspond to a single function. */
124938fd1498Szrj for (i = 0; vnode->iterate_referring (i, ref) && function != BOTTOM; i++)
125038fd1498Szrj {
125138fd1498Szrj struct cgraph_node *cnode = dyn_cast <cgraph_node *> (ref->referring);
125238fd1498Szrj if (cnode)
125338fd1498Szrj {
125438fd1498Szrj if (cnode->global.inlined_to)
125538fd1498Szrj cnode = cnode->global.inlined_to;
125638fd1498Szrj if (!function)
125738fd1498Szrj function = cnode;
125838fd1498Szrj else if (function != cnode)
125938fd1498Szrj function = BOTTOM;
126038fd1498Szrj }
126138fd1498Szrj else
126238fd1498Szrj function = meet (function, dyn_cast <varpool_node *> (ref->referring),
126338fd1498Szrj single_user_map);
126438fd1498Szrj }
126538fd1498Szrj return function;
126638fd1498Szrj }
126738fd1498Szrj
126838fd1498Szrj /* Pass setting used_by_single_function flag.
126938fd1498Szrj This flag is set on variable when there is only one function that may
127038fd1498Szrj possibly referr to it. */
127138fd1498Szrj
127238fd1498Szrj static unsigned int
ipa_single_use(void)127338fd1498Szrj ipa_single_use (void)
127438fd1498Szrj {
127538fd1498Szrj varpool_node *first = (varpool_node *) (void *) 1;
127638fd1498Szrj varpool_node *var;
127738fd1498Szrj hash_map<varpool_node *, cgraph_node *> single_user_map;
127838fd1498Szrj
127938fd1498Szrj FOR_EACH_DEFINED_VARIABLE (var)
128038fd1498Szrj if (!var->all_refs_explicit_p ())
128138fd1498Szrj var->aux = BOTTOM;
128238fd1498Szrj else
128338fd1498Szrj {
128438fd1498Szrj /* Enqueue symbol for dataflow. */
128538fd1498Szrj var->aux = first;
128638fd1498Szrj first = var;
128738fd1498Szrj }
128838fd1498Szrj
128938fd1498Szrj /* The actual dataflow. */
129038fd1498Szrj
129138fd1498Szrj while (first != (void *) 1)
129238fd1498Szrj {
129338fd1498Szrj cgraph_node *user, *orig_user, **f;
129438fd1498Szrj
129538fd1498Szrj var = first;
129638fd1498Szrj first = (varpool_node *)first->aux;
129738fd1498Szrj
129838fd1498Szrj f = single_user_map.get (var);
129938fd1498Szrj if (f)
130038fd1498Szrj orig_user = *f;
130138fd1498Szrj else
130238fd1498Szrj orig_user = NULL;
130338fd1498Szrj user = propagate_single_user (var, orig_user, single_user_map);
130438fd1498Szrj
130538fd1498Szrj gcc_checking_assert (var->aux != BOTTOM);
130638fd1498Szrj
130738fd1498Szrj /* If user differs, enqueue all references. */
130838fd1498Szrj if (user != orig_user)
130938fd1498Szrj {
131038fd1498Szrj unsigned int i;
131138fd1498Szrj ipa_ref *ref;
131238fd1498Szrj
131338fd1498Szrj single_user_map.put (var, user);
131438fd1498Szrj
131538fd1498Szrj /* Enqueue all aliases for re-processing. */
131638fd1498Szrj for (i = 0; var->iterate_direct_aliases (i, ref); i++)
131738fd1498Szrj if (!ref->referring->aux)
131838fd1498Szrj {
131938fd1498Szrj ref->referring->aux = first;
132038fd1498Szrj first = dyn_cast <varpool_node *> (ref->referring);
132138fd1498Szrj }
132238fd1498Szrj /* Enqueue all users for re-processing. */
132338fd1498Szrj for (i = 0; var->iterate_reference (i, ref); i++)
132438fd1498Szrj if (!ref->referred->aux
132538fd1498Szrj && ref->referred->definition
132638fd1498Szrj && is_a <varpool_node *> (ref->referred))
132738fd1498Szrj {
132838fd1498Szrj ref->referred->aux = first;
132938fd1498Szrj first = dyn_cast <varpool_node *> (ref->referred);
133038fd1498Szrj }
133138fd1498Szrj
133238fd1498Szrj /* If user is BOTTOM, just punt on this var. */
133338fd1498Szrj if (user == BOTTOM)
133438fd1498Szrj var->aux = BOTTOM;
133538fd1498Szrj else
133638fd1498Szrj var->aux = NULL;
133738fd1498Szrj }
133838fd1498Szrj else
133938fd1498Szrj var->aux = NULL;
134038fd1498Szrj }
134138fd1498Szrj
134238fd1498Szrj FOR_EACH_DEFINED_VARIABLE (var)
134338fd1498Szrj {
134438fd1498Szrj if (var->aux != BOTTOM)
134538fd1498Szrj {
134638fd1498Szrj /* Not having the single user known means that the VAR is
134738fd1498Szrj unreachable. Either someone forgot to remove unreachable
134838fd1498Szrj variables or the reachability here is wrong. */
134938fd1498Szrj
135038fd1498Szrj gcc_checking_assert (single_user_map.get (var));
135138fd1498Szrj
135238fd1498Szrj if (dump_file)
135338fd1498Szrj {
135438fd1498Szrj fprintf (dump_file, "Variable %s is used by single function\n",
135538fd1498Szrj var->dump_name ());
135638fd1498Szrj }
135738fd1498Szrj var->used_by_single_function = true;
135838fd1498Szrj }
135938fd1498Szrj var->aux = NULL;
136038fd1498Szrj }
136138fd1498Szrj return 0;
136238fd1498Szrj }
136338fd1498Szrj
136438fd1498Szrj namespace {
136538fd1498Szrj
136638fd1498Szrj const pass_data pass_data_ipa_single_use =
136738fd1498Szrj {
136838fd1498Szrj IPA_PASS, /* type */
136938fd1498Szrj "single-use", /* name */
137038fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
137138fd1498Szrj TV_CGRAPHOPT, /* tv_id */
137238fd1498Szrj 0, /* properties_required */
137338fd1498Szrj 0, /* properties_provided */
137438fd1498Szrj 0, /* properties_destroyed */
137538fd1498Szrj 0, /* todo_flags_start */
137638fd1498Szrj 0, /* todo_flags_finish */
137738fd1498Szrj };
137838fd1498Szrj
137938fd1498Szrj class pass_ipa_single_use : public ipa_opt_pass_d
138038fd1498Szrj {
138138fd1498Szrj public:
pass_ipa_single_use(gcc::context * ctxt)138238fd1498Szrj pass_ipa_single_use (gcc::context *ctxt)
138338fd1498Szrj : ipa_opt_pass_d (pass_data_ipa_single_use, ctxt,
138438fd1498Szrj NULL, /* generate_summary */
138538fd1498Szrj NULL, /* write_summary */
138638fd1498Szrj NULL, /* read_summary */
138738fd1498Szrj NULL, /* write_optimization_summary */
138838fd1498Szrj NULL, /* read_optimization_summary */
138938fd1498Szrj NULL, /* stmt_fixup */
139038fd1498Szrj 0, /* function_transform_todo_flags_start */
139138fd1498Szrj NULL, /* function_transform */
139238fd1498Szrj NULL) /* variable_transform */
139338fd1498Szrj {}
139438fd1498Szrj
139538fd1498Szrj /* opt_pass methods: */
execute(function *)139638fd1498Szrj virtual unsigned int execute (function *) { return ipa_single_use (); }
139738fd1498Szrj
139838fd1498Szrj }; // class pass_ipa_single_use
139938fd1498Szrj
140038fd1498Szrj } // anon namespace
140138fd1498Szrj
140238fd1498Szrj ipa_opt_pass_d *
make_pass_ipa_single_use(gcc::context * ctxt)140338fd1498Szrj make_pass_ipa_single_use (gcc::context *ctxt)
140438fd1498Szrj {
140538fd1498Szrj return new pass_ipa_single_use (ctxt);
140638fd1498Szrj }
140738fd1498Szrj
140838fd1498Szrj /* Materialize all clones. */
140938fd1498Szrj
141038fd1498Szrj namespace {
141138fd1498Szrj
141238fd1498Szrj const pass_data pass_data_materialize_all_clones =
141338fd1498Szrj {
141438fd1498Szrj SIMPLE_IPA_PASS, /* type */
141538fd1498Szrj "materialize-all-clones", /* name */
141638fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */
141738fd1498Szrj TV_IPA_OPT, /* tv_id */
141838fd1498Szrj 0, /* properties_required */
141938fd1498Szrj 0, /* properties_provided */
142038fd1498Szrj 0, /* properties_destroyed */
142138fd1498Szrj 0, /* todo_flags_start */
142238fd1498Szrj 0, /* todo_flags_finish */
142338fd1498Szrj };
142438fd1498Szrj
142538fd1498Szrj class pass_materialize_all_clones : public simple_ipa_opt_pass
142638fd1498Szrj {
142738fd1498Szrj public:
pass_materialize_all_clones(gcc::context * ctxt)142838fd1498Szrj pass_materialize_all_clones (gcc::context *ctxt)
142938fd1498Szrj : simple_ipa_opt_pass (pass_data_materialize_all_clones, ctxt)
143038fd1498Szrj {}
143138fd1498Szrj
143238fd1498Szrj /* opt_pass methods: */
execute(function *)143338fd1498Szrj virtual unsigned int execute (function *)
143438fd1498Szrj {
143538fd1498Szrj symtab->materialize_all_clones ();
143638fd1498Szrj return 0;
143738fd1498Szrj }
143838fd1498Szrj
143938fd1498Szrj }; // class pass_materialize_all_clones
144038fd1498Szrj
144138fd1498Szrj } // anon namespace
144238fd1498Szrj
144338fd1498Szrj simple_ipa_opt_pass *
make_pass_materialize_all_clones(gcc::context * ctxt)144438fd1498Szrj make_pass_materialize_all_clones (gcc::context *ctxt)
144538fd1498Szrj {
144638fd1498Szrj return new pass_materialize_all_clones (ctxt);
144738fd1498Szrj }
1448